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

# RCS brand walkthrough: create to first send

> Follow one RCS brand through its full lifecycle — create it, submit it for carrier review, launch the agent, publish the first template, and send the first RCS message with SMS fallback and status callbacks wired in.

# RCS Brand Walkthrough: Create to First Send

The [RCS onboarding guide](/guides/rcs-onboarding) documents every gate in the brand-to-launch registry: brand capture, agent creation, verification, per-carrier launch. This walkthrough runs one brand through the whole tree — from `POST /api/v1/rcs/brands` to a delivered rich card — so the parity gap with the [WhatsApp getting-started guide](/guides/whatsapp/getting-started) closes on the brand path too. Use the API walkthroughs when you script; the console equivalents are named inline.

## 1. Why RCS needs a brand first

SMS sends start as soon as a number is live. RCS does not: every send goes out under a **verified business agent**, and carriers only launch an agent after they have reviewed the registered business behind it. Know-your-business screening lives on the *brand record* — name, website, industry, a contact person, and the postal address — so the first gate is a full brand payload, not just a sender id. Fill every field the first time: a rejected field restarts the review clock in days, not minutes.

## 2. Create the brand

**Console.** Open **Messages → RCS → Brands**, click **Create brand**, and complete the form — the field map one-to-one onto the create call. Save creates the draft and submits it in one step. The console path is covered end to end in the [RCS brands console guide](/guides/rcs-brands-console).

**API.** One payload carries the identity carriers review:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/rcs/brands \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "brand_name": "Acme Retail",
    "brand_website": "https://acmeretail.com",
    "brand_logo_url": "https://acmeretail.com/assets/logo.png",
    "industry_vertical": "Retail",
    "contact_first_name": "Ada",
    "contact_last_name": "Wong",
    "contact_email": "ada.wong@acmeretail.com",
    "contact_phone": "+14155552671",
    "address_line_1": "100 Market Street",
    "city": "San Francisco",
    "state_province": "CA",
    "country": "US",
    "postal_code": "94103",
    "tax_id": "94-1234567",
    "legal_entity_name": "Acme Retail Inc."
  }'
```

The response returns `201` with the brand in `draft` and the id (`br_…`) every later call references. Submit it with `POST /api/v1/rcs/brands/:id/submit` — submission is the gate to create the agent on it. Send `tax_id` and `legal_entity_name` even though the API marks them optional: carriers in markets like India and Brazil ask for them before approving an agent.

## 3. Verification and launch

Per-brand state machine, with the signal to poll at each step:

| Step         | Endpoint                         | Ends when                                                                                 |
| ------------ | -------------------------------- | ----------------------------------------------------------------------------------------- |
| Brand        | `POST /rcs/brands/:id/submit`    | Status is `pending_review` (any status but `rejected`/`suspended` already backs an agent) |
| Agent        | `POST /rcs/bots` with `brand_id` | Bot record exists (draft)                                                                 |
| Verification | `POST /rcs/bots/:id/verify`      | `GET /rcs/bots/:id/quality` shows `verification_status: verified`                         |
| Launch       | `POST /rcs/bots/:id/launch`      | `carrier_statuses` shows `launched` on at least one carrier                               |

The verification call is `multipart/form-data`: conversation screenshots under `screenImages[]` (up to 10), KYC documents under `kycdocs[]` (up to 5, one `document_type` label per file), and an optional `brandLogoImage`. India and Brazil ask for KYC proof at brand registration; a US-only brand may need nothing beyond the field block. The document choices and the reusable `rcs_brand_verification` compliance profile are the [RCS brand verification KYC guide](/guides/rcs-brand-verification-kyc).

Launch is per carrier: the bot is sendable once `carriers_launched ≥ 1`, so compare the launched set against where your audience sits before you scale traffic.

## 4. Publish the first template

For campaigns and flows, author the definition as a stored template, not an inline payload — approval applies to the named template. **Templates → New Template** in the console (or the Rich Card Studio) does this visually; the API takes the same definition:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/rcs/bots/bot_4kqzx1/templates \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "rich_template_data": {
      "name": "order-update",
      "title": "Your order has shipped",
      "body": "Track your package — expected delivery {{delivery_date}}.",
      "actions": [
        {
          "type": "open_url",
          "label": "Track it",
          "fallbackUrl": "https://acmeretail.com/track/{{order_id}}"
        }
      ]
    }
  }'
```

The template lands as **Pending review** and flips to **Approved** on the carrier's verdict; a rejected one carries its `rejection_reason` inline. Two discipline rules: `PUT` on a template replaces the whole definition and resets approval, so land edits between campaign launches; and an inline rich card in a send is fine for one-off traffic, but anything a campaign sends repeatedly belongs in an approved template. Lifecycle sequencing lives in the [RCS Templates tab guide](/guides/rcs-templates-tab).

## 5. First send, with SMS fallback

Once the bot shows `launched` on at least one carrier and the template is `Approved`, send rich cards directly:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/messages/rcs \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+14155552671",
    "rich_card": {
      "card_content": {
        "title": "Your order has shipped",
        "description": "Track your package — expected delivery Friday.",
        "media": {
          "height": "MEDIUM",
          "content_info": { "file_url": "https://acmeretail.com/assets/order-card.jpg" }
        }
      },
      "suggestions": [
        { "action": { "text": "Track it", "open_url": { "url": "https://acmeretail.com/track/12345" } } },
        { "reply": { "text": "Need help", "postback_data": "order_help" } }
      ]
    }
  }'
```

The response carries a message id and an initial status. A plain-text send uses `body` instead of `rich_card`; a carousel of 2–10 cards uses `rich_card_carousel`. A single-card carousel renders as malformed — use `rich_card` for one card.

**Fallback toggle.** RCS → SMS fallback is org-level: open **Settings → Channels → Cross-Channel Fallback** and save a rule with **Primary: RCS, Fallback: SMS**. Once saved, every send that hits a non-capable handset, an unlaunched carrier, or an exhausted provider retries over SMS automatically — including a TCPA opt-out re-check before the SMS leg goes out. The `/messages/rcs` body accepts no per-request `fallback` field; keeping the chain on the organization makes it hold across the API, campaigns, flows, and inbox replies.

## 6. Status callbacks

Wire the delivery lifecycle through [webhook events](/webhooks/events) rather than polling the send response:

| Event               | Meaning                                                                       |
| ------------------- | ----------------------------------------------------------------------------- |
| `message.sent`      | Orbit accepted the message and handed it to the carrier path                  |
| `message.delivered` | The handset confirmed receipt                                                 |
| `message.read`      | The recipient opened it (RCS read receipts)                                   |
| `message.failed`    | Terminal failure — the fallback chain is exhausted or the send was suppressed |

RCS sends emit the same envelope as every other channel, so one handler covers the mix. Read receipts are the RCS win over SMS: `message.read` shows a card earned attention, which the per-template counters (Sent / Delivered / Read / Taps in the Templates tab) aggregate.

## 7. Common rejections

A brand or template rejection is not a dead end — the verdict carries a `rejection_reason`, and re-submitting after a fix is safe. The patterns that recur:

* **Trademark / brand-name mismatch.** The brand name on the form does not match the website or the legal entity. Align the display name with public registration and re-submit.
* **Evidence mismatch.** The KYC document names a different entity than the brand fields, or a required document is missing or unlabeled. Attach the matching proof (or a compliance profile for repeat filings) and re-submit.
* **Thin brand form.** Contact person, address, or legal fields blank. Carriers reject thin forms; fill every field the first time.
* **Link issues on templates.** A malformed or non-HTTPS URL pair on a template action. Fix the URL and re-submit — approval resets on every edit.

## Related

* [RCS onboarding](/guides/rcs-onboarding) — the ordered path through every gate, plus tester devices, capability checks, and reach sizing.
* [RCS brands console](/guides/rcs-brands-console) — the dashboard equivalents of each call above.
* [RCS Templates tab](/guides/rcs-templates-tab) — approval lifecycle and per-template deliverability.
* [RCS brand verification KYC](/guides/rcs-brand-verification-kyc) — document choices and the reusable compliance profile.
* [RCS channel page](/channels/rcs) — message shapes and the REST contract the walkthrough references.
