Sending webhooks
An outbound endpoint is a destination you register once, and an agent then POSTs to it by name. The destination can be a URL you control or another deployed agent in the same workspace, which is how two agents talk to each other without either of them holding a credential.
Two target kinds
A external endpoint POSTs to an http or https URL you supply. It generates a signing secret by default so the receiver can verify the payload, and you can opt out of signing if the receiver will not verify.
An agent endpoint POSTs to a sibling deployed agent. Signing is forced on and cannot be turned off, and the dispatcher signs with the receiving endpoint’s own secret rather than one you manage. The receiver needs an inbound endpoint configured for an agent sender before the send will land, so create that side first. Agent-to-agent deliveries also carry a source-agent header, so the receiving side can attribute who called.
Bind the endpoint to the agent that will use it and the dashboard groups it under that agent, which matters as soon as you have more than a couple.
Over REST
Endpoints live under /v1/outbound-webhook-endpoints, authenticated with Authorization: Bearer <key>. Names follow the same slug rule as inbound endpoints: 3 to 50 characters, lowercase alphanumeric and hyphens, starting and ending with a letter or digit, unique per workspace.
curl -X POST https://api.superagnt.com/v1/outbound-webhook-endpoints \
-H "Authorization: Bearer $AGNTDATA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "ops-notifier",
"targetKind": "external",
"targetUrl": "https://hooks.example.com/agnt",
"description": "Ping our ops service when a run finishes"
}'
# 201 → the endpoint id, plus the generated signing secret, shown once.| Route | Does |
|---|---|
POST /v1/outbound-webhook-endpoints | Registers a destination. A target URL is required for an external target and must be http or https; a target agent id is required for an agent target. |
GET /v1/outbound-webhook-endpoints | Every outbound endpoint in the workspace. |
GET /v1/outbound-webhook-endpoints/:id | One endpoint, including whether it holds a signing secret, but never the secret itself. |
GET /v1/outbound-webhook-endpoints/deliveries | The send log. Filter with endpointId, page with limit and cursor. |
DELETE /v1/outbound-webhook-endpoints/:id | Deactivates the destination — the soft delete. Sends to it start failing; agnt_webhooks_set_active re-enables it. |
no POST that sends
One tool does the dispatch
agnt_webhooks_send takes an endpoint (its name or its id) and a JSON payload. The body goes out as application/json with a 10 second timeout.
agnt_webhooks_send({
endpoint: "ops-notifier", // the endpoint name, or its id
payload: { run_id: "run_42", status: "completed", rows: 1840 }
})Four management tools sit alongside it: agnt_webhooks_create_outbound registers a destination, agnt_webhooks_update_outbound patches the target URL, description or signing requirement in place (renaming would break the sender’s calls, so it does not), agnt_webhooks_set_active disables an endpoint without deleting it, and agnt_webhooks_rotate_secret mints a new signing secret.
retries stop at one
The same scheme, both directions
A signed outbound delivery carries x-agnt-webhook-timestamp and x-agnt-webhook-signature (v1=<hex>) over v1:${timestamp}:${rawBody}, HMAC-SHA256, with the same five minute replay window the ingest receiver enforces. Sender and receiver share one implementation, so one verifier covers both directions.
The worked verifier, in Node and Python, is on Receiving webhooks. Hand it to whoever owns the receiving service, along with the signing secret.
signing on with no secret fails the send
Never on the API-key surface
A newly generated secret is returned once, at creation or at rotation. After that no /v1 route reveals it and none rotates it: reading a signing secret is a dashboard action, logged as a reveal, and rotation happens either in the dashboard or through agnt_webhooks_rotate_secret. An API key on its own can register destinations and read the audit log, but cannot extract the material that would let it forge a signed payload.
Rotation takes effect immediately and the previous secret stops working on the next send, so update the receiver in the same window.
Every attempt is a row
Each dispatch writes a delivery row, newest first, whether it succeeded or not. This is the surface that answers “did it actually go out, and what did the receiver say”.
| Field | What it tells you |
|---|---|
dispatch_status | pending, succeeded or failed. Anything below a 400 from the receiver counts as succeeded. |
response_status | What the receiver returned. Null means the request never completed (timeout or network error). |
response_body | Stored truncated. Enough to read an error message, not enough to archive a payload. |
attempt | 1 is the first try, 2 is the single auto-retry. A retry row points back at the attempt it retried. |
signed | Whether this delivery carried a signature. The first thing to check when a receiver rejects everything. |
receiving_delivery_id | For agent-to-agent sends, the delivery id the receiving endpoint created. Joins both halves of the hop. |
From an agent, agnt_webhooks_list_deliveries with the outbound direction returns that list, filtered by endpoint or by outcome, and agnt_webhooks_get_delivery returns a single row with the heavy fields the list omits: the full request payload and headers, and the response body and headers.
curl "https://api.superagnt.com/v1/outbound-webhook-endpoints/deliveries?endpointId=<id>&limit=50" \
-H "Authorization: Bearer $AGNTDATA_API_KEY"
# page forward with the returned cursor
curl "https://api.superagnt.com/v1/outbound-webhook-endpoints/deliveries?cursor=<cursor>" \
-H "Authorization: Bearer $AGNTDATA_API_KEY"Receiving webhooks
The ingest contract, the refusal codes, and the worked signature verifier.
Queues
The other way one agent hands work to another, when the handoff is a backlog rather than an event.
Schedules
Wake an agent on a clock, then have it notify your systems when it is done.