Webhook Guide
Subscribe to appointment events and receive JSON payloads in your systems as they happen.
When to Use
- Keep CRMs, marketing platforms, or BI tools in sync without polling.
- Trigger custom automations (e.g., send swag kits when appointments are confirmed).
- Receive notifications for failures in external systems.
Core Concepts
- Location Scoped: Webhooks are created per location, so each header/payload is only sent for events at that location.
- Triggers: Must be a subset of
NEW_APPOINTMENT,APPOINTMENT_CONFIRMED,APPOINTMENT_CANCELLED,APPOINTMENT_RESCHEDULED,APPOINTMENT_REMINDER. - Headers: Optional key/value pairs appended to every delivery (use for auth tokens or tenant IDs). Hop-by-hop and cloud-metadata header names are rejected.
Content-Typeis alwaysapplication/json. - Destination: Must be public
https. Query strings are allowed.http, credentials in the URL, fragments, IP literals, localhost, and internal/metadata hosts are rejected with400. - Active Flag: Toggle delivery without deleting configuration.
Endpoint Overview
| Endpoint | Purpose |
|---|---|
GET /v3/webhook?locationId=<uuid> | List webhooks for a location. |
POST /v3/webhook?locationId=<uuid> | Create a webhook (url, headers, triggers, active). |
POST /v3/webhook/setWebhooks?locationId=<uuid> | Replace the entire set for a location in one request. |
All routes require company authentication. Create and replace requests reject destinations that are not public https.
Payload Structure
Deliveries are POST requests with body:
{
"appointment": { ...appointment fields... },
"trigger": "NEW_APPOINTMENT"
}The appointment payload matches the appointment object used when the event is dispatched, plus trigger.
Security Recommendations
- Use public HTTPS: The destination must be a globally reachable
httpsURL. Private, loopback, link-local, CGNAT, and cloud-metadata addresses are not delivered. Existing non-https rows remain visible onGETuntil you replace them. - Deliveries are not signed. OnSched does not attach a signature header. To authenticate the caller, set your own secret in
headerswhen you create or replace the webhook (for exampleAuthorizationorWebhook-Secret). The API echoes those headers, except hop-by-hop and metadata names (Host,Cookie,Metadata-Flavor, and similar). - Do not allowlist source IPs. OnSched does not publish webhook source address ranges.
- Respond quickly: Return a
2xxstatus within about five seconds. Long-running work should happen asynchronously on your side. Redirects are not followed. - Replace to remove. There is no update or delete route.
POST /v3/webhook/setWebhooksreplaces the entire set for a location. Send an empty list to remove every webhook at that location.
Retry Behavior
Webhooks are sent once. If the destination responds with a non-2xx status, times out (~5 seconds), or is not an allowed public https URL, an error is logged but the API does not automatically retry and the appointment change still succeeds. If reliability is critical, relay deliveries through your own queue or monitor logs via observability tooling to reprocess failures.
Troubleshooting
- Not receiving events: Ensure the webhook is
activeand that the location ID matches the appointments being created. - Multiple events per booking: Actions like rescheduling emit both
APPOINTMENT_RESCHEDULEDand a newNEW_APPOINTMENTfor the replacement slot, so handle idempotency by referencingappointment.id. - Headers missing: Remember to send headers as a nested JSON object when creating or setting webhooks. Only string values are supported.
See also
Updated 1 day ago
Did this page help you?
