Orbit
Orbit Webhooks
Webhooks push a signed HTTP POST to a URL of your choosing every time a deployment changes state, so your team hears about a failed build in the channel they already watch instead of finding out from a customer.
Where Webhooks Live
Open Orbit, click the project, and choose Webhooks under the Configure group in the project tab strip. The page is titled Webhooks and describes itself as receiving HTTP POST notifications when deployments change state, with Slack, Discord and generic JSON supported.
Webhooks and Hooks are different things and sit next to each other in the same menu. Webhooks are outgoing: Orbit tells you something happened. Deploy hooks are incoming: something tells Orbit to deploy. For those, see Triggering Deployments Via Deploy Hooks.

Adding a Webhook
- In the Add a webhook card, give it a Label. Something like the destination it posts to.
- Paste the URL. It must start with
https://. - Under Trigger on, tick the events you want.
- Click Add webhook.
The signing secret is shown once, immediately after creation, with a warning that it will not be shown again. Copy it before you navigate away.
A project can hold up to ten webhooks. Adding an eleventh is refused with a message naming the limit.
The Five Events
| Event | Fires when |
|---|---|
| Queued | The deployment enters the queue |
| Building | The build starts |
| Succeeded | The deployment is live |
| Failed | The build or deploy errored |
| Cancelled | The deployment was stopped before finishing |
Pick deliberately. Subscribing to all five on a busy project turns a useful alert channel into noise that everyone mutes. For most teams, Failed alone is the right starting point, with Succeeded added only where a deploy notification is genuinely useful, such as a production channel.
Slack and Discord
If the URL is a Slack incoming webhook or a Discord webhook, Orbit detects it from the URL and sends a formatted message rather than raw JSON. The page says so under the URL field: Slack and Discord URLs are auto-detected.
The formatted message carries the project name, the event, the branch, the short commit, the build time, the deployed URL, and the error text when something failed. Colour follows the event, so a red card in the channel means a failure without anyone reading it.
Nothing else is needed. Create the incoming webhook in Slack or Discord, paste the URL here, choose your events, and you are finished.
Generic JSON Payloads
Any other URL receives a JSON body. The fields are:
| Field | Contents |
|---|---|
event | One of the five event names, prefixed deployment. |
projectId, projectName, projectSlug | Which project |
deploymentId | The deployment this is about |
gitCommit, gitBranch, gitCommitMessage | The code being deployed |
buildDurationMs | Build time, where known |
deployedUrl | Where it went live |
panelUrl | A link back into KPanel |
errorMessage | Present on failures |
triggeredAt | ISO 8601 timestamp |
deliveryId | Unique per delivery, for deduplication |
Use deliveryId to make your endpoint idempotent. If you retry a delivery, or a network hiccup causes a duplicate, the id lets you recognise that you have already handled it.
Verifying the Signature
Every delivery carries three headers:
X-Orbit-Signature-256, an HMAC-SHA256 of the exact request body using your signing secret, formatted assha256=followed by the hex digest.X-Orbit-Event, the event name.X-Orbit-Delivery, the delivery id.
Verify the signature before you act on a payload. Compute the same HMAC over the raw body bytes, and compare using a constant-time comparison rather than string equality.
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.ORBIT_WEBHOOK_SECRET)
.update(rawBody)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received))) {
return res.status(401).end();
}
Compute the HMAC over the raw request body, before any JSON parsing and re-serialising. A body that has been parsed and stringified again is usually byte-different, and the signature will never match no matter how correct your code looks.
Testing a Webhook
Each webhook row has Send test delivery. It fires a real delivery to your endpoint immediately and reports the HTTP code it got back, or the failure detail.
Use it right after adding a webhook, before you rely on it. A firewall rule or a route that only accepts GET is much easier to find now than during an incident.
Delivery History
Each row carries a sparkbar of the last seven days with the delivery count, success percentage and average duration, plus the last fired time and its result.
Expand Show delivery history for the individual deliveries: the event, the response code, the duration, and the error text where there was one. Any delivery can be re-sent with Retry delivery, which reports the code it got back.
Deliveries time out after twelve seconds. If your endpoint does slow work, acknowledge with a 200 first and process afterwards, rather than holding the connection open.
Rotating the Secret
Click Rotate secret. The new secret is displayed once, and the tooltip is explicit that the old secret becomes invalid immediately.
That means a short window where deliveries are signed with a secret your endpoint does not know. Plan for it: rotate at a quiet moment, and update your endpoint as the very next action.
Rotate when someone with access to the secret leaves, or if it has ever been pasted into a shared channel or a ticket.
Disabling and Deleting
Disable webhook stops deliveries but keeps the configuration and the history, and the row shows a Disabled badge. That is the right choice when you are pausing alerts, for example during a planned migration that will produce a lot of noise.
Delete webhook removes it entirely. Use disable unless you are certain.
Other Ways To Be Notified
Webhooks are the flexible option. Two lighter alternatives sit in Settings:
- Deploy email notifications, with three settings: all deploys, failures only, or off.
- Notification channels, which post to a webhook URL on deploy success or failure, build regressions and bundle regressions, with their own delivery history and test button.
See Orbit Project Settings for both.
Troubleshooting
Deliveries show as failed with an HTTP code. Your endpoint returned an error. The code tells you which: 404 means the path is wrong, 401 or 403 usually means your own signature check is rejecting it, and 500 means your handler threw.
Deliveries fail with a timeout. Your endpoint took longer than twelve seconds. Return 200 immediately and do the work asynchronously.
Nothing is delivered at all. Check the webhook is enabled and that the event you expected is ticked. A build that never queued does not fire a queued event.
The signature never validates. Almost always the raw-body problem described above. Log the exact bytes you are hashing and compare their length with the Content-Length header.
A Slack URL is being sent raw JSON. Slack incoming webhooks live under hooks.slack.com. A different Slack URL will not be detected as one.
Where To Go Next
- Triggering Deployments Via Deploy Hooks for the incoming direction.
- Orbit Project Settings for email notifications and notification channels.
- Orbit Status Page to tell your customers, not just your team.