Webhooks
Webhooks let ClientLoop notify your systems when something happens — for example, when an application's status changes — by sending an HTTP request to a URL you control, instead of you having to poll the API.
A webhook is a subscription owned by an agency or an org. It has:
- a URL — the HTTPS endpoint ClientLoop delivers to;
- a list of events it is subscribed to (see Events);
- an enabled flag controlling whether deliveries are sent;
- a signing secret, returned once when the webhook is created, that you use to verify a delivery's signature and confirm it genuinely came from ClientLoop.
Delivery
When a subscribed event occurs, ClientLoop sends an HTTP POST to the
webhook's URL with the event payload as a JSON body. Each request is signed —
verify the signature before trusting it — and you
respond with 200 or 201 to acknowledge the delivery.
If your endpoint returns any other status (or is unreachable), the delivery is
retried with exponential backoff — growing up to one hour between
attempts — for up to 7 days. After that the delivery is marked failed and
no further attempts are made.
Every delivery is recorded, retained for 90 days, and can be retrieved for a webhook through the API so you can inspect attempts, response codes, and the delivered payload.
Payload format
Every payload is a JSON object. Alongside the event-specific fields it always carries three common fields:
type— identifies the event and its payload version (e.g.application.status.changed.v1), so a single endpoint can dispatch on it. It matches the entry in the webhook'seventslist. See Versioning.eventId— a stable identifier for this delivery. It is identical across every retry, so use it to deduplicate (deliveries are retried for up to 7 days, so the same event can reach you more than once).requestId— a fresh identifier minted for each individual delivery attempt, useful for tracing a specific request in your logs. It is also sent as thecl-request-idheader.
{
"eventId": "WebhookRequest#2cVQF8s0u9c2bq5b3pTn1mY7kde",
"requestId": "2dWRg9t1v0d3cr6c4qUo2nZ8lef",
"type": "application.status.changed.v1",
"...": "event-specific fields"
}See Events for the catalog of events and their payloads.
Versioning
Each payload type is versioned with a trailing .v<n> (e.g.
application.status.changed.v1). Within a version, changes are only ever
additive: new fields may be added to an existing version, but a field is
never renamed or removed without publishing a new payload version (e.g.
application.status.changed.v2). Parse defensively and ignore unknown fields so
an added field does not break your handler.
You subscribe to a specific version by listing its type in the webhook's
events, so moving to a new version is always an explicit choice on your part.
When a new version is published, the previous one is deprecated rather than removed immediately:
- These docs are updated as versions are deprecated and new versions are added.
- An email notice is sent to the technical contact listed on the organization.
- A deprecated version generally remains available for 180 days after its deprecation, giving you time to migrate.