Skip to main content
Webhooks let Contractors Cloud notify your application the moment something happens, instead of you polling the API for changes. Create a webhook pointing at an HTTPS endpoint you control, subscribe it to one or more events, and Contractors Cloud sends a POST request with a JSON payload to that endpoint every time one of those events occurs.

Creating a webhook

company_id is optional. Omit it (or send null) to receive matching events across every company in your organization, or set it to scope the webhook to a single company. The response includes a signing_secret:
signing_secret is a credential — store it the way you’d store any other secret, and never expose it to a browser or client app. It’s returned on every response for this webhook (including list results), but there’s no separate endpoint to retrieve or rotate it. To change it, delete the webhook and create a new one.
See Create webhook for every field, and Update webhook and Delete webhook for managing it afterward — deleting a webhook also removes all of its event subscriptions and its entire delivery history.

Subscribing to events

A new webhook isn’t subscribed to anything by default. Discover the current catalog of events with List subscribable events:
Then subscribe your webhook to one with Create webhook event:
A webhook can subscribe to as many events as you like, but only once each. The endpoint above is the authoritative list of what’s currently subscribable — treat the table below as a reference, not a substitute for checking it: See the Webhook Events reference for listing, updating, and removing subscriptions.

Receiving deliveries

Every delivery is a POST request with a Content-Type: application/json body in the same envelope, regardless of event:
data matches the shape of the corresponding resource returned elsewhere in the API — the example above is trimmed to representative fields; a real projects.created delivery includes the full project resource. Financial breakdown fields (such as financials_total_amount and expenses_total_amount) may be omitted from a project payload depending on the permissions of the user whose action triggered the event; amount_estimated and estimated_total_amount are always present. See the Project type for the full field list. Your endpoint has 10 seconds — connection and response combined — to return a 2xx status code. Returning anything else, or not responding in time, marks the delivery error or timeout respectively; see Retries for what happens next.

Verifying signatures

Every delivery carries a ContractorsCloud-Signature header so you can confirm it came from Contractors Cloud and wasn’t tampered with in transit:
t is the Unix timestamp the delivery was sent, and v is the hex-encoded HMAC-SHA256 signature of the string <t>.<raw request body>, computed with your webhook’s signing_secret as the key. To verify a delivery:
  1. Extract t and v from the header.
  2. Compute hash_hmac('sha256', "{t}.{raw_body}", signing_secret) against the raw request body bytes exactly as received — re-serializing the parsed JSON can reorder keys or change whitespace, which changes the signature.
  3. Compare your computed value to v using a constant-time comparison, not == or string equality, to avoid leaking timing information.
Optionally, reject deliveries whose t is too old (for example, more than 5 minutes in the past) to reduce the window for replay attacks.

Retries

If a delivery comes back error or times out, Contractors Cloud automatically retries it up to 3 times: roughly 1 minute, then 15 minutes, then 60 minutes after the previous attempt. Each retry is a new send record with retry_parent_id pointing back at the attempt it retried, a fresh timestamp and signature, and the identical request body.
Deliveries aren’t guaranteed to arrive in order, and the same event can be delivered more than once (for example, if a retry and the original both eventually succeed). Design your endpoint to handle duplicate and out-of-order deliveries — for example, by keying off a stable field in data rather than assuming strict arrival order.

Testing and monitoring

Verify your endpoint and signature-checking logic without waiting for a real event, using Send test webhook:
This takes no request body and always delivers the same fixed payload, with data set to {"id": "foo", "value": "bar"}. It works even if the webhook is disabled or has no event subscriptions yet, which makes it useful for confirming a new webhook is reachable before you subscribe it to anything. Every delivery attempt — test or real — is recorded as a webhook send, including the exact request body sent and the response your endpoint returned, retained for 365 days. List them with List webhook sends to audit past deliveries, and watch a webhook’s error_rate as an ongoing health signal for roughly the last 90 days of activity.
See the Webhooks reference for every field and status code, and Webhook send for the full shape of a delivery record.