curl --request POST \
--url https://api.interchange.io/api/v2/storefront/creative-reviews/{creativeId}/decide \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{}'import requests
url = "https://api.interchange.io/api/v2/storefront/creative-reviews/{creativeId}/decide"
payload = {}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({})
};
fetch('https://api.interchange.io/api/v2/storefront/creative-reviews/{creativeId}/decide', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"id": "42",
"reviewRef": "review:42",
"storefrontId": "1234",
"creativeId": "cr_abc123",
"contentDigest": "<string>",
"sourceTrust": {
"classification": "platform_managed_media",
"evidence": {
"kind": "<string>",
"digest": "<string>",
"policyVersion": "creative-review-source-trust/v1"
},
"reviewVersionDigest": "<string>",
"inlineAssets": [
{
"kind": "image",
"url": "<string>"
}
],
"staticRepresentation": {
"kind": "text",
"value": "<string>"
}
},
"mediaBuyId": "<string>",
"buyerCustomerId": 0,
"submittedPayload": "<unknown>",
"previewContexts": [
{
"contextRef": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"buyerPackageId": "<string>",
"placement": {
"kind": "publisher",
"publisherDomain": "<string>",
"placementId": "<string>"
}
}
],
"interactivePreviewAvailable": true,
"status": "pending",
"reviewedBy": "<string>",
"reviewedAt": "2023-11-07T05:31:56Z",
"reviewerNotes": "<string>",
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"renderPreview": {
"url": "<string>",
"expiresAt": "2023-11-07T05:31:56Z"
},
"observation": {
"status": "queued",
"observedAt": "2023-11-07T05:31:56Z",
"record": {
"version": 1,
"outcome": "completed",
"startedAt": "2023-11-07T05:31:56Z",
"durationMs": 4503599627370495,
"viewport": {
"width": 4503599627370495,
"height": 4503599627370495
},
"domains": [
{
"domain": "<string>",
"requests": 4503599627370495,
"kinds": [
"script"
],
"firstParty": true
}
],
"pixels": 4503599627370495,
"redirects": [
{
"from": "<string>",
"to": "<string>"
}
],
"popups": [
{
"to": "<string>"
}
],
"navigationAttempts": 4503599627370495,
"consoleErrors": 4503599627370495,
"bytes": 4503599627370495,
"media": [
{
"kind": "vast",
"domain": "<string>"
}
],
"metering": "cdp",
"blockedRequests": 4503599627370495,
"failure": "<string>",
"screenshotDropped": "too_large"
}
},
"thumbnailUrl": "<string>"
}{
"data": null,
"error": {
"code": "<string>",
"message": "<string>",
"field": "<string>",
"details": {}
}
}{
"data": null,
"error": {
"code": "<string>",
"message": "<string>",
"field": "<string>",
"details": {}
}
}{
"data": null,
"error": {
"code": "<string>",
"message": "<string>",
"field": "<string>",
"details": {}
}
}{
"data": null,
"error": {
"code": "<string>",
"message": "<string>",
"field": "<string>",
"details": {}
}
}Record a decision on a pending creative review
Approve or reject one immutable pending review version. Use the reviewRef returned by the queue. A bare value always selects the legacy AdCP creative-id namespace, including when numeric; creative:<id> is the explicit equivalent. Only pending → approved or pending → rejected transitions are allowed; revoking an approved creative is a separate gesture. Approval wakes the separate delivery ledger and does not by itself report the creative live. Rejection can notify the buyer immediately; approval notifies only after delivery reaches a terminal outcome.
curl --request POST \
--url https://api.interchange.io/api/v2/storefront/creative-reviews/{creativeId}/decide \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{}'import requests
url = "https://api.interchange.io/api/v2/storefront/creative-reviews/{creativeId}/decide"
payload = {}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({})
};
fetch('https://api.interchange.io/api/v2/storefront/creative-reviews/{creativeId}/decide', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"id": "42",
"reviewRef": "review:42",
"storefrontId": "1234",
"creativeId": "cr_abc123",
"contentDigest": "<string>",
"sourceTrust": {
"classification": "platform_managed_media",
"evidence": {
"kind": "<string>",
"digest": "<string>",
"policyVersion": "creative-review-source-trust/v1"
},
"reviewVersionDigest": "<string>",
"inlineAssets": [
{
"kind": "image",
"url": "<string>"
}
],
"staticRepresentation": {
"kind": "text",
"value": "<string>"
}
},
"mediaBuyId": "<string>",
"buyerCustomerId": 0,
"submittedPayload": "<unknown>",
"previewContexts": [
{
"contextRef": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"buyerPackageId": "<string>",
"placement": {
"kind": "publisher",
"publisherDomain": "<string>",
"placementId": "<string>"
}
}
],
"interactivePreviewAvailable": true,
"status": "pending",
"reviewedBy": "<string>",
"reviewedAt": "2023-11-07T05:31:56Z",
"reviewerNotes": "<string>",
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"renderPreview": {
"url": "<string>",
"expiresAt": "2023-11-07T05:31:56Z"
},
"observation": {
"status": "queued",
"observedAt": "2023-11-07T05:31:56Z",
"record": {
"version": 1,
"outcome": "completed",
"startedAt": "2023-11-07T05:31:56Z",
"durationMs": 4503599627370495,
"viewport": {
"width": 4503599627370495,
"height": 4503599627370495
},
"domains": [
{
"domain": "<string>",
"requests": 4503599627370495,
"kinds": [
"script"
],
"firstParty": true
}
],
"pixels": 4503599627370495,
"redirects": [
{
"from": "<string>",
"to": "<string>"
}
],
"popups": [
{
"to": "<string>"
}
],
"navigationAttempts": 4503599627370495,
"consoleErrors": 4503599627370495,
"bytes": 4503599627370495,
"media": [
{
"kind": "vast",
"domain": "<string>"
}
],
"metering": "cdp",
"blockedRequests": 4503599627370495,
"failure": "<string>",
"screenshotDropped": "too_large"
}
},
"thumbnailUrl": "<string>"
}{
"data": null,
"error": {
"code": "<string>",
"message": "<string>",
"field": "<string>",
"details": {}
}
}{
"data": null,
"error": {
"code": "<string>",
"message": "<string>",
"field": "<string>",
"details": {}
}
}{
"data": null,
"error": {
"code": "<string>",
"message": "<string>",
"field": "<string>",
"details": {}
}
}{
"data": null,
"error": {
"code": "<string>",
"message": "<string>",
"field": "<string>",
"details": {}
}
}Authorizations
API key or access token
Path Parameters
Creative review identifier. Use the reviewRef value returned by the queue to select one immutable review. A bare value always selects the AdCP creative-id namespace, including when numeric; creative:<id> is the explicit equivalent.
1"review:42"
Body
Request body for the operator decide endpoint. Records a terminal decision only when the pending creative and its frozen work item still match; revised content additionally requires expected_content_digest.
Decision to record. Must be approved or rejected — revoked is a separate gesture and is not allowed here.
approved, rejected SHA-256 contentDigest from the exact review version shown to the operator. Rolling-upgrade clients may omit it only while the review content has never advanced; revised content requires this field and otherwise returns a conflict.
^[a-f0-9]{64}$"0db36cf6c4bfb43123aee1c3eaf5ee965e1c34c9df606b02a56c72a226ad097a"
Opaque immutable review-version identity returned with the review. It binds source-trust evidence to the submitted content; clients should send it when available.
^[a-f0-9]{64}$Optional free-text note from the reviewer (e.g. reason for rejection). Visible to the buyer in their sync_creatives follow-up.
2000Response
Record a decision on a pending creative review
A single creative review queue row — one buyer-submitted creative awaiting (or having received) an operator decision.
Legacy surrogate review row id (BIGINT serialized as a string). Preserved for response compatibility; prefer reviewRef for follow-up actions.
^[1-9]\d*$"42"
Collision-free opaque review reference. Pass this exact value to get, evaluate, or decide this review.
^review:[1-9]\d*$"review:42"
Storefront the submission was made against.
"1234"
AdCP creative id as submitted by the buyer.
"cr_abc123"
Immutable SHA-256 identity of the exact creative object forwarded downstream. Request-level account and correlation fields are excluded.
^[a-f0-9]{64}$Receipt-bound source classification and review concurrency identity when observed. Null means provenance was not observed or cannot be proven; clients must fail closed and never use this projection to load network resources.
Show child attributes
Show child attributes
AdCP media_buy_id this creative was associated with at submit time, if any. Null when the buyer attaches creatives independently of a buy.
customer_id of the buyer that submitted the creative — the tenancy boundary on buyer-side reads.
-9007199254740991 <= x <= 9007199254740991Credential-stripped snapshot of the buyer submission used for review and delivery. It contains the creative fields and may also contain request-level account, buyer_ref, and context used for downstream account selection and callback correlation. Only push_notification_config and pushNotificationConfig are removed from this operator-facing response and stored separately.
Current exact preview targets. Empty for legacy, standalone, defaulted, ambiguous, stale, or superseded routes.
Show child attributes
Show child attributes
Server-issued availability for the explicit third-party interactive-preview request. False disables that action only; source inspection and approval decisions remain available.
Lifecycle state of a buyer-submitted creative awaiting storefront review. pending until an operator decides; approved or rejected after a decision; revoked if an operator pulls a previously-approved creative.
pending, approved, rejected, revoked User id of the operator who decided this review (BIGINT serialized as string). Null while pending.
Decision timestamp (ISO 8601). Null while pending.
^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$Free-text reviewer note attached at decide time. Null when the operator did not supply one.
Submission timestamp (ISO 8601).
^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$Last-modified timestamp (ISO 8601). Equal to created_at while pending; bumped when the row transitions to a decided state.
^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$Live sandboxed preview of the submitted creative, when the render origin is enabled for this environment and the seller. Null or absent means only source inspection is available.
Show child attributes
Show child attributes
What this exact creative version did when Interchange ran it once, headlessly, on the render origin (domains contacted, pixel-shaped requests, redirects, popups, navigation attempts, bytes). Null or absent means it has not been observed; status says whether a run is queued, running, or ended without a result. Evidence from one run, never a safety verdict.
Show child attributes
Show child attributes
App-relative, authenticated path to a PNG of the creative frame from the observation run, e.g. /api/v2/storefront/creative-reviews/review:42/thumbnail. Null or absent when no screenshot exists. Never a public URL.