Experimental. Brand rights lifecycle (
get_rights, acquire_rights, update_rights) is part of AdCP 3.0 as an experimental surface — it may change between 3.x releases with at least 6 weeks’ notice. Sellers implementing any of these tasks MUST declare brand.rights_lifecycle in experimental_features. See experimental status for the full contract.create_media_buy — select a pricing_option_id from get_rights and provide campaign details. The agent clears against existing contracts and returns terms, generation credentials, and disclosure requirements.
Schema
- Request:
acquire-rights-request.json - Response:
acquire-rights-response.json
Response time
Seconds to minutes foracquired or rejected. The pending_approval status means the rights holder needs to review — resolution may take hours to days.
Quick start
Parameters
Request
| Field | Type | Required | Description |
|---|---|---|---|
rights_id | string | Yes | Rights offering identifier from get_rights |
pricing_option_id | string | Yes | Selected pricing option |
buyer | brand-ref | Yes | Buyer’s brand identity |
campaign.description | string | Yes | How the rights will be used |
campaign.uses | string[] | Yes | Specific rights uses for this campaign |
campaign.countries | string[] | No | Countries where the campaign will run |
campaign.format_ids | format-id[] | No | Creative formats that will be produced |
campaign.estimated_impressions | integer | No | Estimated total impressions |
campaign.start_date | date | No | Campaign start date |
campaign.end_date | date | No | Campaign end date |
revocation_webhook | push-notification-config | Yes | Webhook for revocation notifications. If the rights holder needs to revoke rights, they POST a revocation-notification to this URL. |
idempotency_key | string | No | Client-generated key for safe retries. Resubmitting with the same key returns the original response. |
push_notification_config | push-notification-config | No | Webhook for async status updates if the acquisition requires approval. See push notifications. |
Response statuses
The response uses a discriminated union onstatus:
| Status | Description | Key fields |
|---|---|---|
acquired | Rights cleared, credentials issued | terms, generation_credentials, rights_constraint, disclosure |
pending_approval | Requires rights holder review | detail, estimated_response_time |
rejected | Request denied | reason, suggestions (optional) |
suggestions is present on a rejected response, the rejection is actionable — the buyer can adjust their request and retry. When suggestions is absent, the rejection is final and the buyer should not retry for this rights/talent combination. This convention applies consistently across acquire_rights rejections, get_rights excluded results, and creative approval rejections.
Request validation
Two campaign-field validations are normative foracquire_rights. Both produce INVALID_REQUEST with the offending field populated and recovery: "correctable" (the buyer can fix the request and retry).
Expired campaign window
Brand agents MUST reject withINVALID_REQUEST and field: "campaign.end_date" when campaign.end_date is in the past at the time of the request. Acquiring rights for a window that has already elapsed produces a zero-duration grant and is almost always a buyer-side bug — surfacing it deterministically is more useful than silently issuing credentials that immediately expire.
Unlike create_media_buy, which supports an any_of past-start auto-adjust pattern (a flight can be time-shifted forward without re-licensing), rights grants are not time-shiftable: the contract attaches to the requested period, so reject-only is the correct contract for acquire_rights.
Brand agents MAY also reject when campaign.start_date is more than the rights agent’s configured grace window in the past (typically the rights agent rejects start dates earlier than now - 24h since rights cannot be retroactively granted); that decision is contract-specific and SHOULD use field: "campaign.start_date". The end_date < now check is the normative floor.
CPM-priced rights under a governance plan
When the buyer’s request carries an intent-phasegovernance_context token on the protocol envelope (the buyer’s plan is governed — see Buyer-side governance invocation) and the selected pricing option has model: "cpm", campaign.estimated_impressions is the input the brand agent uses to project commitment against remaining plan budget. To make that projection deterministic across implementations:
- Brand agents MUST reject with
INVALID_REQUESTandfield: "campaign.estimated_impressions"when agovernance_contextis present, the selectedpricing_option.modelis"cpm", andcampaign.estimated_impressionsis either omitted or0. Implementer-chosen defaults (e.g., assuming 1M impressions) are non-conformant — they hide a policy decision inside each implementation and produce different governance outcomes for identical requests. - When
estimated_impressionsis provided and non-zero, the projected commitment is(pricing_option.price / 1000) × campaign.estimated_impressions, evaluated inpricing_option.currency. Ifpricing_option.currencydiffers from the governance plan’s budget currency (as carried on the plan), the brand agent MUST reject withINVALID_REQUESTandfield: "pricing_option_id"— currency conversion is not specified for governance projection, so currency-mismatched offers cannot be cleared against a governed plan. - If the projected commitment exceeds the buyer’s remaining plan budget, the agent MUST reject with
INVALID_REQUESTandfield: "campaign.estimated_impressions", populatingreasonwith the projected commitment and remaining budget so the buyer can adjust. - Non-CPM pricing options (
model: "flat_rate", etc.) commit the flat amount regardless of impression volume; brand agents MUST NOT requireestimated_impressionsfor governance projection on those options. Buyers MAY still provideestimated_impressionsfor cap-tracking purposes.
governance_context token are unaffected by this validation — estimated_impressions remains optional in that case (sellers MAY refuse to transact ungoverned plans as a matter of commercial policy, per Buyer-side governance invocation, but that refusal is independent of this projection rule).
Generation credentials
When rights are acquired, the agent coordinates with LLM providers to issue scoped credentials:- Agent clears the rights against existing contracts
- Agent tells the provider (e.g., Midjourney): “Issue a rights key for this talent, licensed to this buyer”
- Agent returns the credentials to the buyer
| Field | Type | Description |
|---|---|---|
provider | string | LLM/generation service (e.g., “midjourney”, “elevenlabs”) |
rights_key | string | Scoped API key for generating rights-cleared content |
uses | string[] | Rights uses this credential covers |
expires_at | datetime | When the credential expires (provider-determined) |
endpoint | uri | Provider endpoint for rights-scoped generation (optional, uses provider default if omitted) |
Rights constraint
Whenstatus is acquired, the response includes a rights_constraint object:
| Field | Type | Description |
|---|---|---|
rights_constraint | object | Pre-built constraint for creative manifests. Contains validity period, country restrictions, and impression cap from agreed terms. Embed directly in the manifest’s rights array. |
Creative lifecycle
After acquiring rights:- Generate: Creative agent uses
generation_credentialsto produce content - Manifest: Embed the
rights_constraintfrom theacquire_rightsresponse directly into the creative manifest’srightsarray. The rights agent pre-builds this constraint with the correct validity period, country restrictions, and impression cap from the agreed terms. - Approve: POST a
creative-approval-requestto theapproval_webhookURL, authenticating with the provided credentials. The response is acreative-approval-responsewith statusapproved,rejected, orpending_review. Ifpending_review, poll the returnedstatus_urlfor updates (suggested: every 5 minutes, back off to every 30 minutes after 1 hour). - Serve: Place approved creative via
create_media_buy, respecting country and date restrictions - Report: Use
report_usagewithrights_idfor cap tracking and billing
acquire_rights returns pending_approval and you provided push_notification_config, you’ll receive a webhook notification when the status changes to acquired or rejected. Otherwise, re-call acquire_rights with the same rights_id and idempotency_key after the estimated_response_time interval. Set approval_status: 'pending' on any creative manifests built during this period.
Revocation
If the rights holder needs to revoke rights (talent controversy, contract violation, etc.), they POST arevocation-notification to the buyer’s revocation_webhook, authenticating with the credentials provided at acquisition time. The notification contains an idempotency_key (required, used for deduplication across retries), rights_id, brand_id, reason, and effective_at timestamp.
The buyer is responsible for:
- Deduplicating by
idempotency_key— the same revocation may be delivered multiple times; see Push Notifications — Reliability for the canonical dedup contract - Stopping creative delivery by
effective_at - Removing or replacing affected creatives from active campaigns
- Ceasing use of generation credentials (providers may also invalidate credentials independently)
revoked_uses is present, only those uses are revoked (e.g., voice revoked but likeness remains).
Acknowledging revocations
Return HTTP200 immediately upon receiving and validating a revocation notification. The rights holder retries on non-2xx responses using exponential backoff (1s, 5s, 30s, 5m, 30m). After 6 failed attempts, the rights holder may escalate through other channels.
All webhook signing follows the AdCP push notification signing profile — RFC 9421 by default (rights agent signs with its adcp_use: "webhook-signing" key published at its brand.json agents[] entry), with the deprecated HMAC-SHA256 fallback available when the rights holder populates authentication.credentials on the webhook registration.
Impression caps and overage
Whenterms.impression_cap is set, it is a soft cap. Delivery is not automatically halted at the cap — the buyer is responsible for monitoring usage via report_usage and managing delivery accordingly. Impressions beyond the cap are billed at terms.overage_cpm. If the rights holder wants a hard cap (no delivery beyond the limit), they specify this in restrictions.
Usage reporting
Theusage_reporting_url in the acquired response is a convenience endpoint provided by the rights agent for HTTP-based impression reporting. It accepts the same payload as the report_usage MCP task. Use whichever integration is simpler for your pipeline — the MCP tool for agent-to-agent workflows, or the URL for direct HTTP calls from ad servers.
Renewal and updates
To extend a rights grant, adjust impression caps, change pricing, or pause/resume, useupdate_rights. Extended grants receive re-issued generation credentials and an updated rights_constraint for re-embedding in manifests.
Next steps
update_rights
Extend, adjust, or pause an existing rights grant.
report_usage
Report impressions against rights grants for billing and cap tracking.
brand.json spec
Rights constraints on creative manifests.