Docs

Webhooks

A named pairing of a partner's browser Origin and its notification URL — the address side of the API access chain.

What a Webhook Entry Is

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.

Api Keys

The record that binds a webhook entry.

Certificates

Delivered to the entry's notification URL.

Contracts

Per-tenant consumer policy & spaces.

Core Concepts

Origin
The exact 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.
Notification URL
A full 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.
API key binding
Set from the API key side — the "Pick a webhook" dropdown on the key form. A webhook entry can be bound to at most one API key at a time. The binding is one of the four an API key needs to be fully bound; without it the key's partner has no allow-listed origin and no address for notices, so it cannot reach the platform.
Wake
The admin action that sends a refresh notice to the entry's notification URL, available on a fully bound API key. Use it after you finish or change a partner's wiring — the partner re-fetches its configuration instead of waiting to discover the change.

Rules & Limits

  • Name: required and unique — it is how the entry appears in the API key form's picker.
  • Origin: required, in the form scheme://host[:port], unique across all webhook entries. Exact-match only — https://app.example.com and https://app.example.com:8443 are different origins.
  • Notification URL: required, a full URL starting with http:// or https://.
  • Binding: at most one API key per entry. On the key form a new pick re-binds, clearing the selection unassigns, and leaving the field untouched keeps the current binding.
  • Deleting a webhook entry does not delete the API key — the key simply loses the binding, stops being fully bound, and its partner loses access until another entry is bound.
  • Changes take effect immediately across the platform.

Receiving Notices

What a partner endpoint should do with a refresh notice.

  1. Accept the POST quickly and respond with a success status — treat it as a doorbell, not a delivery.
  2. Re-fetch the affected data through your authenticated API connection. The notice itself carries no payload to act on — this is deliberate, so a notification endpoint never becomes a place where data can leak or be spoofed.
  3. Design the endpoint to be idempotent: notices are best-effort and delivered once, without retries, and a re-fetch after a duplicate or missed notice always converges on the same state.
One special delivery
The certificate code handshake is the exception to "notices carry no data": after a partner claims its one-time certificate code, the public PEM and shared secret key are delivered to this notification URL — never to a caller-chosen address. See the Certificates page.

The Notice Payloads

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_agent
Your granted spaces or their agents changed — re-read GET /v1/space/list.
r_consumer_policy
Your contract or its policy changed — re-read GET /v1/resources/consumer-contract and GET /v1/resources/consumer-policy. A r_consumer_policy_delete means the contract was removed.
r_agent_front_settings
An agent's partner-facing front settings were saved — re-read GET /v1/resources/agent-front-settings?agentId=<slug>. This is the notice a front-settings save sends on its own.
r_json
The same agent front settings, but carried in the api-key Wake batch (alongside r_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_keys
A generic "something on your key changed" ping — re-read whatever you cache for the key.
r_cert · r_cert_delete
A certificate was delivered, rotated, or deleted. r_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

Once, no retries
Each notice is best-effort and sent once. A non-2xx response, a timeout (~5s), or an unreachable URL is logged on the KeenAgents side but never retried. Make the endpoint idempotent and fast — a re-fetch after a duplicate or missed notice always converges on the same state.
A missed refresh notice
Costs nothing the next fetch does not recover, because the notice carries no data. Your configuration is simply stale until your next authenticated read.
A missed certificate delivery
Is recoverable — unlike a refresh notice, it carried the material, but re-running the code handshake re-delivers it to the same URL. Never expose the shared secret to the browser.

In the Admin UI

  • Webhooks live as a sub-page of the API Keys sidebar section, with list, create and detail pages — gated by the shared api-keys permission for read and api-keys:w for write.
  • The create and detail forms carry the three fields: name, Origin and notification URL.
  • Binding happens on the API key form via the "Pick a webhook" dropdown, which offers unassigned entries plus the currently bound one on Edit.
  • The Wake button lives on the API key's detail page and is available only while the key is fully bound.
  • A Rebuild Resource Cache button on the entry's detail page rebuilds the API-key data this webhook's details live on, on demand — a shortcut to the same action on the Cache page. It is gated by the cache permission (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.
Webhook entry detail page

A webhook entry's detail screen — its name, the partner's browser Origin, and the notification URL.

origin uniquenotify-then-fetchbound from the API key side

Good to Know

  • A rejected Origin produces no error at all — KeenAgents simply drops the connection, so the caller sees a connection reset or a generic gateway error. This is deliberate: an unknown caller learns nothing from the refusal. It looks like an outage but is the allow-list working.
  • A partner seeing "silent drops" from a page that used to work usually moved origins — a staging domain, a new port, an http/https switch. Update the webhook entry's Origin to the page's real origin.
  • Changing the notification URL redirects every future notice and certificate delivery — coordinate with the partner before editing it, and Wake the key afterwards so the partner confirms the new address works.

Previous

Contracts

Next

Connecting a Site

Keen Agents 2026

Documentation

Release 15