Available events
Submissions
submission.created, submission.qualified, submission.updated, submission.deletedContacts
contact.created, contact.updated, contact.archived, contact.deleted, contact.tag_added, contact.tag_removed, contact.association_changed, contact.job_changedCompanies
company.created, company.updated, company.deleted, company.restored, company.merged, company.tag_added, company.tag_removedDeals
deal.created, deal.updated, deal.stage_changed, deal.won, deal.lost, deal.reopened, deal.deleted, deal.restored, deal.merged, deal.tag_added, deal.tag_removed, deal.association_changed, deal.line_item_added, deal.line_item_updated, deal.line_item_removedProducts
product.created, product.updated, product.archived, product.restoredQuotes
quote.created, quote.updated, quote.published, quote.viewed, quote.accepted, quote.voided, quote.deletedTasks
task.created, task.updated, task.completed, task.deleted, task.restoredMeetings
meeting.booked, meeting.rescheduled, meeting.cancelledCalls
call.completed, call.transcribed, call.analyzedLists
list.member_added, list.member_removedGET /api/v1/webhooks/events returns the same catalog, with subscribable telling you which groups the current token may subscribe to.
Scopes your app needs
The read scope is checked twice: when you subscribe (
403 insufficient_scope, with required_scopes, if the token lacks it) and on every delivery, against the app’s current installation in that workspace. A workspace that removes a scope from your app, or uninstalls it, stops receiving the matching deliveries without you doing anything. Register the scopes in the Developer Portal and request them during OAuth.
Subscribe after install
Once a workspace has authorized your app, create the subscription with its access token. Do it once per workspace, right after the OAuth callback, and keep the returnedid and secret with that workspace’s record.
- The
Idempotency-Keymakes the call safe to retry; a replay returns the webhook without the secret. - Your app only ever sees the webhooks it registered.
GET /api/v1/webhookswith a workspace’s token lists yours in that workspace. - Limits: 5 webhooks per workspace while your app is in development, 100 once it is approved. Creation is rate limited to 60 an hour per app per workspace (500 once approved); the response and a
429carryRateLimit-*headers. One webhook can subscribe to any number of events (X-Orbit-Eventand the envelope’seventsay which one arrived), so a single subscription per workspace is usually enough, andPATCHwithis_activepauses and resumes it without a delete and a new secret. form_idlimits a webhook to one form’s submission events. Every other event is workspace-wide, and a webhook with any of them refuses a form filter.filterslimits deal events to deals in given pipelines or stages:{ "pipeline_ids": [...], "stage_ids": [...] }, checked against where the deal is when the event happens (sodeal.stage_changedis judged by the stage the deal moved to). Other events on the same webhook are not filtered. There are no field filters: subscribe to the specific event you need (deal.wonrather thandeal.updated) to keep deliveries down.- The URL’s host is refused only when it points at a private or internal address. A host that does not resolve yet is accepted, so you can register a development endpoint before it is public; deliveries re-check the host every time. Localhost is never reachable from Orbit, so use a tunnel for local testing.
- A replayed create (same
Idempotency-Key) returns the webhook without its secret. If the original response was lost before you stored the secret, delete that webhook and create it again under a new key.
Receiving deliveries
Every delivery is a POST with the same envelope:team_id tells you which workspace the event belongs to, so one endpoint can serve every installation. actor.app_id is your app’s id (credential.app.id from GET /api/v1/me) when the change came from your own API call, so a sync can skip its own writes; see Changes your app made. source is app for ordinary activity and import for records a bulk import or CRM migration wrote; import events are only delivered once the workspace turned that on (see Imports), so a customer migrating from another CRM does not flood your app, and when they do turn it on you can tell those deliveries apart. Verify X-Orbit-Signature with the secret you stored for that webhook before reading anything else; see Webhook Security.
Delivery, retries and logs
- Submissions and meetings are delivered as they happen; CRM, call and submission-change events within about a minute.
- A failed delivery (timeout, connection error, 5xx or 429) is retried with exponential backoff, up to 3 retries by default.
Retry-Afteron a 429 is honoured. Other 4xx responses are final. - 10 consecutive failed events switch the webhook off.
GET /api/v1/webhooks/:idshowsis_active,consecutive_failuresandlast_error;PATCHwith{ "is_active": true }turns it back on. - Deliveries are at-least-once. De-duplicate on
id(also sent asX-Orbit-Event-ID); a retry carries the same one. Order is not guaranteed; useoccurred_at. GET /api/v1/webhooks/:id/deliverieslists every attempt, with status codes and errors, for debugging a customer’s installation.
Best practices
Respond quickly
Return a 2xx within a few seconds and process the event in a queue. The default timeout is 30 seconds.
Verify signatures
Validate
X-Orbit-Signature with the webhook’s secret before processing.Handle retries
Store processed event ids so a retried delivery is a no-op.
Fetch what you need
Payloads carry the record that changed, not its related records. Use the API for a deal’s contacts, a call’s transcript or a submission’s form.
Expect imports to be off
Records written by a CSV import, the API’s bulk endpoints or a CRM migration are not delivered unless the workspace’s owner turned on Send imported records to integrations (Settings → Integrations → Connected apps). If your app needs a customer’s existing records, read them through the API instead of waiting for
contact.created; when a workspace does turn import delivery on, deliveries carry "source": "import".Clean up on uninstall
Deliveries stop on their own when a workspace removes your app, and every token you hold for that workspace is revoked (
401 invalid_token, refreshes 400 invalid_grant). Set an uninstall URL in the Developer Portal to be told right away: Orbit POSTs { "event": "app.uninstalled", "app_id", "client_id", "team_id", "uninstalled_at", "reason" } there, signed in X-Orbit-Signature with your app’s signing secret (same HMAC-SHA256 scheme as deliveries), with X-Orbit-Event: app.uninstalled and X-Orbit-Timestamp. Answer 2xx. A 429, a 5xx or no answer in time is retried three times; any other 4xx is final. reason is workspace_removed or app_suspended. Revoking the last live token you hold for a workspace ends its installation too, without a notification; while another member’s token is live, the installation stays.Next steps
Event payloads
Every event’s
dataWebhooks API
Create, change, delete, and read the delivery log