Documentation
Deployments from Vercel
Every production deployment can become a record in Kicklace — named after the commit, with its branch and a link to the build — moving through a pipeline of its own. Once a deploy is a record entering a stage, “when production deploys, draft the changelog email” is an ordinary automation.
Written for the developer who ships on Vercel (#199). Every production deployment becomes a Release in Kicklace — named after the commit, with its branch, its commit message and a link to the build — and releases move through a pipeline of their own, Deployed → Announced. There is no code to write and nothing to deploy.
Why a record and not an event: a deployment is not a person, and the automation engine runs on records. Once a deploy is a record entering a stage, "when production deploys, draft the changelog email" is an ordinary automation over the engine that was already there.
The screen is Settings → Integrations → Vercel, and only an owner or an admin can change it.
There is a shorter way in (#200): pressing Add Integration in Vercel writes Kicklace's keys into
your projects for you, allows their addresses, and — in the same click — makes the webhook this page
otherwise asks you to register by hand. docs/vercel-integration.md is that door. Everything below is
still how it works underneath, and is still the way to set it up when you would rather not install
anything.
Setting it up
1. Make the address. Settings → Integrations → Vercel → Connect Vercel. Two things happen:
you get an address of the form https://<your Kicklace>/api/webhooks/vercel/<token>, and the
workspace gains the Releases object with the pipeline Deployed → Announced. The token is not a
secret on its own — the signature is what proves a post came from Vercel — but it is not published
either, so a stranger cannot guess your endpoint.
2. Register it in Vercel. Choose your team in the Vercel dashboard, then Settings → Webhooks → Create Webhook. Tick Deployment Succeeded, choose which projects it covers, and paste the address as the endpoint URL. (Account webhooks are a Pro and Enterprise feature, and a team may have up to twenty of them.)
Ticking more events is harmless: everything else is answered 200 and ignored, which is what stops
Vercel retrying it.
3. Bring back the secret. The Webhook Created dialog shows a secret key once, and it is
not shown again. Paste it into the second step in Kicklace. It is encrypted at rest and never shown
back — the screen says "set on the 8th" and offers Replace. Until it is in, nothing is taken:
Kicklace answers no_signing_secret and writes the refusal to your heartbeat. If the secret has gone,
delete the webhook in Vercel and create it again.
Vercel signs with x-vercel-signature: an HMAC-SHA1 of the raw request body, hex, keyed with that
secret. There is no timestamp in the scheme, so there is no skew window to keep. Kicklace compares it
in constant time and refuses anything else.
What a deployment becomes
Only deployment.succeeded with target: "production" is a release. A preview is somebody's branch,
and deployment.created, deployment.error and deployment.canceled are a build's own progress: a
customer hears about what shipped, not about what was attempted.
One release lands in the stage Deployed, with:
| Field | From |
|---|---|
| Name | the commit message's first line, or Deployment dpl_… when there is no commit |
url |
the deployment's page in Vercel's dashboard, else the deployment's own host |
commit |
the whole commit message |
branch |
the branch it was built from |
sha |
the commit's SHA |
deploymentId |
Vercel's own id for the deployment |
deployedAt |
the day Vercel says the event happened |
The commit keys Vercel sends are prefixed with the git provider — githubCommitSha,
gitlabCommitMessage, bitbucketCommitRef — and Kicklace reads all three. A deployment made from
the CLI carries no commit at all, and that is a real deployment: it is named after its id and the
commit fields are left blank.
A deployment lands once. Vercel retries, and a webhook may be delivered more than once; the
release is looked up by deploymentId before anything is written, so a second post answers
already_recorded, writes nothing, and fires no automation.
The automation to write
Under Automations, by hand or through Claude:
When a Release enters Deployed, draft an email to Product updates from Release notes, for a person to send.
The draft_broadcast action writes the email to that list from that template's words, leaves it in
the composer, and tells the workspace's owners and admins that a draft is waiting. Nothing is sent
and nothing is scheduled. You open the draft, read what shipped, edit it, and send it yourself —
which is the only way a list of people ever hears from you in Kicklace.
Move the release to Announced when you have sent it, or add a move_stage to the automation that
sends nothing and only marks it.
What never happens
- Nothing is ever sent because you deployed. The action drafts; a person sends.
- Kicklace never talks back to Vercel. It reads the webhook and nothing else: no token, no API call, no deployment of yours started, stopped or promoted from here.
- Disconnecting keeps your releases. The address stops answering; the Releases object and every release in it stay exactly where they are. A webhook going away is not a reason to throw away what shipped.
- No traffic. Vercel has no webhook for visitors, so this door carries deployments only. Visits and signups come from Kicklace's own script tag, under Settings → Your website.
What you will see
Every post is one row in your website's heartbeat (Settings → Your website), marked as coming from a server, so Vercel's posts sit beside the website's: On the timeline, That deployment is already a release here, Not something Kicklace records, The signature did not hold.
The answers
| Answer | HTTP | What it means |
|---|---|---|
{ ok: true, status: "recorded", id } |
200 | A new release, and the trigger fired |
{ ok: true, status: "already_recorded", id } |
200 | This deployment is already here; nothing written |
{ ok: true, status: "ignored" } |
200 | A preview, a failed build, or an event Kicklace has no use for |
{ ok: false, error: "unknown_endpoint" } |
404 | No workspace has that address |
{ ok: false, error: "no_signing_secret" } |
400 | The second step is not done |
{ ok: false, error: "bad_signature" } |
400 | The signature did not match this body |
{ ok: false, error: "too_large" } |
413 | Over 128 KB |
{ ok: false, error: "server_error" } |
500 | Kicklace fell over; Vercel should retry |
Checked against Vercel's own documentation on 2026-09-08: https://vercel.com/docs/webhooks,
https://vercel.com/docs/webhooks/webhooks-api, and
https://vercel.com/docs/headers/request-headers#x-vercel-signature.