---
title: "Add an RCS agent"
method: POST
path: "/v3/channels/rcs"
tags: ["Channels"]
---

# Add an RCS agent

`POST /v3/channels/rcs`

## Request

- Base URL: `https://api.sent.dm`
- URL: `https://api.sent.dm/v3/channels/rcs`
- Auth: one of:
  - API key in header `x-api-key`
  - HTTP bearer

Asks for an RCS agent and records the order form the carriers vet it against. Always `202`: an agent is approved by the carriers, not by this call, and nothing here can make that happen sooner.

## What it asks for

The RCS Agent Order Form — the same one our team fills in on your behalf today, so nothing has to be collected from you twice. **All fields are required** and must be submitted together so the carrier review has everything it needs. The only exception is `opt_in_screenshot_url`.

**Agent identity:** `display_name`, `description`, `agent_use_case` (must be one of the accepted use cases; the error names the set), `brand_color` (six-digit hex, `#RRGGBB`).

**Brand identity:** `brand_name` — the brand this agent presents. Not taken from `compliance.brand`: a business may present a different brand on RCS than the one its 10DLC registration is filed against, and the carriers vet this one. `privacy_policy_url`, `terms_and_conditions_url`, `website_url`, `logo_url`, and `banner_url` must be absolute `http(s)` URLs that the carriers can fetch without authentication. The form specifies 224×224 px and 50 KB for the logo and 1440×448 px and 200 KB for the banner; these cannot be checked without the image bytes.

**Contact details:** `brand_phone_number`, `customer_support_phone_number`, `brand_email`, `customer_support_email`, `contact_name_and_title`.

**Company:** `company_ein`, `entity_type`, `official_address` (street, city, state, postal_code, country), `brief_company_description`.

**Consent and messages:** `opt_in_process_description`, `start_message`, `help_message`, `stop_message`, `sample_messages` (at least one example message).

**Optional:** `opt_in_screenshot_url` (validated as an http(s) URL if supplied).

Anything supplied is checked against accepted values rather than passed through: a value the provider rejects would otherwise surface days later, to somebody who cannot fix it without asking you.

**A customer has one agent.** Asking again while you have one is `409`.

## What comes back, and what does not

Returns **the agent** — the form as stored, plus `id` and `status`. Not your other channels, which this call cannot have changed.

`status` is `PROVISIONING` until the agent is handed to the carriers and approved. **`GET /v3/channels` reports `rcs: null` until then** — a channel row is what routing reads to decide you are sendable, and writing one for an unapproved agent would claim a channel that cannot carry traffic.

Send `x-profile-id` with an organization key to ask for one of your profiles' agents.

## Headers

- `Idempotency-Key` string
- `x-profile-id` string, uuid

## Request body

- SentDmServicesEndpointsCustomerAPIv3ChannelsRequestsAddRcsChannelRequest: The RCS Agent Order Form, as a customer sends it. The same form the admin side takes — POST /customers/{customerId}/rcs-senders and CreateRcsSenderRequest — rather than a reduced one. It was three fields for a while, which recorded a hosting region and a logo into a config blob and left everything a carrier actually asks about to be collected by hand later. A customer can answer all of this; nobody else can answer any of it. Named in this API's own casing. Every v3 body is snake_case, so the fields are mapped rather than shared: logo_url, banner_url, brand_color. No customer_id. The internal form carries one because an admin names the customer it is acting for; here the key does, and accepting one from the body would let a caller file an agent against somebody else. All fields except opt_in_screenshot_url are required. The full order form must be submitted in one go so the carrier review has everything it needs.
  - `sandbox` boolean: Sandbox flag - when true, the operation is simulated without side effects Useful for testing integrations without actual execution
  - `display_name` string, required: The name the agent shows in the messaging client.
  - `description` string, required: What the agent is for, shown to recipients. Capped by the carriers, not by us.
  - `agent_use_case` 'VERIFICATION' | 'NOTIFICATIONS' | 'MARKETING' | 'MULTI_USE', required: Which kind of traffic the agent carries. One of the accepted use cases; the error names the set.
  - `brand_name` string, required: The brand this agent presents over RCS. Not taken from your compliance.brand: a business may present a different brand on RCS than the one its 10DLC registration is filed against, and the carriers vet this one.
  - `privacy_policy_url` string, uri, required: Required by US carriers. Must be an absolute http(s) URL they can fetch.
  - `terms_and_conditions_url` string, uri, required
  - `website_url` string, uri, required: The brand's own site.
  - `brand_color` string, required: Primary brand colour, as #RRGGBB. Three-digit shorthand is refused: the value is submitted verbatim, so two spellings of one colour is only a way for the stored value to disagree with the form.
  - `logo_url` string, uri, required: Publicly reachable logo. It has to be fetchable without authentication at review time, so a URL behind a login passes this call and fails the review.
  - `banner_url` string, uri, required
  - `brand_phone_number` string, required: The brand's own number. Also becomes the agent's canonical sending number for routing, which is why it is normalised to E.164 rather than stored as sent.
  - `customer_support_phone_number` string, required
  - `brand_email` string, email, required
  - `customer_support_email` string, email, required
  - `contact_name_and_title` string, required
  - `company_ein` string, required
  - `entity_type` string, required
  - `official_address` SentDmServicesCommonChannelsContractsRcsAddress, required: The registered address of the company behind the agent.
    - `street` string, nullable
    - `city` string, nullable
    - `state` string, nullable
    - `postal_code` string, nullable
    - `country` string, nullable
  - `brief_company_description` string, required
  - `opt_in_process_description` string, required: How recipients opt in, in prose. The carriers read this one.
  - `opt_in_screenshot_url` string, uri, nullable: A screenshot of the opt-in, as a publicly fetchable URL.
  - `start_message` string, required
  - `help_message` string, required
  - `stop_message` string, required
  - `sample_messages` string[], required: Examples of what the agent will send, for the review.

## Response `202`

The agent is recorded with status PROVISIONING, awaiting carrier approval

- SentDmServicesEndpointsCustomerAPIv3SharedApiResponseOfRcsAgentState: Standard API response envelope for all v3 endpoints
  - `success` boolean: Indicates whether the request was successful
  - `data` SentDmServicesCommonChannelsContractsRcsAgentState: An RCS agent as its owner sees it: the order form back, plus where the submission stands. Not RcsSenderResponse. That one is the admin projection and carries the pipeline we track about a customer's request — internalStatus, statusReason, isLaunched — and the S3 keys behind the assets. None of that is the customer's to read: an internal status is a note to ourselves, and an S3 key is a storage detail that would become a contract the moment it was published. What is here is what the caller sent, in the names it sent them under, plus the three things only we can answer: the record's id, its status, and the number it sends from. So a read after a write shows the form as stored rather than as echoed.
    - `id` string, uuid, nullable: The agent record. Stable across the whole approval, and what support will ask for. Nullable and omitted when absent: a sender profile with RCS intent records the channel but has no agent until the order form is submitted, so no id exists to report. A zero GUID is not a valid id and is worse than the field being absent.
    - `status` 'PROVISIONING' | 'ACTION_NEEDED' | 'PENDING_REVIEW' | 'ACTIVE' | 'INACTIVE', nullable: Where the agent stands, in terms of who is holding it up — PROVISIONING, ACTION_NEEDED, PENDING_REVIEW or ACTIVE. Resolved from both of the provider's axes rather than reported raw: an agent whose resubmission we have asked for reads ACTION_NEEDED however its carrier status still reads, and an agent not yet handed over reads PROVISIONING rather than pending a review nobody has started.
    - `reason_code` string, nullable: Why the agent is not ACTIVE, as a stable code: an ErrorCodes CHANNEL_xxx value such as CHANNEL_001 (something you owe) or CHANNEL_009 (under review). Switch on this rather than on reason. Omitted while ACTIVE. Read-only; when nothing more specific is known it is the generic reason for the status.
    - `reason` string, nullable: A sentence for reason_code, saying what to do where it is yours. Omitted while ACTIVE.
    - `phone_number` string, nullable: The number the agent sends from, derived from brand_phone_number.
    - `display_name` string, nullable
    - `description` string, nullable
    - `agent_use_case` string, nullable
    - `brand_name` string, nullable
    - `privacy_policy_url` string, nullable
    - `terms_and_conditions_url` string, nullable
    - `website_url` string, nullable
    - `brand_color` string, nullable
    - `brand_phone_number` string, nullable
    - `customer_support_phone_number` string, nullable
    - `brand_email` string, nullable
    - `customer_support_email` string, nullable
    - `contact_name_and_title` string, nullable
    - `company_ein` string, nullable
    - `entity_type` string, nullable
    - `official_address` SentDmServicesCommonChannelsContractsRcsAddress: The registered address of the company behind the agent.
      - `street` string, nullable
      - `city` string, nullable
      - `state` string, nullable
      - `postal_code` string, nullable
      - `country` string, nullable
    - `brief_company_description` string, nullable
    - `opt_in_process_description` string, nullable
    - `start_message` string, nullable
    - `help_message` string, nullable
    - `stop_message` string, nullable
    - `sample_messages` string[], nullable
    - `created_at` string, date-time, nullable: Omitted when no real agent record exists — the intent-only path has no creation timestamp.
  - `error` SentDmServicesEndpointsCustomerAPIv3SharedApiError: Error information
    - `code` string: Machine-readable error code (e.g., "RESOURCE_001")
    - `message` string: Human-readable error message
    - `details` object, nullable: Additional validation error details (field-level errors)
    - `doc_url` string, nullable: URL to documentation about this error
  - `meta` SentDmServicesEndpointsCustomerAPIv3SharedApiMeta: Request and response metadata
    - `request_id` string: Unique identifier for this request (for tracing and support)
    - `timestamp` string, date-time: Server timestamp when the response was generated
    - `version` string: API version used for this request

## Other responses

- `400`: A required field is missing or not an accepted value
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not Found
- `409`: This customer already has an RCS agent
- `500`: The agent could not be written

## Changes

- **2026-10-16** `6c829543a93e`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/sentdm/apis/sent-dm-api-v3/changes/v3/channels/rcs/post.md)

---

[API](https://skmtc.dev/sentdm/apis/sent-dm-api-v3.md) - [All operations](https://skmtc.dev/sentdm/apis/sent-dm-api-v3/llms.txt) - [OpenAPI document](https://skmtc.dev/sentdm/apis/sent-dm-api-v3/revisions/bdcca958cac7?raw)
