A named pairing of a partner's browser Origin and its notification URL — the address side of the API access chain.
Where a partner's requests come from, and where its notifications go.
A webhook entry is a standalone resource with three fields: a name, the partner's browser Origin, and the partner's notification URL. It answers the two address questions of a partner integration in one record: which web origin the partner's application calls from (the inbound side), and where KeenAgents delivers refresh notices to the partner's server (the outbound side).
A webhook entry does nothing on its own — an API key points at it, the same way a key binds its Client, Certificate and Contract. Origins are unique across your organization's webhook entries, so an inbound request's Origin header always resolves to exactly one entry, and through it exactly one API key and the rest of that partner's chain.
scheme://host[:port] the partner's browser application runs on — no path, no trailing slash — so it matches the browser's Origin header byte for byte. The port matters (browsers omit only the default 80/443), wildcards are not supported, and the value is unique across all webhook entries. Together, the origins of every fully bound key form the organization's Origin allow-list.http:// or https:// URL on the partner's server. Refresh notices land here: lightweight POSTs that say something changed — never the data itself. On receipt the partner re-fetches what it needs over its authenticated API connection (notify-then-fetch), so a missed notice costs nothing that the next fetch does not recover.scheme://host[:port], unique across all webhook entries. Exact-match only — https://app.example.com and https://app.example.com:8443 are different origins.http:// or https://.What a partner endpoint should do with a refresh notice.
Exactly what KeenAgents POSTs to your notification URL — the request you receive, and how to answer it.
KeenAgents is the caller here: it POSTs to your notification URL. Every notice is POST with Content-Type: application/json and a body whose synch-data field names what changed. Two shapes exist — the ordinary refresh notice (an array of change kinds, no data) and the one certificate delivery (carries the material). There is no authentication header on the notice; it is a doorbell, and the value lives behind your own authenticated re-fetch, never in the notice itself.
Refresh notice — the ordinary case (no payload)
POST <your notification URL> Content-Type: application/json { "synch-data": [ "r_api_keys" ] } // a Wake batches every list to re-read into one POST: { "synch-data": [ "r_api_keys", "r_consumer_policy", "r_space", "r_agent", "r_json" ] } // you respond fast with any 2xx — the body is ignored: → 200
The synch-data kinds tell you which authenticated read to make next:
r_space · r_agentGET /v1/space/list.r_consumer_policyGET /v1/resources/consumer-contract and GET /v1/resources/consumer-policy. A r_consumer_policy_delete means the contract was removed.r_agent_front_settingsGET /v1/resources/agent-front-settings?agentId=<slug>. This is the notice a front-settings save sends on its own.r_jsonr_api_keys, r_consumer_policy, r_space, r_agent) rather than by a settings save — re-read the same GET /v1/resources/agent-front-settings?agentId=<slug>. Treat r_json and r_agent_front_settings as the same re-read, from two triggers.r_api_keysr_cert · r_cert_deleter_cert is the one notice that carries a payload — see the next block.Certificate delivery — the one notice that carries data
POST <your notification URL> Content-Type: application/json { "synch-data": "r_cert", // a bare string here, not an array "type": "resource", "result": { "cert": "-----BEGIN PUBLIC KEY-----\n…\n-----END PUBLIC KEY-----", "key": "<shared secret>" // "" when the admin never set one } } → 200
This lands after you claim a certificate code (see Connecting a Site), and again whenever an admin rotates the certificate or presses Wake. Store result.cert (the public key you verify KeenAgents-issued tokens with) and result.key (the shared secret) when it arrives. If you miss a delivery, run the code handshake again to have it re-sent — it is not one-time-forever.
Delivery semantics & failure modes
api-keys permission for read and api-keys:w for write.cache read, cache:w write), separate from the edit permission, so a cache manager can refresh it while an editor without cache rights never sees the button. You rarely need it — normal saves refresh the copy automatically. See Resource Cache.
A webhook entry's detail screen — its name, the partner's browser Origin, and the notification URL.
Keen Agents 2026
Documentation
Release 15