> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Activation approval state errors

> Decode and resolve the ACTIVATION_APPROVAL_* maker-checker errors on audience activations: NOT_FOUND, NOT_ACTIONABLE, ALREADY_DECIDED, SELF_DECISION, BATCH_CHANGED, and MISMATCH.

# 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:

```json theme={null}
{
  "error": {
    "code": "ACTIVATION_APPROVAL_BATCH_CHANGED",
    "message": "The submitted audience differs from the batch that was approved. Request a new approval for the current audience.",
    "status": 409
  },
  "meta": {
    "request_id": "req_01J8Z9K3P4Q5R6S7T8U9V0W1X2",
    "timestamp": "2026-08-20T12:10:00.000Z"
  }
}
```

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

| Code | HTTP | Your move |
| - | - | - |
| `ACTIVATION_APPROVAL_NOT_FOUND` | 404 | Re-enumerate with `GET /api/v1/cdp/audience/approvals`; if absent, mint a fresh request by submitting without `approval_id`. |
| `ACTIVATION_APPROVAL_NOT_ACTIONABLE` | 409 | Consumed: mint a fresh approval. Rejected: read the decision reason, fix, and submit a new request. |
| `ACTIVATION_APPROVAL_ALREADY_DECIDED` | 409 | Re-read the approval; the first decision stands. Act on its current status. |
| `ACTIVATION_APPROVAL_SELF_DECISION` | 403 | Route the decision to a different owner or admin. |
| `ACTIVATION_APPROVAL_BATCH_CHANGED` | 409 | Re-issue the activation request for the current membership; get it approved; consume the new approval. |
| `ACTIVATION_APPROVAL_MISMATCH` | 409 | Pair the run with the approval that matches its platform, audience, segment, and operation. |

## 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:

```json theme={null}
{ "error": { "code": "ACTIVATION_APPROVAL_NOT_FOUND", "message": "No activation approval with that id (it may have rolled off the bounded queue).", "status": 404 }, "meta": { "request_id": "req_01J8Z9K3P4Q5R6S7T8U9V0W1X2", "timestamp": "2026-08-20T12:10:00.000Z" } }
```

```json theme={null}
{ "error": { "code": "ACTIVATION_APPROVAL_NOT_ACTIONABLE", "message": "This approval is 'consumed', not 'approved' — request a fresh approval before activating.", "status": 409 }, "meta": { "request_id": "req_01J8Z9K3P4Q5R6S7T8U9V0W1X2", "timestamp": "2026-08-20T12:10:00.000Z" } }
```

```json theme={null}
{ "error": { "code": "ACTIVATION_APPROVAL_SELF_DECISION", "message": "Maker-checker: you cannot approve or reject your own activation request — a second person must sign off.", "status": 403 }, "meta": { "request_id": "req_01J8Z9K3P4Q5R6S7T8U9V0W1X2", "timestamp": "2026-08-20T12:10:00.000Z" } }
```

```json theme={null}
{ "error": { "code": "ACTIVATION_APPROVAL_BATCH_CHANGED", "message": "The submitted audience differs from the batch that was approved. Request a new approval for the current audience.", "status": 409 }, "meta": { "request_id": "req_01J8Z9K3P4Q5R6S7T8U9V0W1X2", "timestamp": "2026-08-20T12:10:00.000Z" } }
```

```json theme={null}
{ "error": { "code": "ACTIVATION_APPROVAL_MISMATCH", "message": "This approval was granted for a different destination, segment, or operation.", "status": 409 }, "meta": { "request_id": "req_01J8Z9K3P4Q5R6S7T8U9V0W1X2", "timestamp": "2026-08-20T12:10:00.000Z" } }
```

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.

## Related

* [Campaign and conference state-machine transition errors](/troubleshooting/campaign-conference-state-machine)
  for the overlapping 409 family on campaign launches and approvals.
* [Audience activation pipeline](/guides/audience-activation-pipeline) for
  the maker-checker flow end to end, including the preflight override
  interplay.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.