Bring GitHub issues into Keepr and comment the time back
What the integration does
One integration connects a GitHub repository to one Keepr project. Inbound, GitHub tells Keepr about its issues: a new issue becomes a task in the Keepr project, closing it archives the task, and reopening it restores the task. A pull request that closes exactly one issue — with “Closes #12” or an issue linked under Development — is tracked on that issue's task, and the browser extension starts its timer there too; any other pull request gets a task of its own, archived when it is merged or closed. Keepr asks GitHub which issues a pull request closes, so this needs the token from step 4.
Outbound, Keepr reports tracked time back. GitHub has no time-tracking field, so each time entry on a task linked to an issue or pull request becomes one comment there, edited when the entry changes and deleted when the entry is deleted. Only time from the integration's Keepr project is sent, to the second, never rounded.
Before you start
In Keepr you need to be an owner or admin of the organization, or a manager of the workspace that holds the project. Every plan includes integrations: Free runs one at a time, Team three, and Ultimate — trial included — as many as you need.
In GitHub you need admin access to the repository to add a webhook. GitHub Enterprise Server works the same way, as long as it can reach over HTTPS and Keepr can reach it back over the public internet.
1. Create the integration in Keepr
Open Organization settings → Integrations and press “New integration”. Choose GitHub, the Keepr project its tasks go into, and the name it acts under: Keepr shows its actions as, for example, “Archived by GitHub · Website”.
Keepr then shows the webhook signing secret, once. Copy it before closing the dialog. Afterwards only its first characters are shown; if it is lost, rotate it on the integration's page and paste the new one into GitHub.
2. Add the webhook in GitHub
In the repository, open Settings → Webhooks → “Add webhook”, at . Paste the endpoint from the integration's Inbound webhooks section into “Payload URL”, set “Content type” to application/json, and paste the signing secret into Secret.
Under “Which events would you like to trigger this webhook?”, choose “Let me select individual events”, tick Issues and Pull requests, untick Pushes, and save. GitHub sends a ping at once; it appears in the integration's recent deliveries as a connection test.
A webhook on the GitHub organization, at , works too and brings every repository's issues into the one Keepr project; tasks from two repositories stay apart, since each is matched by its repository as well as its number.
3. Choose who the time is reported as
GitHub shows every comment as written by the owner of the token Keepr uses. The comment names the Keepr member who tracked the time, but the author is that account, for everyone's entries. Posting as a Keepr GitHub App (keepr[bot]), or as each member, is planned; until then, give Keepr a token that belongs to no person.
Use a machine user: a separate GitHub account for automation, which GitHub's terms allow. Give it write access to the repository, sign in as it, and create a fine-grained token at Settings → Developer settings → Fine-grained tokens. Choose the organization as the resource owner, “Only select repositories” with the repositories the integration covers, and under Repository permissions set Issues and Pull requests to “Read and write”; read-only Metadata is added on its own.
If your organization requires approval for fine-grained tokens, an organization owner approves the request under the organization's Settings → Personal access tokens before the token works. Give it an expiry you will notice: once it lapses, sends fail with “Credential rejected”.
Your own token works the same way, but then every comment is shown as yours.
4. Give Keepr the address and the token
On the integration's page, open Credentials and press “Set…” next to the GitHub credential. The GitHub API address is , or for GitHub Enterprise Server; a pasted page of either is saved as its API address. Paste the token and save.
Keepr stores the token encrypted and afterwards shows only its first characters. It uses it to write time back and to read which issues a merge or pull request closes; nothing else. Without it, issues still come in, but a merge or pull request is left alone and shows “Couldn't read its issues” in the recent deliveries.
What Keepr sends
An entry is sent once it is finished — a running timer sends nothing until it stops — and only when its task is in the integration's project and links to an issue or pull request on that GitHub. Tasks the integration created link that way, and so do tasks started from the browser extension on a GitHub page.
Each entry gets one comment naming the member, the duration and the day. An edit rewrites that comment instead of adding another, deleting the entry deletes it, and moving the entry to another issue moves the comment. A comment deleted by hand is written again the next time the entry changes; a hidden marker in it lets Keepr find its own comment after a timeout instead of posting twice.
Imported time is history and is never sent. The integration's “Recently sent” list shows the latest entries, each with its item, the member, the time GitHub holds for it, and whether the last send worked; a failed row says why and what to do.
Pause, rotate or revoke
The switch on the integration's page turns it off without losing anything. While it is off, deliveries are recorded but not acted on (GitHub's “Redeliver” replays one later), and no time is sent: an entry saved during the pause is sent the next time it changes. Switching it back on takes a slot under your plan's limit again.
“Rotate…” in Credentials replaces the webhook secret at once, with no grace period: deliveries fail until the new secret is in GitHub. “Remove” next to the GitHub credential stops time reporting and leaves the inbound direction alone.
Revoke is final. Keepr destroys both secrets and acts on nothing more; the integration stays in the list as history, and what it did stays attributed to it in the audit log and on archived tasks. Revoke the token in GitHub as well.
When a webhook is not possible
If you cannot add a webhook — no admin access, or a GitHub Enterprise Server that cannot reach Keepr — a GitHub Actions workflow can create the tasks through the REST API instead. It needs a personal API token, which is part of the Ultimate plan: create one under API tokens with the timers:write scope, and store it as a repository secret at .
Run the workflow on the issues event, for the opened type, and have it call with the header “Authorization: Bearer” and the token, and a JSON body of externalKey (the issue number), name (its title), url (its html_url) and projectId. Keepr returns the existing task or creates it, matched exactly as a webhook-created one is, so a rerun is harmless.
For the closed type, make the same call to get the task, then with its id, which needs the projects:write scope. Every field is in the API reference at api.keepr.ru/docs. Time reporting needs no webhook and works either way once the address and token are set.
If something goes wrong
Every delivery appears under the integration's recent deliveries with what it did. One that GitHub lists with a 401 was signed with a different secret: rotate the secret and paste the new one. A 415 means the webhook sends form data: set its content type to application/json. “Task already there” means a task for the issue existed — for example, one started from the browser extension — and nothing was duplicated.
In “Recently sent”, “Address or credential not set” means the integration has no API address or token yet. “Credential rejected” means the token was revoked, expired, never approved, lacks Issues write access, or can no longer see the repository. “Issue not found” means the issue was deleted or transferred, and “Address not allowed” that the API address is not public HTTPS. “Tool refused it” is any other refusal from GitHub; “Tool unreachable, retrying” clears on its own once GitHub answers.
A send that failed for good is tried again the next time the entry changes.