Outbound webhooks
Centerfy POSTs a JSON event to your URL when something changes: 45 events across contacts, appointments, opportunities, messages, notes, conversations, contracts, invoices, quotes and team.
Outbound webhooks push changes to you; the inbound API is how you push changes to Centerfy. Each event is one HTTP POST with a JSON body, sent immediately after the change is saved.
Set up
In the app: Settings → API & Webhooks → Webhooks. Enter a default URL, tick the events you want (each event can override the URL), optionally set a Source label, and use Send test to check your endpoint. The panel also shows the example payload for every event.
Through the API: the outbound webhook subscription endpoints create subscriptions with a generated secret token and an optional Source, rotate the secret, list deliveries and re-send one.
Delivery
| Method | POST, Content-Type: application/json. The body is one event object. |
| Authentication | If the subscription has a secret token, every request carries it twice: Authorization: Bearer <token> and X-Webhook-Token: <token>. Reject requests without it. |
| Timing | Sent once, right after the change is saved. Respond with any 2xx quickly; do your work asynchronously. |
| Retries | No automatic retries. Every attempt is logged with its status code and response, and a failed delivery can be re-sent from the panel or with Redeliver. |
| Test sends | Send test and the test endpoint post an example payload with the header X-Webhook-Test: true. |
| Loop prevention | Changes made through the API with X-Webhook-Source equal to the subscription’s Source are not sent to that subscription. |
| Ordering | One change can produce several events: moving an opportunity sends opportunity.updated and opportunity.stage_changed. Don’t rely on their order; use occurred_at. |
Envelope
Every payload has these top-level fields, plus an object for the entity (contact, opportunity, invoice, …) and, for change events, the previous values.
| Field | Description |
|---|---|
event | Event name, e.g. opportunity.stage_changed. |
occurred_at | ISO 8601 timestamp of the change (UTC). |
sub_account_id | Sub-account the event belongs to. |
organization_id | Agency that owns the sub-account. |
{
"event": "contact.created",
"occurred_at": "2026-06-20T14:30:00.000Z",
"sub_account_id": "<sub account uuid>",
"organization_id": "<organization uuid>",
"contact": { "id": "<uuid>", "name": "Jane Doe", "email": "[email protected]", "…": "…" }
}
Events
Each page lists when every event fires and the exact JSON payload.