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

# Compliance profile lifecycle errors — REQUIRED, NOT_APPROVED, LOCKED, IN_USE

> Diagnose the four compliance-profile errors (422 REQUIRED / NOT_APPROVED, 409 LOCKED / IN_USE) on attach, mutate, and delete, and pick the unblocked path for each.

# Compliance profile lifecycle errors

A **compliance profile** is the reusable KYC packet that every gated
surface — number purchases, Sender-ID registrations, brands, and
campaigns — draws from instead of re-asking for the same paperwork.
Four error codes guard that packet across its lifecycle: two block a
surface that references a profile, two block an operation on the
profile itself. This page maps each code to the state that raises it
and to the fix you can run yourself.

<Note>
  Compliance posture is tenant-owned: you create the profile, submit
  it, and decide what it references. Orbit enforces the lifecycle
  gates; the approval itself always comes from the carrier or
  regulator reviewing your packet.
</Note>

***

## The lifecycle state map

A profile moves through one fixed review lifecycle, with three
side-exits:

```
draft → pending_review → approved → expired
           │                 │
           ├─ rejected       └─ rejected
           └─ partially_rejected
```

* **draft** — freely editable. Nothing submits to a carrier until you
  submit the profile, so fields, documents, and metadata may change.
* **pending\_review** — submitted and awaiting carrier or regulator
  review. The payload freezes: downstream submissions carry a copy of
  what we sent, and edits to the live packet could fork it from what
  each carrier holds.
* **approved** — review cleared; the profile may open gated surfaces.
  Still frozen for mutation — once carriers act on the submitted
  packet, edits would fork our record from theirs.
* **locked (not a status — a guard)** — any mutation or submit attempt
  on a non-`draft` answers `409 COMPLIANCE_PROFILE_LOCKED` because the
  payload entered a downstream submission. Fix is clone-and-fix, below.
* **in use (a status-independent guard)** — any asset (number
  purchase, sender, brand, or campaign) still referencing the profile
  answers `409 COMPLIANCE_PROFILE_IN_USE` on delete or document-detach,
  because deletion would strand the downstream reference.
* **rejected / partially\_rejected** — the carrier refused the packet
  (or some of it). Editable again; `rejected` carries the notes to fix
  before re-submit.
* **expired** — the carrier's validity window lapsed. Treated like
  `rejected` for the gating surfaces; re-submit the profile to regain
  approval.

Only `draft`, `rejected`, and `partially_rejected` are editable;
everything else is locked against mutation by design.

The statuses gate surfaces in one direction only — a profile governs
what it may be attached *to*, but every surface's own gate (number
`pending_compliance`, sender `pending`) is documented on
[Troubleshoot a pending number or Sender ID](/compliance/troubleshooting-pending-gated-surfaces).

***

## Map your symptom to the failing operation

Before you read the individual codes, sort the failure by which call
you made:

| You tried to                                                                      | The gate you hit                                                  | Code                              |
| --------------------------------------------------------------------------------- | ----------------------------------------------------------------- | --------------------------------- |
| Attach a profile to a number / register a sender / start a brand / run a campaign | Missing a referencing **approved** profile on a regulated surface | `COMPLIANCE_PROFILE_REQUIRED`     |
| Same as above, but you passed a profile id                                        | Profile referenced is not `approved` yet                          | `COMPLIANCE_PROFILE_NOT_APPROVED` |
| Edit, add documents to, or submit a profile                                       | Profile left `draft` (or is `expired`/approved — mutation frozen) | `COMPLIANCE_PROFILE_LOCKED`       |
| Delete a profile, or detach one of its documents                                  | A downstream asset still references the profile                   | `COMPLIANCE_PROFILE_IN_USE`       |

***

## The four codes

### `COMPLIANCE_PROFILE_REQUIRED` — 422

**Where it fires.** A purchase or registration call on a surface that
requires a profile: a number purchase into a regulated country (UK,
DE, FR, and similar), a DIDWW DID-group placeholder row, a sender
registration, a brand or campaign registration that requires KYC.

**Why.** The surface checked your account for an **approved** profile
covering that use case and country and found none — either because no
profile exists yet, or because the existing ones are `draft`,
`pending_review`, `rejected`, or `expired`.

**Fix.** Two paths:

1. **You already have a suitable profile** — pass its id. For a
   number purchase, send `compliance_profile_id` on the purchase
   request; for a sender or brand registration, attach the profile
   from its console surface (Settings → Compliance → Sender IDs /
   Brand identity). Some surfaces pick up the only approved profile
   automatically; the explicit id is always safer.
2. **You do not** — create a profile (Settings → Compliance →
   Profiles, or `POST /api/v1/compliance/compliance-profiles`), fill
   its fields against the country's checklist (see
   [Country Compliance Requirements](/compliance/country-requirements)),
   submit it, and wait for `approved`. Only then re-run the blocked
   purchase.

### `COMPLIANCE_PROFILE_NOT_APPROVED` — 422

**Where it fires.** The same attach path as above, when the request
references a profile whose status is not `approved`.

**Why.** The gate reads the profile's status: `draft`,
`pending_review`, `rejected`, `partially_rejected`, or `expired` all
fail identical to a missing profile. A `pending_review` retry loop
does nothing but waste lead time.

**Fix.** Read the profile's status first (the Profiles list in the
dashboard, or `GET /api/v1/compliance/compliance-profiles/:id`).

* **pending\_review** — wait for the carrier's review to complete;
  attach succeeds the moment it flips to `approved`. See the lead
  times on
  [Troubleshoot a pending number or Sender ID](/compliance/troubleshooting-pending-gated-surfaces).
* **rejected / partially\_rejected** — read the reviewer notes on the
  Profiles page, fix what they flagged on the still-editable draft,
  and re-submit. A re-submit moves the profile back to
  `pending_review`; only an approved packet clears this gate.
* **expired** — treat as rejected: clone and re-submit (see LOCKED
  below for why clone is the path once a profile is frozen).

### `COMPLIANCE_PROFILE_LOCKED` — 409

**Where it fires.** Any attempt to mutate a profile that has moved
past `draft`: editing structured fields or metadata, updating the
use-case or country, attaching or replacing documents, or re-submit.

**Why.** Once a profile submits to providers, its payload freezes so
the copy carriers hold and the copy Orbit reads stay in sync — an edit
to a post-submit profile would fork those copies. `draft`,
`rejected`, and `partially_rejected` stay editable precisely because
nothing depends on them yet; everything else is locked by design.

**Fix.** Clone-and-fix:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/compliance-profiles/cprof_abc123/clone \
  -H "X-API-Key: dv_live_sk_..."
```

Clone copies the profile — name suffixed ` (copy)`, structured data,
and document attachments — into a new `draft` with a new id and no
provider submissions yet. Edit the clone, submit it, and re-attach it
to every downstream asset the old profile fed (with
`POST /api/v1/numbers/:id/attach-compliance-profile` for numbers, or
the sender-ID / brand surfaces' attach endpoints). This is also the
path for `expired` profiles once you need to re-verify them.

### `COMPLIANCE_PROFILE_IN_USE` — 409

**Where it fires.** `DELETE` on the profile, or a document-detach call
on one of its underlying documents, when any active downstream entity
still references the profile — a purchased number, a registered sender
ID, a brand, or a campaign.

**Why.** Deletion would strand the downstream asset without its KYC
backing, so the API refuses and names the conflict.

**Fix.** Detach downstream first, then retry the delete. Walk your
numbers, sender IDs, brands, and campaigns; for each asset referencing
the profile, either attach a different approved profile or retire the
asset. The conflict check runs server-side, so run the detach walk
from the console surfaces each asset exposes. Only when nothing
references the profile does the delete (or the document-detach)
succeed.

***

## When a non-approved profile is acceptable

Three lawful uses survive the NOT\_APPROVED gate:

1. **Draft-time assembly** — while you fill the profile against its
   country's checklist, nothing is blocked: `COMPLIANCE_PROFILE_REQUIRED`
   answers only the *surface* that wants an approved reference, not
   the profile itself.
2. **Attach by explicit `compliance_profile_id` with optimistic
   reference** — some surfaces accept a profile id and queue against
   `pending_compliance` until approval lands (see the pending-gated
   runbook for the numbers flow). Referencing a non-approved profile
   goes through as long as the surface supports queuing; the 422
   fires when the surface requires an approved profile *now*.
3. **Clone-and-fix cycles** — editing the clone and re-submitting
   replaces the old profile gradually; the old asset keeps serving
   traffic until you re-attach, so an asset mid-swap is not an approved
   profile failure.

Outside these lanes, only `approved` opens the gate.

***

## Retry class map

From [Error Codes](/reference/error-codes): each class permits a
different retry behaviour, so classify before you loop.

| Code                              | Class                                   | Retry?                                                                                                       |
| --------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `COMPLIANCE_PROFILE_REQUIRED`     | **Conditional (missing pre-send gate)** | Retry only after you attach a profile / create and approve one; otherwise identical.                         |
| `COMPLIANCE_PROFILE_NOT_APPROVED` | **Conditional (profile state)**         | Retry only once the referenced profile flips to `approved`; a `pending_review` retry is lead-time burn.      |
| `COMPLIANCE_PROFILE_LOCKED`       | **Deterministic (mutation path)**       | Never retry the mutation; clone, edit the clone, submit, re-attach — the change proceeds only on the new id. |
| `COMPLIANCE_PROFILE_IN_USE`       | **Conditional (downstream reference)**  | Retry the delete only after the detach walk clears every referencing asset.                                  |

None of the four is a transient fault, and none carries
`details.retry_after` — the 409-class conflicts are resolved by state,
not by waiting.

***

## Escalate with the full payload

If a profile-side error persists past the fix above, open a support
ticket carrying:

* The **profile id** (`cprof_…`), its current status, and the
  operation you attempted (attach / mutate / delete).
* The **error code and HTTP status** from the response envelope.
* The **referencing asset id** (`num_…`, sender id, brand id, or
  campaign id) for REQUIRED / NOT\_APPROVED / IN\_USE.
* The **`meta.request_id`** from the failed response — the durable
  handle support uses to pull the attempt directly.
* For LOCKED: the id of the clone you created and its own status.

With those five, the reviewer reads the profile's state, its
downstream references, and the exact request without a second
round-trip.

***

## Related references

* [Troubleshoot a pending number or Sender ID](/compliance/troubleshooting-pending-gated-surfaces) — the status vocabulary, pending-gated surfaces, and re-submission path this page plugs into.
* [Assemble your tenant's compliance posture](/guides/compliance-profiles-assemble) — how a profile composes with country rules and vertical packs, and the day-one activation order.
* [Country Compliance Requirements](/compliance/country-requirements) — the per-market checklist a profile grades against before any of this.
* [Error Codes](/reference/error-codes) — the attach-time retry-class table these four codes join.
* [Compliance profiles API](/api-reference/endpoints/compliance) — the endpoint surface, including the clone endpoint the LOCKED fix drives.
