Skip to content

Documentation

Sponsors and issues from GitHub

Three things happen on GitHub that are really things happening to a person: somebody starts sponsoring you, somebody opens an issue, and somebody stars the repository. One address takes all three — a sponsor becomes a purchase, an issue becomes a support message you can answer from their record, and a star is recorded only if you ask for it.

Three things happen on GitHub that are really things happening to a person: somebody starts sponsoring you, somebody opens an issue, and somebody stars the repository. Kicklace takes all three through one address.

  • A sponsor becomes a purchase on their record, and the lifecycle moves them to Purchaser — the same event a payment from your own servers posts, so an automation written for a purchase answers a sponsor without knowing GitHub exists.
  • An issue becomes a support message on the person who opened it, which is what lets you write back to them from their record.
  • A star is recorded only if you switch it on, because a star is not consent to anything.

There is no code to write and nothing to deploy. Kicklace changes nothing in GitHub, reads no code, and never reads the words inside an issue.

What this is not. It is not sign-in with GitHub for the people on your team, and it is not a GitHub App with access to your repositories. It is one webhook, going one way.

The screen is Settings → Integrations → GitHub, and only an owner or an admin can change it.


Setting it up

1. Make the address. Settings → Integrations → GitHub → Connect GitHub. You get an address of the form https://<your Kicklace>/api/webhooks/github/<token>. The token is not a secret on its own — the signature is what proves a post came from GitHub — but it is not published either, so nobody can guess your endpoint.

2. Add it in GitHub. Where depends on what you want:

What you want Where the webhook goes
Sponsors Your sponsors → Dashboard → Webhooks → Add webhook
Issues and stars The repository's Settings → Webhooks → Add webhook

On that form, paste the address as the Payload URL, set Content type to application/json, and choose Let me select individual eventsSponsorships, Issues, Stars. One address takes all three. Ticking more is harmless: anything else is answered 200 and ignored, which is what stops GitHub retrying it.

The content type matters. GitHub's other option wraps the whole payload inside a form field, and Kicklace answers that with invalid_json and a sentence saying so.

3. Use the same secret in both places. Unlike most services, GitHub does not make a secret for you: the Secret box on that same form is one you fill in. Type a long random secret there, and paste the same one into the second step in Kicklace. It is encrypted at rest and never shown back — the screen says "set on the 9th" and offers Replace. Until it is in, nothing is taken: Kicklace answers no_signing_secret and writes the refusal to your heartbeat.

GitHub signs with X-Hub-Signature-256: an HMAC-SHA256 of the raw request body, hex, keyed with that secret. Kicklace compares it in constant time and refuses anything else — including the older X-Hub-Signature, which is SHA-1 and is kept by GitHub for legacy reasons only.

When you add the webhook, GitHub sends a ping. It is answered and ignored on purpose, so the frame still says nothing has come through until a real sponsor, issue or star arrives.

What lands

What GitHub sends What it becomes
sponsorship.created, monthly a purchase for the tier's amount, and a subscription started
sponsorship.created, one-time a purchase for the tier's amount
sponsorship.tier_changed the subscription renewed, at the new amount
sponsorship.cancelled the sponsorship ending, on their timeline
issues.opened a support message: the title and a link
star.created nothing, unless stars are switched on

Everything else is answered 200 and ignored. sponsorship.pending_cancellation and pending_tier_change are somebody's future intention rather than something that happened; sponsorship.edited is a change to a tier's own wording; an issue being closed, labelled or reopened is a life the issue is living on GitHub, not on a person's timeline.

A sponsorship amount is written in US dollars. GitHub sends no currency at all — a tier carries only its monthly price in cents — and GitHub Sponsors is priced in dollars, so that is what is recorded.

A bot is not a person. Anything GitHub marks as one, and any handle ending in [bot], is skipped: an automated account opening an issue is a machine doing its job.

Nothing lands twice. An issue is recognised by its repository and number, a star by its repository and the person's handle, and a sponsorship change by GitHub's own delivery id. A retry, or a second webhook pointed at the same address, writes nothing the second time.

Who it lands on

By their public address, when GitHub gives one. Most of the time it does not: a GitHub profile shows an email only if its owner chose to.

By their handle otherwise. A handle is not an opaque billing id — it is a name somebody chose, and it is how you would reach them — so a sponsor with no visible address is still written down, as a person named after their handle with that handle on their record.

And the two become one when an address turns up. The handle is carried the way a browser id is, which means the rule the rest of Kicklace already keeps applies here: an address arriving beside a handle that Kicklace only knew anonymously fills that record in, and an address that already belongs to somebody else folds the handle-only record into them, keeping the earliest first touch. So a sponsor who later signs up on your website is one person, not two.

Two people who both have addresses are never merged automatically. That rule is not bent here.

What is never read

An issue's body never reaches Kicklace. Not from a private repository, and not from a public one either. An issue's body is whatever somebody typed: it can be long, and it can carry a stack trace with a key in it. The title and the link are what land, and the issue itself is one click away with all of GitHub's own permissions still in front of it.

No secret key of yours is ever in one of these payloads, because Kicklace asks GitHub for nothing — GitHub posts, and Kicklace reads.

Stars

Off by default, and the switch is on the same frame: Record a star as a visit.

A star is not consent. Turning this on records that somebody was here and nothing more: no list, no subscription, no lifecycle move, and no email may be sent to them because of it. It is worth turning on if you want to see who is watching; it is worth leaving off if your repository has thousands of stars and you do not want thousands of records.

Unstarring is not recorded. Taking a star back is not something to write on somebody's timeline.

Automations to write

Under Automations, by hand or by asking Claude:

When somebody makes a purchase, wait 1 day, then send them Thank you for sponsoring.

When a support message arrives, create a task for me: Answer {{name}}, due today.

Both are ordinary sentences in the automation language — see the automation language — because a sponsor is a purchase and an issue is somebody writing in. A support message also means the person counts as engaged, so you can write to them directly from their record without putting them on any list.

When something does not arrive

Every post GitHub makes, taken or refused, shows on Settings → Your website → Your website's heartbeat, in plain words. The usual three:

  • No webhook secret is set for that endpoint yet — step 3 is not done, so nothing is taken.
  • The signature did not hold — the secret in GitHub and the secret in Kicklace are not the same words. Replace it in Kicklace, or edit the webhook in GitHub.
  • Not something Kicklace records — the event arrived and there was nothing to do with it: a ping, an issue being closed, a star with the switch off.

GitHub keeps its own log too, under Recent Deliveries on the webhook's page, with the exact request and Kicklace's exact answer. Redelivering from there is safe: nothing lands twice.

Disconnecting stops the address answering. Every sponsor, issue and star already recorded stays exactly where it is.