create_media_buy, update_media_buy, sync_creatives or media_buy_delivery, the call includes
a push_notification_config. It says where to push the result and how to sign it. We reject an
unsigned or wrongly signed callback with 401, and the task is never resolved. A refused delivery
changes nothing on our side.
This page covers callbacks you send to Apostra. To verify the events Apostra sends to your own
endpoints, see Webhook endpoints; that is a different scheme.
Choose a profile
You can sign with one of three profiles, strongest first:
HMAC is deprecated in AdCP and removed in 4.0. AdCP 3.3 deprecates
brand.json key discovery, and
4.0 removes it, so new agents should sign with Web Bot Auth.
AdCP 3.3 Web Bot Auth
With Web Bot Auth, each delivery names its signer in theSignature-Agent header, and we fetch your public keys from
that origin’s key directory. We accept it on:
sync_creativescallbacks registered for RFC 9421 (see Creative-sync callbacks below);- storefront inventory-source callbacks;
- direct
media_buy_deliveryreports to a sales agent’s callback URL.
brand.json profile only for now.
To sign with Web Bot Auth:
- Publish a signed key directory at
/.well-known/http-message-signatures-directoryon the origin of your agent endpoint, the endpoint we have on file for your agent or source. - On each delivery, send
Signature-Agentwith your agent’s origin, plusSignature-Input(taggedweb-bot-auth) andSignature. - Cover
@method,@target-uri,@authorityandsignature-agent, and, when the callback has a body,content-typeandcontent-digest. - Use a fresh
nonceon every delivery attempt, including a retry, and keepexpireswithin 300 seconds ofcreated. - Optionally publish an origin revocation list at
/.well-known/governance-revocations.json. We refuse a key on that list.
- Origin. The origin in
Signature-Agentmust be the origin of the endpoint we registered for that agent or source. A signature from another agent’s directory, or from a different origin of your operator, gets401, however valid it is. - URL. The
@target-uriyou sign must be the callback URL exactly as we sent it inpush_notification_config.url, query string included. A signature made for one operation fails on any other. - Replay. A nonce we have already accepted gets
401. We record a nonce only after every check that could answer503has passed, so redelivering after a503is always safe, provided the retry is signed afresh.
RFC 9421 with brand.json keys
To sign the AdCP 3.2 webhook profile with RFC 9421 HTTP Message Signatures, you need:- An https agent endpoint that answers
get_adcp_capabilitieswithout credentials, over the protocol you registered with us (MCP or A2A). Your capabilities tell us where yourbrand.jsonlives. - A
brand.jsonwhoseagents[]entry for your endpoint has the same URL as the endpoint we call and declares ajwks_uri. SignatureandSignature-Inputheaders on each delivery. Always send both: aSignaturewith noSignature-Inputis refused rather than checked as HMAC.
brand.json like this:
- If your capabilities declare
identity.brand_json_url, we fetch that https URL. When it is on a different registrable domain from your agent, it must list your agent’s domain inauthorized_operators[]. - An AdCP 3.x agent that declares no
identity.brand_json_urlis looked up at/.well-known/brand.jsonon its origin, then on its registrable domain if that returns404or410. We follow at most oneauthoritative_locationorhouseredirect. - An AdCP 4.0 agent must declare
identity.brand_json_url.
HMAC-SHA256
Sign with theauthentication.credentials value from the push_notification_config on the call you
are answering. It is unique to that callback URL: it is not your Apostra API key, and a sales agent
that is also an inventory source receives a different value on each.
Send two headers:
Serialize the body once and sign the exact bytes you send. We allow 300 seconds of clock skew.
Node.js
@adcp/sdk webhook emitter produces this signature when
the push_notification_config declares HMAC-SHA256.
Creative-sync callbacks
We choose the scheme for eachsync_creatives call from the capabilities we have stored for your
agent, and it cannot change once we send the call:
- An HMAC delivery to a URL we registered without a credential gets
401. - An RFC 9421 or Web Bot Auth delivery for a call that carried a credential gets
401. - To go back to HMAC, set
webhook_signing.supportedtofalseor removeidentity.brand_json_url, unless your origin has already signed with Web Bot Auth. Calls already sent keep their scheme.