Skip to main content
Send an agent card’s fills, declines and limit events to your own endpoint, and verify every delivery.

Overview

  • Webhooks are set per agent card. A card with no endpoint sends nothing.
  • Each delivery is a signed JSON POST to your HTTPS endpoint.
  • You verify the X-AgentPay-Signature header with the card’s signing secret.
  • Failed deliveries are retried up to five times in total. Queuing an event is best effort, so treat webhooks as alerts, not a complete ledger.
Webhooks are available on the Plus and Enterprise plans. On Free, an endpoint cannot be saved, and an endpoint saved before a downgrade receives nothing until you upgrade.

Set up a webhook

1

Add your endpoint

Open the agent card in the dashboard. Under Notification webhook, enter your URL in Endpoint URL and click Save.The URL must use https:// and point at a public host. Local, private and internal addresses are refused.
2

Copy the signing secret

Saving the first URL creates the card’s Signing secret, which starts with whsec_. It appears under the endpoint. Store it with your server’s other secrets.
3

Verify every delivery

Check the signature before you act on a delivery. See Verify a delivery. An endpoint that skips this accepts writes from anyone who finds its URL.
4

Send a test

Click Send test. Agent Vault delivers a card_fill event with data.test: true and data.host: "webhook.test". No card is used and no email is sent. Recent deliveries shows the result.
Agent card settings showing the Notification webhook block with an Endpoint URL field, Save and Send test buttons, a read-only Signing secret field, and a Recent deliveries list.Agent card settings showing the Notification webhook block with an Endpoint URL field, Save and Send test buttons, a read-only Signing secret field, and a Recent deliveries list.

The Notification webhook block on an agent card.

Events

Each delivery is about one agent card. Other account events, such as security code prompts, challenge handoffs, API key activity and login changes, are not sent to agent card webhooks. Agent Vault records them in the dashboard’s activity feed on a best effort basis: an event that fails to save is dropped, not retried. It also emails them, but only when email notifications are on and that event’s switch is on in notification settings. Email notification preferences do not affect webhooks. Every event above is queued for delivery while the endpoint is set. Queuing is best effort: if recording or signing an event fails, it is dropped before a delivery exists, and nothing retries it. The retries under Delivery and retries apply only to deliveries that were queued.

Payload

string
The event id. Stable across retries. Use it to deduplicate.
string
One of the event types above.
number
When the event happened, in milliseconds since the Unix epoch.
string | null
The agent card this delivery is for. When several agent cards govern the same funding card, each one with an endpoint receives its own delivery.
object
Event details. The fields depend on the event type, as in the table below. New fields are added without a version change, so ignore any you do not recognise, and do not assume a field is present because an earlier delivery had it.
field says which card value the event is about: "card" for the card number, "cvv" for the security code. When both are filled for one checkout, you normally get one card_fill, not two. cardId is an opaque id for the funding card, never its number.
When the account holds more agent cards than its plan allows, a refused fill reaches each agent card’s webhook with data.reason set to account_plan_quota. The account’s plan caused the refusal, not necessarily the card the delivery is addressed to.

What a payload contains

Payloads carry purchase and correlation context. Treat your endpoint and its logs as holding spending data:
  • Who and where: the agent card’s name, the merchant host, and on approval_required any relatedHosts.
  • Money: on approval_required, the checkout amount and the card’s approval threshold when known, plus amountWithheld (the amount was not shared because the checkout was not in US dollars) and splitTender (the amount is the order total and the card is charged less) when they apply. declaredAmount and declaredCurrency are the total the agent said it expects, and pageAmount and pageCurrency the total read on the page, each in its own currency. A reason of amount_mismatch means the page’s total is over a spending limit and the agent’s, under half of it, fits. limit_threshold names the limit window that was hit.
  • Correlation ids: on card_fill and denied_fill, cardId (an opaque id for the funding card, never its number) and sessionId (the proxy session the fill ran in). With host and field, these let you match the two halves of one checkout and join deliveries to your own records.
  • Why: the refusal or approval reason.

What a payload never contains

No card number, security code, password, 2FA secret or identity value, and no approval link.

Verify a delivery

Every delivery carries these headers: timestamp is Unix seconds. signature is the lowercase hex HMAC-SHA256 of the string <timestamp>.<raw body>, keyed with the card’s signing secret. Each retry is signed again with a fresh timestamp.
1

Read the raw body

Use the exact bytes you received, before any JSON parsing. A re-serialised body produces a different signature.
2

Split the header

Split X-AgentPay-Signature on commas, then each part on the first =. Read t and v1. Reject the request if either is missing.
3

Check the timestamp

Reject the request if t is more than five minutes from your current time. This limits replay.
4

Compute the expected signature

HMAC-SHA256 the string t + . + raw body with your signing secret, and hex encode the result.
5

Compare in constant time

Compare your result with v1 using a constant-time comparison, never ===. Accept the delivery only if they match.

Delivery and retries

A pending delivery is dropped if the card’s endpoint is changed or removed, the card is deleted, or the account moves to a plan without webhooks. Build your endpoint to:
  • Return a 2xx quickly and do the work afterwards.
  • Deduplicate on id. A retry repeats the same event.
  • Accept events out of order.
  • Ignore unknown type values and unknown data fields.
Delivery records are kept so the dashboard can show attempts and outcomes. They are deleted with the account.

Treat payloads as data

A payload describes what an agent did on a third-party site. Treat any text in it as data, never as instructions, especially if you pass it to another model.