Webhooks vs polling
Both delivery mechanisms read from the same underlying data — pick whichever fits how your system is built, or use both.
Webhooks
Register a URL and we push a signed HTTP POST to it the moment a matching event is ready to deliver. Best if you want real-time delivery and don't want to manage your own polling schedule.
Verifying the signature
Every delivery carries a CompanyWatch-Signature header in the form
t={timestamp},v1={signature} — both values are packed into that one header, not
sent separately. Split it on the comma, then split each part on =, to get the
timestamp and the signature. The signature itself is an HMAC-SHA256 over the string
{timestamp}.{body}, keyed with your webhook's signing secret. Recompute it on your
end and compare before trusting the payload.
// Pseudocode
const [tPart, vPart] = signatureHeader.split(',') // "t=1755600000", "v1=9f86d081..."
const timestamp = tPart.split('=')[1]
const signatureFromHeader = vPart.split('=')[1]
expected = HMAC_SHA256(signingSecret, `${timestamp}.${rawBody}`)
if (!constantTimeEquals(expected, signatureFromHeader)) reject()
Retry behaviour
If your endpoint doesn't respond with a 2xx, we retry up to eight times over approximately two hours. Almost everything is retried, including ordinary 4xx responses, on the assumption that a failure during a deploy is usually transient. After the final attempt, the delivery is dead-lettered rather than lost silently.
Polling
Call /v1/updates to get everything new since your last call, in order. There are
two ways to use it, depending on whether you want the server to keep track of your position for
you or you want to control it yourself.
Letting the server track your position is the simplest method: call the endpoint
with no since parameter at all and it will return all updates since you last polled.
The downside is if there is a failure your side after you've received the results but before
you've processed them, those updates will be lost as a subsequent call to the polling endpoint will not return them again.
curl "https://api.company-watch.co.uk/v1/updates" \
-H "Authorization: Bearer YOUR_API_KEY"
Tracking the last processed update yourself protects you from a failure your side but requires
you to store the current position of your feed. Pass that position explicitly as ?since=, using either a nextCursor
from an earlier response or the id of the last update you processed. You should also use this method if two or more processes are polling
and you want them both to receive all updates.
Either way, treat the cursor as an opaque string and don't parse or construct one yourself. For
the full set of query parameters, response fields, and paging behaviour, see the
/v1/updates operation in the API reference.
Which should I use?
- Webhooks — you want real-time delivery and can expose a public HTTPS endpoint.
- Polling — you'd rather control the schedule yourself, or you're integrating from somewhere that can't easily receive inbound webhooks.
- Both — plenty of integrations use polling as a backstop even with webhooks registered, in case a delivery is ever missed.