Guides
Webhooks
Four state changes Orkasa pushes to you the moment they happen.
Polling a list tells you a deal closed up to a minute late, and costs a request every minute forever. A webhook tells you when it happens.
event_type | fires when | permission | payload |
|---|---|---|---|
deal_won | an operation reaches won · sold · rented | operations:read | the operation |
offer_accepted | an offer reaches accepted | offers:read | the offer |
signature_signed | a signature document reaches signed | signatures:read | the signature |
document_completed | a document reaches received or verified | documents:read | the document |
Each payload is produced by the same serializer as the matching list
endpoint, so a field means the same thing whether you polled it or were pushed
it. And the permission to subscribe is the resource's own :read — you can only
be told about what you could already have fetched.
Subscribe
curl -X POST "$ORKASA_API/hooks" \
-H "Authorization: Bearer $ORKASA_KEY" \
-H 'Content-Type: application/json' \
-d '{
"event_type": "deal_won",
"target_url": "https://hooks.zapier.com/hooks/catch/123/abc/"
}'
201 with a flat { "id": "…" } — no data envelope, because Zapier stores
the whole body as its subscribeData. target_url must be https.
Unsubscribe
curl -X DELETE "$ORKASA_API/hooks/<id>" -H "Authorization: Bearer $ORKASA_KEY"
204, always. A repeated unsubscribe, or one for something already gone, is
not an error: a Zap being torn down never fails on that step.
Test without waiting for an event
curl "$ORKASA_API/hooks/sample?event_type=deal_won" \
-H "Authorization: Bearer $ORKASA_KEY"
Recent rows already in the event's terminal state, in the normal envelope. A REST-hook has no past event to show while you are building the Zap; this fills that step, and doubles as a polling fallback.
How delivery works
Subscribing arms a database trigger, not a poll. On the qualifying transition — and only on the first one — the row is enqueued in an outbox, but only if someone is already listening: with no subscription for that brokerage and event, nothing is written at all. Silence costs nothing.
A cron drains the outbox every minute:
POST <target_url>
x-orkasa-event: deal_won
x-orkasa-signature: sha256=<hmac of the exact body>
content-type: application/json
The signature is HMAC-SHA256 over the exact bytes sent. Zapier does not verify it — its catch URL is itself the secret — but any other consumer should, and the header is simply omitted when no secret is configured.
At most once per target
That is the right default for a consumer that does not deduplicate:
- every target returned 2xx → delivered;
- every target failed → retried on the next run, up to 3 attempts. Safe: nobody saw it;
- some targets succeeded, or attempts ran out → marked delivered with the reason recorded. Retrying would re-POST to the targets that already got it, and a duplicated Zap run is worse than a missed one;
- the subscription vanished before serialization → nothing to send.
The outbox table is called outbound_webhook_events, not webhook_events:
that name was already taken by the inbound log for Stripe, Meta and
WhatsApp callbacks. The two are unrelated.