Skip to main content

Activation approval state errors

When your organization turns on activation approval (maker-checker), every audience activation needs a second person’s sign-off before any hashed identifier leaves the platform: your submit enqueues a pending approval request, an owner or admin decides it, and your re-submit consumes it. The ACTIVATION_APPROVAL_* codes below fire when the approval you present no longer matches a pending, matching, intact decision. None of them means the ad network refused anything; the run never dispatches.

The approval lifecycle first

  1. Request. POST /api/v1/cdp/audience/activate/:platform without an approval_id records a pending approval request instead of dispatching.
  2. Decide. A different person with owner or admin role calls POST /api/v1/cdp/audience/approvals/:id/decision with decision: "approve" | "reject".
  3. Consume. You re-submit the activation with the returned approval_id; the approval is single-use and turns consumed.
Four rules govern the whole lifecycle:
  • A decided approval stays decided. Once an approval is approved, rejected, or consumed, it can never be re-decided (ACTIVATION_APPROVAL_ALREADY_DECIDED), and a non-approved approval can never dispatch a run (ACTIVATION_APPROVAL_NOT_ACTIONABLE).
  • You cannot decide your own request. Segregation of duties: the person who asked for the activation must not be the person who signs it off. This applies to the requester even when they hold an owner or admin role.
  • The approval is bound to the exact batch it was minted for. The platform fingerprints the destination platform, audience, segment, operation, and member set at request time. If the membership drifts afterwards, the original decision is invalid for the new batch (ACTIVATION_APPROVAL_BATCH_CHANGED).
  • The approval is bound to the exact target. Platform, audience, segment, and operation must match at consume time (ACTIVATION_APPROVAL_MISMATCH).

Read the envelope first

Every one of these failures arrives as the standard error envelope:
Before doing anything else, copy meta.request_id, the approval id (apr_...), and the activation run id if one exists. Every code below is deterministic: backoff-retry never turns one into a success.

The six codes

ACTIVATION_APPROVAL_NOT_FOUND (404)

No approval row with that id exists in this organization: the id was mistyped, it belongs to a different organization, or the request rolled off the bounded approval queue. Re-enumerate the live queue with GET /api/v1/cdp/audience/approvals and copy the id from there. If the request genuinely no longer exists, mint a fresh one by re-submitting the activation without an approval_id. Anything else, for example the id appeared in the list a moment ago and now 404s, is an escalation: open a ticket with meta.request_id and the approval id.

ACTIVATION_APPROVAL_NOT_ACTIONABLE (409)

The approval exists but is not approved; the message names the current status. A consumed approval already dispatched its run and cannot be replayed: if the audience must go out again, mint a fresh approval request. A rejected one means an approver declined it: read the decision reason, fix what was flagged, and submit a new request rather than retrying the old id.

ACTIVATION_APPROVAL_ALREADY_DECIDED (409)

A decision was submitted for an approval that is no longer pending, usually two approvers racing on the same request. The first decision wins and stands. Re-read the approval from GET /api/v1/cdp/audience/approvals and act on the status it now carries.

ACTIVATION_APPROVAL_SELF_DECISION (403)

You are both the requester and the decider. Maker-checker exists so that a PII audience export always has two sets of eyes, so the control refuses the decision even when you hold an owner or admin role. Route the approval to a different owner or admin. If your organization has exactly one owner or admin, invite a second approver first; the check itself cannot be waived per request while the policy is on.

ACTIVATION_APPROVAL_BATCH_CHANGED (409)

The member batch you submitted differs from the one the approver signed off on: rows were added or removed since the approval was minted, typically because the segment recomputed or the audience was edited in between. The protective check rejects the dispatch on purpose; an approval must never cover a batch nobody reviewed. Re-issue the activation request with the current members so a fresh approval is minted for the batch you actually dispatch, then have it decided and consumed. Do not edit the activation or campaign in place expecting the check to pass, and do not re-send the old approval_id.

ACTIVATION_APPROVAL_MISMATCH (409)

The approval was granted for a different destination, segment, or operation than the run you are submitting, for example an approval minted for facebook / add presented to a google / remove run. Either re-enumerate approvals and present the one that matches this exact platform, audience, segment, and operation, or submit the run the approval names.

The operator move per code

What never to do

  • Do not replay the same approval id expecting success. Approvals are single-use and status-locked; a consumed or rejected id stays refused.
  • Do not edit the activation or campaign in place to “fix” a BATCH_CHANGED. The fingerprint compares your submitted batch against the approved one, so the protective check rejects the attempt; the only path is a fresh approval for the current batch.
  • Do not decide your own request from another session. The control keys on your user identity, not the session.
  • Do not retry with backoff. These are deterministic 404/403/409 responses, not transient failures.

Worked envelopes and escalation payload

The five refuses you will see in the wild, verbatim from the API:
When a code does not resolve with the moves above, open a ticket carrying the escalation payload: meta.request_id from the envelope, the approval id (apr_...), the activation run id from GET /api/v1/cdp/audience/activations when a run exists, plus the platform, segment, and operation of the run you attempted. That bundle is sufficient to reconstruct the decision chain on our side.