Webhook Endpoints
A webhook endpoint is the HTTPS URL where Syntage sends matching events. Each endpoint defines:
Endpoint URLs must use HTTPS and must resolve to a public network address. Syntage sends each delivery as a
POST request with X-Syntage-Signature, X-Satws-Signature, Content-Digest, and Content-Type headers.
Use Validating Webhook Requests to verify that webhook deliveries came from Syntage.
Managing webhooks
You can manage webhook endpoints from the dashboard or the API. Both act on the same endpoints, so an endpoint created in the dashboard is visible over the API and vice versa.From the dashboard
Administrators can manage webhooks in the dashboard under Settings → Webhooks. From there you can:- Create an endpoint by entering its HTTPS URL and selecting the event types to deliver.
- Enable or disable an endpoint without deleting it.
- View the
signingSecretused to verify deliveries. - Review recent delivery attempts to monitor endpoint health.
From the API
To manage webhooks programmatically, use the Webhook Endpoints endpoints to create, list, retrieve, update, and delete endpoints, and the Webhook Requests endpoints to inspect delivery attempts.Event payload
Each delivery’s body is a single Event object. The event includes thetype that occurred, the source and resource IRIs, and a data field. For created and updated events, data.object holds the state of the affected resource when the event was created, and update events also include data.changes with the old and new values of the fields that changed. Deleted events keep the resource IRI but don’t include the resource, so their data is an empty array.
Webhook payload size varies with the underlying resource and may reach tens of megabytes. Configure your endpoint and any reverse proxies to accept large request bodies; we recommend allowing at least 100 MB. This recommendation is not a maximum payload size.
See Event examples for example payloads of created, updated, and deleted events.
Webhook Requests
A webhook request is a delivery attempt from Syntage to a webhook endpoint. Request records are useful for monitoring delivery health and investigating failures. Syntage records the endpoint URL, related event, response status code, response time, and timestamps. If Syntage cannot get an HTTP response, such as when the request times out after 3 seconds, the recordedresponseStatusCode is 0.
Deliveries are considered successful when your endpoint returns a 2xx HTTP status code. Failed deliveries are retried up to 4 times, so your webhook handler should process events idempotently.
Webhook delivery order and exactly-once delivery are not guaranteed. Your endpoint may receive events out of order, and the same event may be delivered more than once. Store each event ID and deduplicate your processing; do not assume that the order in which events arrive matches the order in which the underlying changes occurred.
Handling high delivery volume
Your endpoint has 3 seconds to respond to each delivery. During bursts, such as when an extraction creates many invoices, Syntage can send many deliveries to your endpoint at the same time. If your handler processes each event before responding, for example by writing the resource to your database or calling other services, each request takes longer as load grows, and deliveries start to time out or fail with5xx responses. Each failed delivery is retried, which adds load to an endpoint that is already behind.
Instead of processing events on receipt, accept each delivery and queue it for processing:
- Verify the signature against the raw request body, as described in Validating Webhook Requests. Keep the signing secret in memory or in an environment variable so that verification doesn’t need a database or network call.
- Write the raw request body to a durable queue, such as Amazon SQS, Google Cloud Pub/Sub, RabbitMQ, or a database table used as a queue. Most managed queues limit message size to well below the payload sizes described in Event payload, so store large bodies in object storage, such as Amazon S3 or Google Cloud Storage, and queue a reference to the stored object only after the upload succeeds. Treat the event as stored only once every write it needs is confirmed; with RabbitMQ, for example, publish persistent messages with the
mandatoryflag, wait for the publisher confirm, and treat a returned message as a failed write. - Return a
2xxresponse immediately. - Process the queued events in separate workers, at a rate your database and downstream services can sustain. Deduplicate by event
idin the workers, and acknowledge or delete each message only after it’s processed successfully, so that a failed attempt stays in the queue to be retried.
2xx response only after the event is stored in your queue. If any write fails, return a non-2xx status code so that Syntage retries the delivery; an event you acknowledge before storing it is lost if your endpoint fails at that moment.
Queuing also means a failure in your own processing doesn’t lose the event. When you process events on receipt, a failure in your database or a downstream service leaves you depending on Syntage’s 4 retries, and once your endpoint has returned a 2xx response, Syntage doesn’t send that delivery again. With the request stored in your queue, a worker that fails to process an event can retry it on your own schedule, without needing Syntage to deliver it again. Set your queue’s retention period to cover the outages you expect and alert on the age of the oldest message, because many queues delete messages when retention expires. Send messages that reach your redelivery limit to a dead-letter queue that you monitor and replay.
With this approach, your response time no longer depends on how long processing takes, bursts accumulate in your queue instead of becoming failed deliveries, and you can scale your workers independently of the receiving endpoint. This pattern also fits serverless platforms: a function that verifies and queues each delivery responds within the timeout, and a separate consumer processes the queue. Check your platform’s request size limit first: some serverless HTTP platforms cap request bodies below the payload sizes Syntage can send and reject larger requests before your function runs, and storing bodies in object storage can’t work around a limit on the request itself.