Get compliance requirements for a market

Call this first. It returns what a channel, country and sender type demand before you can send there — and setup[], the calls that satisfy those demands, in order, each with a body you can copy and send as it stands. You never have to track forty countries' rules yourself.

Channel

channel is sms, whatsapp or rcs, and defaults to sms — so a caller that omits it gets exactly what this endpoint has always returned.

sms is the only one answered today; the other two are 501 until their requirements are declared. They are refused rather than answered with an empty requirement set, because empty would say the channel demands nothing, and both demand plenty — WhatsApp a business verification and a display name review, RCS a carrier approval. Saying "not yet" is the true answer and the same one POST /v3/sender-profiles gives for channels.whatsapp.

type is an SMS sender type, and SMS is the only channel whose senders have one.

Requirements vary enormously. US TEN_DLC registers a brand and a campaign with The Campaign Registry and asks for a substantial set of values. An alphanumeric sender in one country pre-registers with supporting documents; in another it needs nothing at all. This is the authoritative answer for whichever market you are asking about, and it is the same declaration used to validate the calls themselves — so it can never drift from what is actually enforced.

setup[] — what to do

One step. POST /v3/channels/sms adds the market and records everything it registers with — the identity in compliance.brand, the programme in compliance.campaign. There were three, in a load-bearing order, while the identity and the campaign were resources of their own; they are members of this call's body now, so there is nothing to sequence.

Correct any of it afterwards with PATCH /v3/channels/sms/{country}/{type}, which takes the same compliance object one key at a time.

Each step's body has every key that market wants already present, with the values left blank. Blank rather than filled with placeholders, because the body is meant to be sent: a null value counts as not supplied, so posting a step verbatim comes back naming every blank you left. attachments[] lists files to send as multipart on the channel call, each under the field name given — a file cannot be a JSON value, so documents are never listed in compliance[].

Every step is a call for whoever holds the key. To set a sender profile up instead, send the same requests with the x-profile-id header naming it; there is no separate path.

requirements[] — what each value means

Each entry names a key for the compliance array, its value type, and whether it is required. required_when marks values needed only in certain cases — evaluate it against your own payload, e.g. brand.entity_type == PUBLIC_PROFIT. options lists accepted values where the market constrains them, and label is suitable for rendering a form field.

Values Sent supplies on your behalf are never listed: correlation ids, environment flags, carrier elections, and booleans derivable from what you already send.

When nothing is required

required is false and requirements is empty, and the single setup step carries no compliance array at all. A sender_id_pattern may still be present — many markets constrain the sender string without registering anything.

GET
/v3/compliance/requirements

Response Body

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v3/compliance/requirements"
{
  "success": true,
  "data": {
    "channel": "sms",
    "country": "US",
    "type": "TEN_DLC",
    "required": true,
    "sender_id_pattern": null,
    "requirements": [
      {
        "key": "brand",
        "type": "object",
        "format": null,
        "required": false,
        "required_when": null,
        "options": null,
        "min_length": null,
        "max_items": null,
        "item_fields": [
          {
            "key": "inherit",
            "type": "boolean",
            "format": null,
            "required": false,
            "required_when": null,
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Run on the organization's brand",
            "notes": "True to register under the parent organization's identity rather than one of this profile's own; every field below is then neither asked for nor accepted. Omitted, the brand is the organization's unless this block supplies identity fields, which says plainly enough that it wants one of its own."
          },
          {
            "key": "legal_name",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.brand.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Registered legal name",
            "notes": "TCR companyName — the name on the incorporation documents, which is often not the name recipients would recognise."
          },
          {
            "key": "business_name",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.brand.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Public-facing name",
            "notes": "TCR displayName — the name recipients would recognise. Named for what it holds rather than for TCR's field, which is why it is not `display_name`."
          },
          {
            "key": "tax_id",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.brand.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Tax identifier",
            "notes": "TCR ein. TcrBrandSubmissionValidator refuses a submission without one, so it is wanted here rather than discovered at filing time."
          },
          {
            "key": "tax_id_type",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.brand.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Kind of tax identifier",
            "notes": "Which kind of identifier `tax_id` is, e.g. us_ein. Derived onto the brand form, and not itself sent to TCR."
          },
          {
            "key": "ein_issuing_country",
            "type": "string",
            "format": "iso3166_alpha2",
            "required": false,
            "required_when": null,
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Country that issued the tax id",
            "notes": "TCR einIssuingCountry — where the tax id was issued, which is not always where the business trades. Defaults to `country` when omitted, which is right for most."
          },
          {
            "key": "entity_type",
            "type": "enum",
            "format": null,
            "required": false,
            "required_when": "compliance.brand.inherit != true",
            "options": [
              "PRIVATE_PROFIT",
              "PUBLIC_PROFIT",
              "NON_PROFIT",
              "SOLE_PROPRIETOR",
              "GOVERNMENT"
            ],
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Entity type",
            "notes": "TCR entityType. Decides which vetting TCR applies and, for SOLE_PROPRIETOR, fixes the campaign fee regardless of volume. Also refused at submission if absent."
          },
          {
            "key": "street",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.brand.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Street address",
            "notes": null
          },
          {
            "key": "city",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.brand.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "City",
            "notes": null
          },
          {
            "key": "state",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.brand.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "State or region",
            "notes": "TCR state. Two letters for a US registration."
          },
          {
            "key": "postal_code",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.brand.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Postal code",
            "notes": null
          },
          {
            "key": "country",
            "type": "string",
            "format": "iso3166_alpha2",
            "required": false,
            "required_when": "compliance.brand.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Country of registration",
            "notes": null
          },
          {
            "key": "website",
            "type": "string",
            "format": "url",
            "required": false,
            "required_when": null,
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Website",
            "notes": "TCR website. Optional, and worth sending: carriers weigh it when vetting, so a brand that has one and omits it is vetted on less than it could be."
          },
          {
            "key": "contact_name",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.brand.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Responsible contact",
            "notes": "Split into TCR's firstName/lastName on submission. BrandService refuses a blank one, so a missing name is reported here rather than thrown after the profile was written."
          },
          {
            "key": "contact_email",
            "type": "string",
            "format": "email",
            "required": false,
            "required_when": "compliance.brand.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Contact email",
            "notes": "TCR email."
          },
          {
            "key": "contact_phone",
            "type": "string",
            "format": "e164",
            "required": false,
            "required_when": "compliance.brand.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Contact phone",
            "notes": "TCR sends it as both phone and mobilePhone, so it is asked for once. Named for the contact it belongs to rather than as a bare `phone` on a block that also carries an address."
          }
        ],
        "label": "Business identity",
        "notes": "The identity the registration is filed against. Omit to have none; { \"inherit\": true } to register under your organization's."
      },
      {
        "key": "campaign",
        "type": "object",
        "format": null,
        "required": false,
        "required_when": "compliance.campaign.inherit != true",
        "options": null,
        "min_length": null,
        "max_items": null,
        "item_fields": [
          {
            "key": "inherit",
            "type": "boolean",
            "format": null,
            "required": false,
            "required_when": null,
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Run on the organization's campaign",
            "notes": "True to register under the parent organization's programme rather than one of this profile's own; every field below is then neither asked for nor accepted. Owning the identity and inheriting the campaign is refused — a campaign is filed against an identity registration, and chk_tcr_inheritance forbids that pairing outright."
          },
          {
            "key": "description",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.campaign.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "What this programme sends",
            "notes": "TCR description: what recipients will get and why, in a sentence. The only one of these TCR takes verbatim as a description of the programme, which is why it is asked for rather than derived from the customer's name."
          },
          {
            "key": "message_flow",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.campaign.inherit != true",
            "options": null,
            "min_length": 40,
            "max_items": null,
            "item_fields": null,
            "label": "Consent narrative",
            "notes": "TCR messageFlow: how recipients opt in, in prose. Under 40 characters is refused, and carriers reject vague descriptions — say where opt-in happens, that the box is unchecked by default, and that consent is not a condition of purchase."
          },
          {
            "key": "use_cases",
            "type": "array",
            "format": null,
            "required": false,
            "required_when": "compliance.campaign.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": 5,
            "item_fields": [
              {
                "key": "use_case",
                "type": "enum",
                "format": null,
                "required": true,
                "required_when": null,
                "options": [
                  "MARKETING",
                  "ACCOUNT_NOTIFICATION",
                  "CUSTOMER_CARE",
                  "FRAUD_ALERT",
                  "2FA",
                  "DELIVERY_NOTIFICATION",
                  "SECURITY_ALERT",
                  "M2M",
                  "HIGHER_EDUCATION",
                  "POLLING_VOTING",
                  "PUBLIC_SERVICE_ANNOUNCEMENT"
                ],
                "min_length": null,
                "max_items": null,
                "item_fields": null,
                "label": "Use case",
                "notes": "What this entry sends. MIXED and LOW_VOLUME are refused — volume decides those."
              },
              {
                "key": "sample_messages",
                "type": "array",
                "format": null,
                "required": true,
                "required_when": null,
                "options": null,
                "min_length": null,
                "max_items": 5,
                "item_fields": null,
                "label": "Sample messages",
                "notes": "TCR sample1..sample5 for this use case. One to five, each carrying the brand name and an opt-out instruction."
              }
            ],
            "label": "Use cases",
            "notes": "What the campaign sends, and an example of each. One to five entries; how they register is decided by volume, never declared."
          },
          {
            "key": "opt_in_message",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.campaign.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Opt-in confirmation",
            "notes": "TCR optinMessage. Should state message frequency and that rates may apply. Its presence is what sets subscriberOptin."
          },
          {
            "key": "opt_out_message",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.campaign.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Opt-out confirmation",
            "notes": "TCR optoutMessage. Its presence is what sets subscriberOptout."
          },
          {
            "key": "help_message",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": "compliance.campaign.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Help reply",
            "notes": "TCR helpMessage. Its presence is what sets subscriberHelp."
          },
          {
            "key": "opt_in_keywords",
            "type": "string",
            "format": "csv_keywords",
            "required": false,
            "required_when": "compliance.campaign.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Opt-in keywords",
            "notes": "TCR optinKeywords, comma separated, e.g. START,YES."
          },
          {
            "key": "opt_out_keywords",
            "type": "string",
            "format": "csv_keywords",
            "required": false,
            "required_when": "compliance.campaign.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Opt-out keywords",
            "notes": "TCR optoutKeywords, comma separated. STOP, END, CANCEL, UNSUBSCRIBE and QUIT are honoured regardless of what is declared."
          },
          {
            "key": "help_keywords",
            "type": "string",
            "format": "csv_keywords",
            "required": false,
            "required_when": "compliance.campaign.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Help keywords",
            "notes": "TCR helpKeywords, comma separated, e.g. HELP,INFO."
          },
          {
            "key": "privacy_policy_link",
            "type": "string",
            "format": "url",
            "required": false,
            "required_when": "compliance.campaign.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Privacy policy URL",
            "notes": "TCR privacyPolicyLink."
          },
          {
            "key": "terms_and_conditions_link",
            "type": "string",
            "format": "url",
            "required": false,
            "required_when": "compliance.campaign.inherit != true",
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Terms and conditions URL",
            "notes": "TCR termsAndConditionsLink."
          },
          {
            "key": "volume",
            "type": "string",
            "format": null,
            "required": false,
            "required_when": null,
            "options": null,
            "min_length": null,
            "max_items": null,
            "item_fields": null,
            "label": "Expected monthly volume",
            "notes": "Decides how the campaign registers and which fee tier applies: below the low-volume threshold it registers as LOW_VOLUME with sub-use-cases, above it as a single use case or MIXED. Omitting it registers the campaign at the higher-fee standard tier."
          }
        ],
        "label": "Messaging campaign",
        "notes": "What the programme sends and how recipients consented. Omit to run on your organization's; supplying it takes one of your own. { \"inherit\": true } says so outright."
      }
    ],
    "setup": [
      {
        "step": 1,
        "resource": "channel",
        "method": "POST",
        "path": "/v3/channels/sms",
        "why": "Adds the market, claims a number for it, and records everything The Campaign Registry asks — the identity in `compliance.brand`, the programme in `compliance.campaign`. The registration stays outstanding until it is filed and answered, which happens off this call.",
        "body": {
          "country": "US",
          "number_type": "TEN_DLC",
          "sender_value": null,
          "compliance": {
            "brand": {
              "inherit": null,
              "legal_name": null,
              "business_name": null,
              "tax_id": null,
              "tax_id_type": null,
              "ein_issuing_country": null,
              "entity_type": null,
              "street": null,
              "city": null,
              "state": null,
              "postal_code": null,
              "country": null,
              "website": null,
              "contact_name": null,
              "contact_email": null,
              "contact_phone": null
            },
            "campaign": {
              "inherit": null,
              "description": null,
              "message_flow": null,
              "use_cases": null,
              "opt_in_message": null,
              "opt_out_message": null,
              "help_message": null,
              "opt_in_keywords": null,
              "opt_out_keywords": null,
              "help_keywords": null,
              "privacy_policy_link": null,
              "terms_and_conditions_link": null,
              "volume": null
            }
          }
        },
        "attachments": null
      }
    ]
  },
  "error": null,
  "meta": {
    "request_id": "req_7X9zKp2jDw",
    "timestamp": "2026-09-04T16:45:29.195715+00:00",
    "version": "v3"
  }
}
{
  "success": false,
  "data": null,
  "error": {
    "code": "VALIDATION_001",
    "message": "type must be one of: LOCAL, MOBILE, TEN_DLC, TOLL_FREE, SHORT_CODE, ALPHANUMERIC",
    "details": null,
    "doc_url": "https://docs.sent.dm/reference/api/error-catalog"
  },
  "meta": {
    "request_id": "req_7X9zKp2jDw",
    "timestamp": "2026-09-04T16:45:29.1957201+00:00",
    "version": "v3"
  }
}
Empty
Empty
{
  "success": true,
  "error": {
    "code": "string",
    "message": "string",
    "details": {
      "property1": [
        "string"
      ],
      "property2": [
        "string"
      ]
    },
    "doc_url": "string"
  },
  "meta": {
    "request_id": "string",
    "timestamp": "2019-08-24T14:15:22Z",
    "version": "string"
  }
}
{
  "success": true,
  "error": {
    "code": "string",
    "message": "string",
    "details": {
      "property1": [
        "string"
      ],
      "property2": [
        "string"
      ]
    },
    "doc_url": "string"
  },
  "meta": {
    "request_id": "string",
    "timestamp": "2019-08-24T14:15:22Z",
    "version": "string"
  }
}
{
  "success": true,
  "error": {
    "code": "string",
    "message": "string",
    "details": {
      "property1": [
        "string"
      ],
      "property2": [
        "string"
      ]
    },
    "doc_url": "string"
  },
  "meta": {
    "request_id": "string",
    "timestamp": "2019-08-24T14:15:22Z",
    "version": "string"
  }
}

Add an RCS agent POST

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. **Required, because US carriers refuse a submission without them:** - **`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`** and **`terms_and_conditions_url`** — fetched over the public internet at review time, so they must be absolute `http(s)` URLs. One behind a login passes this call and fails the review. **Everything else is optional here** and can follow. `display_name`, `description`, `agent_use_case` and `brand_color` are collected as the submission is assembled; `hosting_region` (`us` or `eu`) defaults to `us` and cannot be changed once approved; `billing_category` (`CONVERSATIONAL`, `SINGLE_MESSAGE`, `BASIC_MESSAGE`) defaults to `CONVERSATIONAL`. Contact details, `official_address`, the consent narrative and the start/help/stop messages are all part of the form. Anything supplied is checked against the 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. `logo_url` and `banner_url` are validated as URLs only. The form also specifies 224x224 and 50 KB for the logo and 1440x448 and 200 KB for the banner, which cannot be checked without the image bytes. **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.

List profiles in organization GET

**Deprecated.** This endpoint is replaced by `/v3/sender-profiles` and will be removed in a future release. It still behaves exactly as before, so nothing needs to change today — but new integrations should use `/v3/sender-profiles`, which models a profile's markets, compliance, brand, campaigns and billing explicitly. Retrieves all sender profiles within an organization, including brand information for each profile. Profiles represent different brands, departments, or use cases within an organization, each with their own messaging configuration.