Skip to main content
When Apostra calls your sales agent or inventory source with an async task, such as 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.
We do not step down from Web Bot Auth. After we accept one delivery signed with Web Bot Auth from your origin, we refuse every RFC 9421 brand.json delivery and every HMAC delivery from that origin with 401, whatever its signature. We do not fall back to them if a Web Bot Auth delivery fails. Roll your signing keys through your key directory instead. Moving back to an older profile is not a setting you can change; contact us if you need it.

AdCP 3.3 Web Bot Auth

With Web Bot Auth, each delivery names its signer in the Signature-Agent header, and we fetch your public keys from that origin’s key directory. We accept it on:
  • sync_creatives callbacks registered for RFC 9421 (see Creative-sync callbacks below);
  • storefront inventory-source callbacks;
  • direct media_buy_delivery reports to a sales agent’s callback URL.
Storefront catalog and change-feed callbacks accept the brand.json profile only for now. To sign with Web Bot Auth:
  1. Publish a signed key directory at /.well-known/http-message-signatures-directory on the origin of your agent endpoint, the endpoint we have on file for your agent or source.
  2. On each delivery, send Signature-Agent with your agent’s origin, plus Signature-Input (tagged web-bot-auth) and Signature.
  3. Cover @method, @target-uri, @authority and signature-agent, and, when the callback has a body, content-type and content-digest.
  4. Use a fresh nonce on every delivery attempt, including a retry, and keep expires within 300 seconds of created.
  5. Optionally publish an origin revocation list at /.well-known/governance-revocations.json. We refuse a key on that list.
We accept a delivery only for the agent the callback URL is bound to:
  • Origin. The origin in Signature-Agent must 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, gets 401, however valid it is.
  • URL. The @target-uri you sign must be the callback URL exactly as we sent it in push_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 answer 503 has passed, so redelivering after a 503 is 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_capabilities without credentials, over the protocol you registered with us (MCP or A2A). Your capabilities tell us where your brand.json lives.
  • A brand.json whose agents[] entry for your endpoint has the same URL as the endpoint we call and declares a jwks_uri.
  • Signature and Signature-Input headers on each delivery. Always send both: a Signature with no Signature-Input is refused rather than checked as HMAC.
We find your brand.json like this:
  1. 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 in authorized_operators[].
  2. An AdCP 3.x agent that declares no identity.brand_json_url is looked up at /.well-known/brand.json on its origin, then on its registrable domain if that returns 404 or 410. We follow at most one authoritative_location or house redirect.
  3. An AdCP 4.0 agent must declare identity.brand_json_url.
When a delivery carries both RFC 9421 and HMAC headers, we check RFC 9421 and ignore the HMAC headers.

HMAC-SHA256

Sign with the authentication.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
The @adcp/sdk webhook emitter produces this signature when the push_notification_config declares HMAC-SHA256.

Creative-sync callbacks

We choose the scheme for each sync_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.supported to false or remove identity.brand_json_url, unless your origin has already signed with Web Bot Auth. Calls already sent keep their scheme.

Responses