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

# Troubleshooting: RCS BRAND_NOT_APPROVED (409)

> Your RCS bot submit or carrier verification came back 409 BRAND_NOT_APPROVED because the brand it points at is under a platform hold (rejected or suspended). Read details.brand_status, correct the brand record, and resubmit the brand — never re-fire the same bot payload.

# Troubleshooting: RCS BRAND\_NOT\_APPROVED (409)

Your RCS request failed with HTTP **409** and the error code
`BRAND_NOT_APPROVED`. Bots can only register under a brand that is not under
a carrier-platform hold, so any request that names a `rejected` or
`suspended` brand stops at this gate. The response is not a bug — it is the
one thing standing between your bot and a brand the reviewer refused.

<Note>
  Approval, refusal, and takedown decisions belong to the review workflow —
  Devotel operations plus Dotgo, the RCS carrier-directory partner. Approval
  is a manual workflow by design: someone reviews the brand before a bot can
  go live, and a refusal lands as this 409 rather than as a failed send
  downstream. Do not program around it; fix the brand.
</Note>

## What brand approval is

Every RCS bot (the agent subscribers see in their messaging app) links to a
**brand** — the verified business entity carriers screen before they let an
agent launch. Brand registration is a **manual review workflow**:

1. You create the brand (`POST /api/v1/rcs/brands`) with its identity and
   KYC fields and submit it (`POST /api/v1/rcs/brands/:id/submit`).
2. The brand enters the review queue and moves to `pending_review`.
   Devotel operations and Dotgo review the record — the 409 you are reading
   about exists precisely so that a refused brand cannot slip a bot past the
   directory. Because the review is human, lead times here are expectations,
   not guarantees.
3. A reviewer decision lands as one of the statuses below. The brand
   record's `status` field and, when a submit was refused,
   `rejection_reason` tell you which.

A bot submit names a brand id, and the server checks that brand before it
forwards anything upstream. Only two statuses are a hard stop:

* **`rejected`** — Devotel ops refused the brand, or Dotgo's own screening
  refused it and the verdict was mirrored down. This is a refused-for-cause
  state, not a queue position.
* **`suspended`** — a platform takedown: the brand was live and was pulled.
  Treat it as a hold on all new bots under that brand until reinstated.

Every other status — `draft`, `pending_review`, `submitted_to_dotgo`,
`approved` — **passes** the gate. A brand still in review does **not** 409;
Dotgo runs its own screening when the bot is submitted alongside the brand,
so a brand-new tenant reaching RCS onboarding is never blocked by a gate
whose verdict a human has not even written yet. The [RCS onboarding guide](/guides/rcs-onboarding)
covers the full create → submit → verify → launch ordering; this page picks
up at "onboarding stopped on a 409."

## Where the 409 surfaces

Three RCS calls run the same brand-not-held precondition before they do any
work, and each returns the same `BRAND_NOT_APPROVED` body:

| Endpoint | Why it checks |
| - | - |
| `POST /api/v1/rcs/bots` — create a bot | The bot points at a brand id up front; a held brand stops the create before the directory call. |
| `PUT /api/v1/rcs/bots` — update a bot's creation data | Brand-redirection edits re-run the same precondition so a bot cannot hop onto a held brand. |
| `POST /api/v1/rcs/bots/:id/verify` — submit for carrier verification | Ops can refuse a brand *after* a bot was created; the verification submit re-checks so the held brand does not reach the carrier. |

**Response shape (all three):**

```json theme={null}
{
  "error": {
    "code": "BRAND_NOT_APPROVED",
    "message": "Brand 'Acme Retail' is in status 'rejected' — bots can only be submitted under a brand that is not under a platform hold",
    "status": 409,
    "details": {
      "brand_id": "brand_9xk2cq",
      "brand_status": "rejected"
    }
  }
}
```

The `PUT /api/v1/rcs/bots` update path ships an update-brand trigger on the
same precondition — an edit that re-points a bot at a held brand 409s the
same way a create would, so a `409` on update is not a separate bug class.

### Read `details.brand_status`

Every `BRAND_NOT_APPROVED` body carries the two facts needed to act,
without a second API call:

* **`details.brand_id`** — which brand is blocking. Keep it for the resubmit
  loop and for a support ticket.
* **`details.brand_status`** — what to do next:
  * `waiting for review` (`draft` / `pending_review` / `submitted_to_dotgo`)
    → **no fix is needed.** The brand is still moving through review and the
    bot gate already passed — re-read the symptom; something later in the
    flow failed, not the brand gate.
  * `rejected` → the brand was refused-for-cause. Fix the record and
    resubmit (below).
  * `suspended` → platform takedown. Fix the record and resubmit; treat a
    takedown as higher-severity than a refusal and reach out if the reason
    is not self-evident.

## The resubmit loop — correct the brand, then resubmit

A refused or suspended brand is **editable** precisely so you can correct
what the reviewer called out. `draft` and `rejected` are the only two
statuses that accept edits, so the loop is short and intentional:

1. **Read the verdict.** `GET /api/v1/rcs/brands/:id` returns the full
   record. On a refusal the reviewer-populated `rejection_reason` names the
   item to fix — a thin contact block, a missing legal entity, a mismatched
   website. Read it literally.
2. **Edit the brand.** `PATCH /api/v1/rcs/brands/:id` accepts the corrected
   fields (every field is optional; send only the ones you are changing).
   Complete the KYC block — contact name, contact email or phone, postal
   address — and complete `tax_id` and `legal_entity_name` when you have
   them; thin forms are the normal refusal class. The
   [RCS brand verification KYC walkthrough](/guides/rcs-brand-verification-kyc)
   maps which documents a country's carriers expect.
3. **Resubmit the brand.** Call `POST /api/v1/rcs/brands/:id/submit` again.
   A `rejected` brand re-enters review with the corrected record; a
   `suspended` brand moves back into review for a takedown appeal.
4. **Retry the bot call.** Once the brand clears review, re-send the bot
   submit / update / verify that 409'd.

<Warning>
  **Do not re-fire the same bot payload against a held brand.** The 409 is
  the gate doing its job; an unchanged bot body only earns the same
  refusal, faster, and re-queues nothing. The thing to resubmit is the
  **brand**, not the bot.
</Warning>

<Note>
  A `rejected` brand that you decide not to fix can be deleted
  (`DELETE /api/v1/rcs/brands/:id`) only while it sits in `draft` or
  `rejected`. Bots linked to that brand stay in place and unlinked; re-link
  them to a held-free brand before you resubmit them.
</Note>

## What not to do

* **Do not treat `waiting for review` as a yes.** A brand still in review
  passes the gate, so Dotgo's screening gets to run — but a refusal there is
  the same `BRAND_NOT_APPROVED` once the verdict lands as `rejected`.
* **Do not route around the gate by re-creating the brand.** A second brand
  with the same refused records earns the same refusal on its single shared
  review path; edit the existing `rejected` brand instead. Deleting and
  re-creating also strands the bot rows linked to the old brand id.
* **Do not poll the bot call for a flip.** The gate responds to the brand
  record, so the poll belongs on `GET /api/v1/rcs/brands/:id` `status`, not
  on the bot endpoint.

## When to escalate

Escalate to [support@devotel.io](mailto:support@devotel.io) when the
reviewer's `rejection_reason` does not map to anything you can correct, when
a `suspended` brand needs a takedown appeal, or when the same correction has
been refused twice. Include:

1. Your **tenant ID** (dashboard → Settings → Organization, or
   `organizationId` on `GET /api/v1/me`).
2. The **`details.brand_id`** from the 409 body.
3. The verbatim **`details.brand_status`** value and, when present, the
   brand's `rejection_reason`.

## See also

* [RCS onboarding guide](/guides/rcs-onboarding) — the full brand → bot →
  verify → launch lifecycle with the field-by-field form walkthrough
* [RCS brand verification KYC walkthrough](/guides/rcs-brand-verification-kyc) —
  the country-by-country document map for what a carrier review asks for
* [RCS API reference](/api-reference/rcs) — the brand and bot endpoint
  surface this page's calls run against
* [Troubleshooting: RCS undelivered](/troubleshooting/rcs-undelivered) — the
  send-side page; once the brand clears review, message-level failures move
  to that page


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