# Sent Documentation > Sent API Documentation - Documentation & Guides: Concepts, quickstart, guides, webhooks, and more — everything to build with Sent. - [One API for SMS, WhatsApp, and RCS](/start.md): Build multi-channel messaging with the Sent unified API: send SMS, WhatsApp, and RCS through one interface with automatic routing, fallback, and cost control. - **Introduction** - [What is Sent](/start/why-sent/what-is-sent.md): A quick introduction to Sent, what it is, what it does, and the problems it solves for teams building with messaging. - [Built for Scale](/start/why-sent.md): Why messaging became infrastructure: the forces that outgrow custom code and how shared platforms turn aggregate traffic into better delivery for everyone. - [What Sent Solves](/start/why-sent/use-cases.md): The messaging problems Sent is built to solve: guaranteed delivery, multichannel reach, and high-volume scale, and the teams that benefit most from each one. - [Compare Your Options](/start/why-sent/comparison.md): Compare Sent with direct provider integration and building in-house: setup time, maintenance, cost structure, migration paths, and a decision flowchart. - **Try Before You Commit** - [Try Sent: Send Your First Message in 2 Minutes, No Code](/start/try-sent.md): Explore Sent capabilities through the Dashboard Playground and send real messages in minutes with no code required. - **Quickstart** - [Quickstart Overview](/start/quickstart.md): Send your first message in minutes with light onboarding: a verified email and phone gets you API access, six pre-built templates, and 500 sends per day. - [Account Setup](/start/quickstart/account-setup.md): Create your Sent account and complete KYC verification: business details, destination countries, messaging use case, and billing to unlock the full platform. - [Channel Setup](/start/quickstart/channel-setup.md): Configure your own SMS, WhatsApp, and RCS sender for production: select a phone number, connect WhatsApp Business, enable RCS, and set up billing in Sent. - [Create Your First Template](/start/quickstart/first-template.md): Create your first message template in the Sent Dashboard: add dynamic variables, submit for WhatsApp and RCS approval, and get the template ID for API sends. - [Send Your First Message](/start/quickstart/first-message.md): Make your first Sent API call to send an SMS, WhatsApp, or RCS message: get your API key, send with a template, read the response, and track delivery status. - [The Sent Dashboard](/start/quickstart/dashboard-walkthrough.md): Tour the Sent Dashboard: send messages from the playground, manage contacts and templates, generate API keys, and monitor deliverability and account balance. - **Core Concepts** - [Core Concepts Overview](/start/concepts.md): The fundamental concepts behind the Sent messaging platform - unified messaging, channels, contacts, templates, Sender Profiles, and how they fit together - [Platform Overview](/start/concepts/platform-overview.md): Understanding Sent's intelligent messaging architecture and how it powers omnichannel communication - [Unified Messaging Intelligence](/start/concepts/unified-messaging.md): Why Sent exposes one intent-based messaging interface instead of channel APIs, and how the routing engine selects channels, falls back, and stays compliant - [Channels](/start/concepts/channels.md): Why Sent routes SMS, RCS, and WhatsApp behind one send call: the three-layer channel model, channel discovery, routing factors, and content adaptation. - [SMS Encoding & Message Length](/start/concepts/sms-encoding-and-length.md): How SMS character encoding (GSM-7 vs Unicode) and message concatenation determine character limits, segment counts, and cost - [Contacts](/start/concepts/contacts.md): What a contact is in Sent - a validated, channel-aware communication endpoint that carries availability, formatting, and routing state for a phone number - [Templates](/start/concepts/templates.md): Why Sent messages are defined as templates, and how one channel-agnostic definition adapts its content, variables, and buttons to SMS, WhatsApp, and RCS - [Sender Profiles](/start/concepts/sender-profiles.md): Why Sent models multi-tenancy as organizations and Sender Profiles, which resources a profile can inherit, and which are always dedicated to it. - [API Authentication](/start/concepts/api-authentication.md): Why the Sent API v3 authenticates every request with a single API key sent as a request header, covering the security model, trade-offs, and OAuth comparison. - [Trust & Safety](/start/concepts/trust-and-safety.md): How Sent protects your account, your recipients, and the platform from spam, fraud, and abuse. - [What is 10DLC?](/start/concepts/10dlc.md): Why carriers in the United States require 10DLC registration for A2P SMS, how The Campaign Registry reviews brands and campaigns, and where Sent fits in - **Implementation Guides** - [Implementation Guides](/start/guides.md): Step-by-step guides for common messaging patterns with Sent: sending messages, tracking delivery status, managing contacts, templates, errors, and testing. - [Connect a WhatsApp Business Account (WABA) to Sent](/start/guides/connect-whatsapp.md): Connect a WhatsApp Business Account to Sent: Meta authorization, choosing the sending number, confirming the channel is live, and the Sender Profile path. - [Managing channels](/start/guides/managing-channels.md): Read and change a sender's channels through the API: SMS markets per country and sender type, the WhatsApp account, the RCS agent, and what each one still owes for compliance. - [Creating and Managing API Keys](/start/guides/api-keys.md): How to create a Sent API key in the dashboard, store it safely in environment variables, verify it authenticates, and rotate or revoke keys independently. - [Sending Messages](/start/guides/sending-messages.md): How to send SMS, WhatsApp, and RCS messages with the Sent API: template sends, free-form text without a template, channel selection, and error handling. - [Message Best Practices](/start/guides/message-best-practices.md): Harden your Sent send path for production: store per-recipient message IDs, make critical sends idempotent, apply RCS send rules, and estimate bulk costs. - [Message Response Handling](/start/guides/message-responses.md): Parse Sent API v3 message-send responses: the success/data/error envelope, per-recipient message IDs, validation and auth error shapes, and async failures. - [SMS Length, Segments & Cost](/start/guides/sms-length-and-cost.md): How Sent counts SMS segments, how segments map to billing, and practical tips to keep messages short and predictable - [Message Status Tracking](/start/guides/message-status-tracking.md): Track Sent message delivery status in real time using webhook status events, API polling, and the dashboard, and handle failed messages and inbound replies. - [Two-Way Conversations](/start/guides/two-way-conversations.md): How Sent handles two-way conversations, from inbound matching and storage to keyword detection, opt-out handling, auto-replies, and the conversation rules that gate free-form replies on SMS, RCS, and WhatsApp. - [Handling Opt-Outs and Consent](/start/guides/opt-out-and-consent.md): How to mirror Sent opt-outs into your own database, set contact opt-out state through the API, detect consent-blocked sends, and apply a stricter send window. - [Managing Contacts](/start/guides/managing-contacts.md): Import your user base into Sent, honor opt-outs, and control channel routing per contact. Covers automatic contact creation, phone validation, and search. - [Working with Templates](/start/guides/working-with-templates.md): Start here for Sent message templates: build one in the dashboard, look up the definition JSON in the reference, and learn how templates and approval work. - [Create a Template in the Dashboard](/start/guides/create-a-template.md): Step-by-step directions for building a message template in the Sent dashboard: header, body, dynamic variables, buttons, category, and review submission. - [Creating a Sender Profile](/start/guides/creating-a-sender-profile.md): Create a Sender Profile in the Sent dashboard: identity, destination countries, sender number, WhatsApp, sharing, billing, and TCR compliance settings. - [Integrating Sender Profiles into Your Application](/start/guides/integrating-sender-profiles.md): Route messages through Sender Profiles in a multi-tenant app: profile API keys, per-customer sends, and per-profile webhook tracking across eight languages. - [Batch Operations](/start/guides/batch-operations.md): How to send messages in bulk with the Sent API: batches of up to 1000 recipients, rate limit management, idempotent retries, and bulk contact imports. - [Error Handling](/start/guides/error-handling.md): Handle errors gracefully with retries, circuit breakers, and fallback strategies - [How to handle Sent API errors](/start/guides/handling-api-errors.md): Handle Sent API v3 error responses in client code: check the success flag, branch on error codes, capture request IDs, and test failures with sandbox mode. - [How to retry Sent API requests safely](/start/guides/retrying-requests-safely.md): Retry Sent API v3 requests without duplicating messages or contacts: derive stable idempotency keys, reuse them across retries, and resolve conflicts. - [How to handle Sent API rate limits](/start/guides/handling-rate-limits.md): Keep your integration under Sent API v3 rate limits: back off on 429 responses, honor Retry-After, throttle requests client-side, and pace batch workloads. - [Testing & Debugging](/start/guides/testing-debugging.md): Test and debug your Sent integration by validating sends with sandbox mode, unit-testing webhook handlers, verifying signatures, and tracing failures. - [Testing with Sandbox Mode](/start/guides/testing-with-sandbox-mode.md): How to test a Sent integration with sandbox mode: assert against real API responses, run CI suites without sending messages, and reproduce failures safely. - **Webhooks & Events** - [Webhooks & Events Overview](/start/webhooks.md): Receive real-time message delivery notifications, inbound messages, and template approval events via webhooks, with guides for setup, security, and retries - [Webhook Setup](/start/webhooks/getting-started.md): Register a webhook endpoint in the Sent Dashboard, choose the message and template events to subscribe to, and verify your configuration with a test delivery - [Webhooks Lifecycle](/start/webhooks/lifecycle.md): How a webhook delivery moves from event generation through signing, retries, and the threshold that turns a failing webhook off, plus the events Sent emits - [Events Reference](/start/webhooks/event-types.md): Complete catalog of webhook event types and JSON payloads for all Sent webhook events - [Receiving Inbound Messages via the message.received Webhook](/start/webhooks/receiving-inbound-messages.md): How to receive contact replies in real time with the message.received webhook, acknowledge and deduplicate deliveries, and skip compliance keywords. - [Security](/start/webhooks/signature-verification.md): Verify webhook authenticity and implement security best practices for Sent webhooks - [Handling Retries](/start/webhooks/handling-retries.md): Make your Sent webhook handler idempotent: choose a payload-based dedupe key, handle duplicate and out-of-order events, and understand why retries happen. - [Local Development & Debugging](/start/webhooks/local-development.md): Expose your local server to receive Sent webhooks through a tunnel, send test events, debug failed deliveries, and process events reliably with queues - [Production Checklist](/start/webhooks/production-checklist.md): Pre-launch checklist for Sent webhook handlers: HTTPS and signature verification, idempotency, monitoring, error handling, scaling, and a runbook template. - **Advanced Topics** - [Advanced Guides Overview](/start/advanced.md): Advanced guides for platforms and enterprises building on Sent: performance optimization, 10DLC registration, compliance, v2 to v3 migration, and multi-tenancy. - [Performance optimization: high throughput on the Sent API](/start/advanced/performance-optimization.md): Optimize Sent API throughput: stay under the 200 requests per minute rate limit, batch up to 1,000 recipients per request, cache reads, and queue sends. - [10DLC Registration Guide](/start/advanced/10dlc-registration.md): How to register your brand and messaging campaigns with TCR through the Sent dashboard, including the form inputs, opt-in rules, and autoresponses required - [Register 10DLC Campaigns via the API](/start/advanced/10dlc-campaigns-api.md): Create, track, update, and delete 10DLC campaigns with the Sent API, from SENT_CREATED to ACTIVE, plus bulk registration patterns for agencies and resellers. - [Compliance & Regulations](/start/advanced/compliance-regulations.md): The compliance controls Sent enforces automatically at send time, what remains your responsibility, and per-region regulations with authoritative sources. - [API v2 to v3 Migration](/start/advanced/migration-v2-v3.md): Migrate your integration from the legacy Sent v2 API to v3 and update auth headers, request and response envelopes, error codes, webhooks, and idempotency. - [Multi-tenant architectures on Sent: profiles vs. accounts](/start/advanced/multi-tenant-architectures.md): Choose a tenant model for your messaging platform: Sender Profiles with per-tenant provisioning, one shared Sent account, or separate accounts per tenant. - [Create and activate Sender Profiles via the API](/start/advanced/sender-profiles-api.md): Create Sender Profiles with the Sent API: the minimum request, which resources are dedicated versus inherited, giving a profile a sender, and reading what its compliance still owes. - **Help & Reference** - [Help & Reference Overview](/start/reference-guides.md): Quick answers when you need help with Sent: frequently asked questions, problem-solution troubleshooting guides, error code references, and support channels. - [Frequently Asked Questions](/start/reference-guides/faq.md): Answers to common questions about Sent: getting started without KYC, pricing and billing, messaging and templates, webhooks, security, and technical limits. - [Troubleshooting Common Issues](/start/reference-guides/troubleshooting.md): Quick problem-to-solution fixes for common Sent issues: authentication errors, message sending failures, template rejections, webhooks, and channel setup. - [Support & Developer Resources](/start/reference-guides/support.md): Get help with Sent: support channels and response times, plus changelog, glossary, error catalog, troubleshooting guides, and FAQ resources for developers. - **LLM & AI Access** - [Docs for LLMs & AI Agents](/start/llm-docs.md): Machine-readable versions of the Sent documentation, plain-text files optimized for LLMs, AI coding assistants, and autonomous agents. - [Sent MCP Server](/start/llm-docs/mcp-server.md): Use Sent directly from Claude Code, Cursor, VS Code, and other AI coding agents via the Model Context Protocol - Build with Sent: The production blueprint — architect and ship a robust Sent integration, layer by layer, in any language. - [Build with Sent](/build.md): The production blueprint for integrating Sent: architecture, the outbound and inbound paths, and everything you need to ship a resilient, secure integration. - **Foundations** - [Reference Architecture](/build/architecture.md): The anatomy of a production Sent integration: the layers, the outbound and inbound request flows, the HTTP surface your app exposes, and where state lives. - [Setting Up the Project: SDK, Config, and Folder Layout](/build/project-setup.md): Prerequisites, SDK installation, the SDK-vs-raw-REST decision, config validation that fails fast, and a folder layout that realizes the reference architecture. - [Authenticating Requests with Per-Request Clients](/build/authentication.md): Build a Sent SDK client from the request's bearer key. Per-request client factories in seven frameworks, 401 guards, key verification, and easy rotation. - [About Per-Request Credentials](/build/per-request-credentials.md): Why the Sent API key is a per-request credential, never a boot-time singleton. Who sends the bearer key in each setup, and why isolation is structural. - **Sending Messages** - [Sending Messages with the Sent SDK: The Outbound Path](/build/sending-messages.md): A thin, testable service layer over messages.send: the request shape, multi-recipient response mapping, channels, sandbox sends, and where status comes from. - [Managing Contacts & Templates](/build/contacts-and-templates.md): Service wrappers for contacts and templates: the camelCase contract mapping, looking up templates by id or name, and decoupling your app from hard-coded IDs. - [Error Handling & Resilience](/build/errors-and-resilience.md): Turn SDK exceptions into your own error envelope, catch the right exception types per language, and build in retries, rate-limit backoff, and idempotency. - **Receiving Webhooks** - [Building the Webhook Receiver](/build/webhook-receiver.md): Build the inbound webhook endpoint end-to-end: capture the raw body, verify the signature, acknowledge fast with a 2xx, and process events asynchronously. - [Verifying Webhook Signatures](/build/signature-verification.md): The exact Svix-style HMAC scheme Sent uses to sign webhooks. Decode the secret, sign id.timestamp.body, compare in constant time, enforce the replay window. - [Managing Webhook Endpoints](/build/endpoint-management.md): The management surface for webhook endpoints. Register endpoints, capture the signing secret exactly once, toggle endpoints, and rotate secrets safely. - [Tracking Delivery Status](/build/status-tracking.md): Turn the stream of webhook events into a queryable per-message delivery status with a forward-only, idempotent store exposed on your own messages endpoint. - **Production Readiness** - [Securing Your Sent Integration: Secrets, CORS, and PII](/build/security.md): Hardening a Sent integration: per-request credentials, HTTPS, security headers and CORS, edge validation, rate limiting, and no secrets or PII in logs. - [Instrumenting Logs, Metrics & Traces](/build/observability.md): Structured logging, request-ID correlation, log levels, and metrics and tracing hooks for a Sent integration, with keys, secrets, and payloads kept out of logs. - [Scaling & Deploying the Integration](/build/scaling-and-deployment.md): Take a single-instance Sent integration to a horizontally scaled deployment: shared state stores, cross-instance idempotency, graceful shutdown, and probes. - [Testing Your Sent Integration: Unit, Route, and Sandbox](/build/testing.md): Test a Sent integration at every layer: mock the SDK for unit tests, drive real routes over HTTP, send safely with sandbox, and pin the webhook verifier. - [Going to Production](/build/going-to-production.md): The go-live checklist for a Sent integration. Credentials, verification, resilience, statelessness, security, monitoring, and a key/secret rotation runbook. - SDKs: Official SDKs for integrating Sent into your applications - [Sent SDKs](/sdks.md): Official SDKs for Sent's unified messaging API. Send SMS, WhatsApp, and RCS messages using your favorite programming language. - **Guides** - [SDK Best Practices](/sdks/best-practices.md): Production-ready patterns for using Sent SDKs. Error handling, retries, testing, and webhook security. - [Testing with SDKs](/sdks/testing.md): Testing strategies for Sent SDKs. Unit tests, integration tests, mocking, and CI/CD best practices. - [SDK Troubleshooting](/sdks/troubleshooting.md): Common issues and solutions when using Sent SDKs. Error codes, debugging tips, and FAQs. - **Languages** - TypeScript SDK: Official TypeScript SDK for Sent - [TypeScript SDK](/sdks/typescript.md): Official TypeScript SDK for Sent. Send SMS, WhatsApp, and RCS messages with full type safety and intelligent autocomplete. - [Your first Sent integration with the TypeScript SDK](/sdks/typescript/first-integration.md): Learn Sent by building a real TypeScript integration: send sandbox messages, receive delivery webhooks on your machine, and look up message status with the SDK. - **Integrations** - [Sending messages from Next.js with the Sent TypeScript SDK](/sdks/typescript/integrations/nextjs.md): Wire the Sent TypeScript SDK into a Next.js app: install, configure a server client, send from a route handler, verify webhooks, and test sandbox sends. - [Sending messages from NestJS with the Sent TypeScript SDK](/sdks/typescript/integrations/nestjs.md): Wire the Sent TypeScript SDK into a NestJS app: install, register a client provider, send from a controller, verify webhooks, and test with sandbox mode. - [Sending messages from Express with the Sent TypeScript SDK](/sdks/typescript/integrations/express.md): Wire the Sent TypeScript SDK into an Express app: install, configure the client, send template messages from a route, verify webhooks, and test sandbox sends. - Python SDK: Official Python SDK for Sent - [Python SDK](/sdks/python.md): Official Python SDK for Sent. Send SMS, WhatsApp, and RCS messages with Pythonic elegance and full async support. - **Integrations** - [Sending messages from Django with the Sent Python SDK](/sdks/python/integrations/django.md): Wire the Sent Python SDK into a Django project: install, configure the client, send a template message from a view, verify webhooks, and test with sandbox mode. - [Sending messages from FastAPI with the Sent Python SDK](/sdks/python/integrations/fastapi.md): Wire the Sent Python SDK into a FastAPI app: install, configure a client dependency, send messages from a route, verify webhooks, and test with sandbox mode. - [Sending messages from Flask with the Sent Python SDK](/sdks/python/integrations/flask.md): Wire the Sent Python SDK into a Flask app: install, configure the client, send a template message from a route, verify webhooks, and test with sandbox mode. - [Sending Sent messages from Celery background tasks](/sdks/python/integrations/celery.md): Send Sent messages from Celery tasks: install the Python SDK, configure a worker-safe client, add a retrying send task, and verify the task with sandbox mode. - Go SDK: Official Go SDK for Sent - [Go SDK](/sdks/go.md): Official Go SDK for Sent. Lightweight, fast, and context-aware with minimal dependencies. - **Integrations** - [Sending messages from a Gin service with the Sent Go SDK](/sdks/go/integrations/gin.md): Wire the Sent Go SDK into a Gin service: install, configure the client, send a template message from a handler, verify webhooks, and test with sandbox mode. - [Sending messages from an Echo service with the Sent Go SDK](/sdks/go/integrations/echo.md): Wire the Sent Go SDK into an Echo service: install, configure the client, send a template message from a handler, verify webhooks, and test with sandbox mode. - Java SDK: Official Java SDK for Sent - [Java SDK](/sdks/java.md): Official Java SDK for Sent. Send messages from JVM services, with Spring Boot integration and full async support. - **Integrations** - [Sending messages from Spring Boot with the Sent Java SDK](/sdks/java/integrations/spring-boot.md): Wire the Sent Java SDK into a Spring Boot app: install, register a client bean, send messages from a controller, verify webhooks, and test with sandbox mode. - C# / .NET SDK: Official .NET SDK for Sent - [C# / .NET SDK](/sdks/csharp.md): Official .NET SDK for Sent. Native async/await support for ASP.NET Core and .NET applications. - **Integrations** - [Sending messages from ASP.NET Core with the Sent C# SDK](/sdks/csharp/integrations/aspnet-core.md): Wire the Sent C# SDK into an ASP.NET Core app: install, register the client with DI, send from an endpoint, verify webhooks, and test with sandbox mode. - PHP SDK: Official PHP SDK for Sent - [PHP SDK](/sdks/php.md): Official PHP SDK for Sent. Elegant syntax with full Laravel and Symfony integration. - **Integrations** - [Sending messages from Laravel with the Sent PHP SDK](/sdks/php/integrations/laravel.md): Wire the Sent PHP SDK into a Laravel app: install, bind the client in a provider, send messages from a controller, verify webhooks, and test with sandbox mode. - [Sending messages from Symfony with the Sent PHP SDK](/sdks/php/integrations/symfony.md): Wire the Sent PHP SDK into a Symfony app: install, register the client service, send messages from a controller, verify webhooks, and test with sandbox mode. - Ruby SDK: Official Ruby SDK for Sent - [Ruby SDK](/sdks/ruby.md): Official Ruby SDK for Sent. Elegant DSL for Rails applications with full type support. - **Integrations** - [Sending messages from Rails with the Sent Ruby SDK](/sdks/ruby/integrations/rails.md): Wire the Sent Ruby SDK into a Rails app: install, configure the client, send a template message from a controller, verify webhooks, and test with sandbox mode. - [Sending messages from Sinatra with the Sent Ruby SDK](/sdks/ruby/integrations/sinatra.md): Wire the Sent Ruby SDK into a Sinatra app: install, configure the client, send a template message from a route, verify webhooks, and test with sandbox mode. - API Reference: Complete API documentation and reference - **Getting Started** - [Sent v3 API](/reference/api.md): Complete v3 API documentation for Sent's intelligent multi-channel messaging platform - [OpenAPI Specification](/reference/api/openapi-spec.md): Where to fetch the machine-readable OpenAPI document for the Sent API v3, how to pin a revision with its SHA-256 digest, and what the document does and doesn't cover. - **Core Concepts** - [Authentication](/reference/api/authentication.md): Sent API v3 authentication reference covering the API key request header, standard response headers, and AUTH error codes with statuses and causes. - [Roles and Permissions](/reference/api/roles-and-permissions.md): How Sent's four user roles control access to Sent API v3 operations and dashboard sections, and which checks produce AUTH_004 errors - [Idempotency](/reference/api/idempotency.md): Idempotency-Key contract for the Sent API v3: supported methods, key format, response caching, replay headers, and concurrency behavior. - [Sandbox Mode](/reference/api/test-mode.md): The sandbox request field in the Sent API v3: validation behavior, supported endpoints and their simulated responses, the X-Sandbox header, and troubleshooting. - [Data Models](/reference/api/data-models.md): Reference for the Sent API v3 response envelope, ApiError and ApiMeta objects, and pagination metadata, plus links to per-resource request and response schemas. - [Error Handling](/reference/api/errors.md): Understanding error responses, HTTP status codes, and troubleshooting common issues in the Sent API v3 - [Error Catalog](/reference/api/error-catalog.md): Every error code the Sent API v3 can return, with the HTTP status it maps to, the cause behind it, and the steps to resolve it - [API v2 to v3 changes](/reference/api/v2-to-v3.md): How Sent API v3 differs from the legacy v2 API: authentication headers, response envelope, property naming, sandbox mode, idempotency, and endpoint coverage. - [Rate Limits](/reference/api/rate-limits.md): Rate limit values, window semantics, 429 response headers, and per-endpoint limits for the Sent API v3, with the scope rules for shared account pools. - [Channel Routing and Fallback Behavior in the Sent API](/reference/channel-routing.md): Accepted channel values for POST /v3/messages, the resolution and fallback rules behind the default sent auto-detect channel, and what channel auto means. - [Two-Way Messaging Keywords, Channel Support, and Endpoints](/reference/two-way-messaging.md): Default and custom keyword actions, exact-match rules, two-way channel support for SMS, RCS, and WhatsApp, and the GET /v3/conversations history endpoints. - [Glossary of Sent Messaging, Compliance, and API Terms](/reference/glossary.md): Definitions of the messaging, compliance, and API terms used across the Sent platform, from channels, contacts, and Sender Profiles to templates and webhooks - **Messages** - [Send a message](/reference/api/messages/SentDmServicesEndpointsCustomerAPIv3MessagesSendMessageV3Endpoint.md): Sends a message to one or more recipients using a template. Supports multi-channel broadcast — when multiple channels are specified (e.g. ["sms", "whatsapp"]), a separate message is created for each (recipient, channel) pair. Returns immediately with per-recipient message IDs for async tracking via webhooks or the GET /messages/{id} endpoint. Sends gated before any delivery attempt do not reject the request — an account-level precondition such as insufficient balance, a template not approved for sending, or free-form content with no open conversation with the contact. The send is accepted with 202 and the affected messages are reported as BLOCKED on GET /messages/{id} and the message.blocked webhook. - [Get message status](/reference/api/messages/SentDmServicesEndpointsCustomerAPIv3MessagesGetMessageEndpoint.md): Retrieves the current status and details of a message by ID. Includes delivery status, timestamps, and error information if applicable. - [Get message activities](/reference/api/messages/SentDmServicesEndpointsCustomerAPIv3MessagesGetMessageActivitiesEndpoint.md): Retrieves the activity log for a specific message. Activities track the message lifecycle including acceptance, processing, sending, delivery, and any errors. - **Conversations** - [List conversation messages](/reference/api/conversations/SentDmServicesEndpointsCustomerAPIv3ConversationsGetConversationsEndpoint.md): Retrieves a paginated list of the authenticated customer's messages across all conversations, ordered by created date (most recent first). - [List messages for a conversation](/reference/api/conversations/SentDmServicesEndpointsCustomerAPIv3ConversationsGetConversationByIdEndpoint.md): Retrieves a paginated list of the messages in a single conversation (scoped to the authenticated customer), ordered by created date (most recent first). - **Contacts** - [Get contacts list](/reference/api/contacts/SentDmServicesEndpointsCustomerAPIv3ContactsGetContactsEndpoint.md): Retrieves a paginated list of contacts for the authenticated customer. Supports filtering by search term, channel, or phone number. - [Get contact by ID](/reference/api/contacts/SentDmServicesEndpointsCustomerAPIv3ContactsGetContactByIdEndpoint.md): Retrieves a specific contact by their unique identifier. Returns detailed contact information including phone formats, available channels, and opt-out status. - [Create a contact](/reference/api/contacts/SentDmServicesEndpointsCustomerAPIv3ContactsCreateContactEndpoint.md): Creates a new contact by phone number and associates it with the authenticated customer. - [Update a contact](/reference/api/contacts/SentDmServicesEndpointsCustomerAPIv3ContactsUpdateContactEndpoint.md): Updates a contact's default channel and/or opt-out status. - [Delete a contact](/reference/api/contacts/SentDmServicesEndpointsCustomerAPIv3ContactsDeleteContactEndpoint.md): **Deprecated.** Use `PATCH /v3/contacts/{id}` with `{"opt_out": true}` instead, and expect this to be removed in a future release. It still behaves exactly as before, so nothing needs to change today. Opting a contact out stops every send to them, which is what deleting one was mostly used for — and it keeps the record of who they were and that they asked. A delete discards the consent history along with the contact, which is the part you need if anyone ever asks why you stopped, or why you started again. Dissociates a contact from the authenticated customer. - [Get message summary for a contact](/reference/api/contacts/SentDmServicesEndpointsCustomerAPIv3ContactsGetContactMessageSummaryEndpoint.md): Returns aggregate message counts, time bounds, channels used, and per-channel success/fail scores (each as a percentage 0-100 of messages on that channel) for one of your contacts. Successful terminal states: SENT/DELIVERED/READ for outbound, RECEIVED for inbound. Fail: FAILED. - **Templates** - [Template Definition](/reference/api/template-definition.md): Reference for the Sent template definition JSON: header, body, footer, button, and variable fields, content rules and limits, and template statuses. - [Get templates list](/reference/api/templates/SentDmServicesEndpointsCustomerAPIv3TemplatesGetTemplatesEndpoint.md): Retrieves a paginated list of message templates for the authenticated customer. Supports filtering by status, category, and search term. - [Get template by ID](/reference/api/templates/SentDmServicesEndpointsCustomerAPIv3TemplatesGetTemplateEndpoint.md): Retrieves a specific template by its ID. Returns template details including name, category, language, status, and definition. - [Create a new template](/reference/api/templates/SentDmServicesEndpointsCustomerAPIv3TemplatesCreateTemplateEndpoint.md): Creates a new message template with header, body, footer, and buttons. The template can be submitted for review immediately or saved as draft for later submission. - [Update a template](/reference/api/templates/SentDmServicesEndpointsCustomerAPIv3TemplatesUpdateTemplateEndpoint.md): Updates an existing template's name, category, language, definition, or submits it for review. - [Delete a template](/reference/api/templates/SentDmServicesEndpointsCustomerAPIv3TemplatesDeleteTemplateEndpoint.md): Deletes a template by ID. Optionally, you can also delete the template from WhatsApp/Meta by setting delete_from_meta=true. - **Sender Profiles** - [List sender profiles](/reference/api/sender/SentDmServicesEndpointsCustomerAPIv3SenderProfilesGetSenderProfilesEndpoint.md): Lists the sender profiles under your organization, newest first, paginated with `page` and `page_size`. Each entry is the same document `GET /v3/sender-profiles/{id}` returns, with one difference: **listed markets carry no `compliance`**. Working out what a market still owes means a catalog lookup and a document read per market, and doing that for every profile on a page would turn one request into dozens to answer a question you did not ask. Read a single profile for that. `compliance` being **absent** is not the same as it being **empty**. Absent means it was not worked out here; empty means the market owes nothing. `api_key` is never returned. It is shown once, by create. - [Get a sender profile](/reference/api/sender/SentDmServicesEndpointsCustomerAPIv3SenderProfilesGetSenderProfileEndpoint.md): Reads one of your sender profiles. The document mirrors `POST /v3/sender-profiles`, with three differences that follow from this being a read rather than a request. `channels.sms` is a **list**. Create takes the one market a profile starts in; a profile can go on to send in several, and this reports all of them, each with its own `status` and its own outstanding `compliance`. `brand` comes back **in full, with `inherit` saying whose it is**. On a request `{ "inherit": true }` carries no data because there is nothing to send; here it carries the data, because the point of a read is to say what the profile actually sends under. **There is no `campaigns` array.** A campaign is only ever a registration, so what a read can usefully say about one is whether anything is still owed for it — and that is reported per market, in `channels.sms[].compliance.requirements`. A profile running on your organization's campaign is asked for none of the campaign fields, so an empty `requirements` is how an inherited campaign reads. `api_key` is **never** returned here. It is shown once, by create. A profile belonging to another organization reads as `404`, not `403`: saying which of the two it is would confirm the id exists. - [Create a sender profile](/reference/api/sender/SentDmServicesEndpointsCustomerAPIv3SenderProfilesCreateSenderProfileEndpoint.md): Creates a sender profile under your organization. A profile is a customer of yours: it sends under its own or your identity, and your customers never see Sent. ## The minimum `{ "name": "Example Retail", "short_name": "Example" }`. `short_name` is the SMS sender id and is required. Identity, inbox, opt-out list and billing come from your organization, so the profile is usable immediately with no compliance work. **A sender is not one of them.** The brand and the campaign can be inherited; a number cannot. A profile either has a sender of its own — `channels.sms` — or it has none and terminates through the shared routes for that country. ## Saying what a profile owns Every capability is one of three things, and there is no flag per state: - **Its own** — supply the capability's fields. Data is what owning looks like. - **The organization's** — `{ "inherit": true }`, with nothing else. - **None** — omit the block. There is no `"inherit": false` that also carries no data. A second way to say the same thing would let a request contradict itself. Inheriting needs no id. A customer has exactly one brand, so `brand` resolves without one. **The campaign has no block of its own.** It is only ever a registration, and every field of one is something a specific market demands — so it lives in `compliance`, alongside the rest of what that market asks for, and it says whose it is there too: `"compliance": { "inherit": true }` runs the profile on your organization's campaign and stops this call asking for any campaign field. Omitted, or `false`, gives the profile its own; inheriting takes *all* of your organization's, because inheritance resolves an owner rather than a single row. A profile with a `brand` of its own **cannot** inherit the campaign, and asking is refused with `400`: a campaign is filed against a brand registration, and your organization's campaign is filed against your organization's brand rather than this profile's. Inherit both, or own both. `channels.sms` is the market the profile starts in — one `country` and `number_type`. It decides what else this call asks for: the compliance catalog is keyed on that pair, and it determines which fields `brand` accepts and what `compliance` answers for. A profile is a tenant, not a market, so it can go on to send in several — but through `POST /v3/channels/sms` with the `x-profile-id` header, one market and its compliance at a time. Reads return every market as `channels.sms[]`, so the read shape is a list even where this one is not. `brand` is required when `number_type` is `TEN_DLC` — inherited or its own. A 10DLC registration has nothing to attach to without one, and no later call can supply it, so omitting it is refused with `400` rather than reported as outstanding. ## Use cases and volume A TCR campaign declares one to five `use_cases`, each with its own `sample_messages` — TCR attributes samples to the use case they illustrate, so they travel together. How that set registers is derived from `volume` and never declared. Below the low-volume threshold the campaign registers as `LOW_VOLUME` with every entry as a sub-use-case; above it, one entry registers as that use case outright and several register as `MIXED` with sub-use-cases. `MIXED` and `LOW_VOLUME` are therefore refused as `use_case` values: they describe the shape of a set, which is ours to work out. **Leaving `volume` out is accepted and costs more.** An absent value registers the campaign at the standard tier, which carries the higher fee — so say so when a campaign is low volume. Sole proprietor brands are the exception: their fee is fixed by entity type, and volume only decides the use case. ## Compliance `brand` is captured identically in every country. Everything a specific market demands on top of it — including every field of the campaign — goes in `compliance`, as key/value entries whose keys depend on the sender's country and type. US `TEN_DLC` registers with The Campaign Registry and asks for a substantial set; an alphanumeric sender may pre-register with documents, or need nothing at all. You do not have to know any of it. Omit `compliance` and the response lists exactly what is outstanding, with types and accepted values — or call `GET /v3/compliance/requirements` first. Anything Sent supplies on your behalf is never asked for, and is rejected if sent. Requirements can be conditional, and the condition is published as `required_when` so you can render a form from it rather than discover the rule by being rejected. Every US `TEN_DLC` campaign field carries `compliance.inherit != true` — send `"inherit": true` and none of them is asked for or accepted, because the profile is running on your organization's campaign. ## Uploading documents Send `application/json` for everything except a market that pre-registers a sender with supporting documents. For those, send `multipart/form-data` instead: put this entire document — unchanged — in a single field named `profile`, and attach each file under a field named after the compliance key it satisfies. Individual form fields per property are not read; the payload is always the one `profile` field. ## WhatsApp and RCS Neither can be inherited, so neither takes an `inherit`: the profile's WhatsApp account and RCS agent are its own or it has none. Sharing your organization's would share its inbox and its throughput, which makes the two indistinguishable to a recipient. `channels.whatsapp` names one of the accounts shared into your organization, and takes the two identifiers nothing else can supply: `waba_id`, because your organization holds one account per client, and `phone_number_id`, because an account may hold several numbers and choosing for you would decide which of your customer's numbers their traffic leaves from. Everything else is resolved from your organization — the Multi-Partner Solution the account arrived through, the client business portfolio that owns it, the access token and that token's expiry. None of them is accepted here: the first two are Meta's answer about provenance, so a value you sent could assert a partnership Meta disagrees with, and the token is minted per client business and rotates roughly every sixty days. `phone_number_id` is optional. Omit it to connect the account now and settle the number later — the channel reads as `provisioning` and the profile keeps sending from your organization's account until a number is named. `POST /v3/channels/whatsapp` connects an account to an existing profile and resolves the same fields the same way. An account of its own needs a sender of its own, so `channels.whatsapp` requires `channels.sms`. A profile sending SMS on your organization's sender shares that inbox and opt-out list, and is not a separate tenant to give an account to — asking is refused with `400`, before your organization is asked to resolve anything. `channels.rcs` records the agent. A carrier approval no API call can trigger is arranged offline, so the capability reports `awaiting_submission` until it is. `rcs.brand_id` is Google's identifier and is unrelated to the top-level `brand`. ## Responses `201` when the profile is complete on return — the fully-inherited case, where nothing needs registering. `202` when something is still provisioning, with per-capability status and outstanding requirements. `409` when the WhatsApp account supplied is already recorded. `400` covers a wrong value as well as a missing one: a missing brand under `TEN_DLC`, an unknown compliance key, a bad type, a sender id the market does not allow, or a `waba_id` that is not one of the accounts shared into your organization. - [Update a sender profile](/reference/api/sender/SentDmServicesEndpointsCustomerAPIv3SenderProfilesPatchSenderProfileEndpoint.md): Changes a profile's own attributes: `name`, `short_name` and `description`. **Only those.** A profile's identity, its markets and its compliance each have a sub-resource of their own, because each has its own validation and its own external consequences — a brand change may need re-registering, a market change provisions a sender. Folding them in here would give those fields two writers and no way to say which one wins. Omitting a field leaves it alone; sending `null` clears it. Those are different requests, so `{}` changes nothing and is refused rather than silently accepted — a caller who misspelt every field would otherwise get a `200` and an unchanged profile. `name` and `short_name` cannot be cleared: `short_name` is the SMS sender id, so a supplied value must be 3–11 characters of letters, numbers and spaces with at least one letter. Returns the profile as `GET /v3/sender-profiles/{id}` would, so the result of the change needs no second call to see. - [Delete a sender profile](/reference/api/sender/SentDmServicesEndpointsCustomerAPIv3SenderProfilesDeleteSenderProfileEndpoint.md): Deletes one of your sender profiles and returns `204`. The delete is **soft**: the profile stops being usable and stops appearing in reads, and its message history is kept, because deleting a profile must not delete the record of what it sent. ## What it releases Anything the profile still held goes with it. A **phone number** returns to our inventory and can be given to whoever asks next — it does not stay reserved for you, and getting the same number back afterwards is not something we can promise. A **WhatsApp account of its own** is deregistered from Meta. Its routing rules stop being used, so nothing sends through the profile after this call. A profile that only inherits from its organization holds nothing of its own and releases nothing. - **Channels** - [Get your channels](/reference/api/channels/SentDmServicesEndpointsCustomerAPIv3ChannelsGetChannelsEndpoint.md): Every market you send SMS in, your WhatsApp account and your RCS agent — with each one's status, and what each market still owes. **Status lives on the channel, never on you or your brand.** An identity has no lifecycle; what has one is the registration of a sender in a market and the approval of a channel. So a customer live in one country and mid-registration in another reports exactly that, rather than one flattened answer. `compliance[]` carries one entry per market, naming the country and sender type it answers for. An empty `requirements` means that market is satisfied; anything listed is what to supply, and `GET /v3/compliance/requirements` describes each key in full. Send `x-profile-id` with an organization key to read one of your profiles' channels. - [List your SMS markets](/reference/api/channels/SentDmServicesEndpointsCustomerAPIv3ChannelsMarketGetSmsMarketsEndpoint.md): Every market you send SMS in, each with its sender, where that sender stands, and what its compliance holds. The same entries `GET /v3/channels` reports under `sms`, and the same shape `GET /v3/channels/sms/{country}/{type}` returns for one of them — so a list, a member read and the all-channels read cannot describe a market differently. Send `x-profile-id` with an organization key to list one of your profiles' markets. - [Get one SMS market (country and sender type)](/reference/api/channels/SentDmServicesEndpointsCustomerAPIv3ChannelsMarketGetSmsMarketEndpoint.md): Reads one market you send in — its sender, where that sender stands, and everything its compliance holds. ## What `compliance` carries A market that registers with a compliance regime reports `brand` — the identity the registration is filed against — and `campaign`, the programme filed against it. Each carries `inherit`, saying whether it is yours or your organization's. A market that registers with nobody has neither, so **both keys are absent** rather than null: absent says this market does not ask, where null would say it asks and you supplied nothing. It reports `documents` instead. `requirements` lists what is still owed, keyed as you write it — `brand.legal_name`, `campaign.message_flow`. ## Writing it back **`PATCH` this same path**, with the `compliance` object from this response: ```json { "compliance": { "brand": { "tax_id": "12-3456789" } } } ``` Nothing else to learn — what comes back can be sent back, an omitted key is left alone, and a `requirements` key is the path into the body that clears it. There is no sub-resource for either half: both are singletons of the market, so both are written here. `GET /v3/compliance/requirements` says what a market demands of anybody; this says what you gave it. Send `x-profile-id` with an organization key to read one of your profiles' markets. - [Add an SMS market — a country and sender type](/reference/api/channels/SentDmServicesEndpointsCustomerAPIv3ChannelsAddSmsChannelEndpoint.md): Gives the customer a sender in one country — the first market it sends in, and the fifth. ## What to have in place first **Call `GET /v3/compliance/requirements?country=US&type=TEN_DLC` first.** It returns this request's body ready to fill in, plus the brand and campaign calls to make before it, in order. You never have to track forty countries' rules yourself. **A market that registers with a compliance regime needs an identity, and this call takes one.** US `TEN_DLC` registers with The Campaign Registry and files that registration against a business identity. Send it in `compliance.brand` and it is recorded here, before the registration that attaches to it — so a customer with no identity reaches a first 10DLC market in one call. `{ "inherit": true }` runs on your organization's instead. A market with neither — none stored, none sent — is `400`, because accepting it would write a channel that could never register and leave it provisioning for ever with nothing saying why. **Everything the regime wants arrives in this request's `compliance`**, as two declared objects: `brand` — the identity the registration is filed against — and `campaign`, with the use case, the consent narrative, the volume, the sample messages and the keywords. There is nothing to set up first. Nothing is submitted here either: the rows are what a submission is later assembled from, and filing is externally rejectable so it happens on its own path. A market that registers with nobody — an alphanumeric sender in most countries — needs neither, and may need documents instead. ## Sending it Takes the same fields `channels.sms` takes on `POST /v3/sender-profiles`, because it is the same work, and both run one provisioning path. `compliance` is top-level and answers for the market in this request, carrying `brand` and `campaign` where the market registers. **Accepts multipart as well as JSON**, with each file named after the compliance key it satisfies — a market that pre-registers its sender needs its documents at the same moment it needs the sender. A market the customer already holds is `409`: adding what is already there is a mistake worth reporting rather than a silent no-op. A market is a `(country, sender_type)` pair, so a **second sender type in a country you already send in is fine** — `US TOLL_FREE` alongside `US TEN_DLC` is the ordinary case. Two of the same type is not. One exception: while a market's sender type is still unassigned, adding any type to that country is `409`, because the market you have may be about to become the one you asked for. Returns **the market**, in the shape `GET` and `PATCH` on `/v3/channels/sms/{country}/{type}` use — so what this answers can be read back and written back without reshaping, and `compliance.requirements` names what it still owes. Not every channel you have: adding a market cannot change an RCS agent or a WhatsApp account, and `GET /v3/channels` is the whole picture. `201` when the market is ready; `202` while a sender or a registration is still outstanding. Send `x-profile-id` with an organization key to add a market to one of your profiles. - [Amend one SMS market's compliance](/reference/api/channels/SentDmServicesEndpointsCustomerAPIv3ChannelsMarketPatchSmsMarketEndpoint.md): Writes what this market declares for compliance, and answers with the market as stored — the same shape `GET` on this path returns, so **what comes back can be sent back**. ## Partial, at every level **An omitted key is left alone. An explicit `null` clears it.** Those are different requests, so `{}` changes nothing and is refused rather than silently accepted, and correcting one field does not blank the others. ```json { "compliance": { "brand": { "contact_phone": "+12125550123" } } } ``` That leaves the campaign untouched, along with every other field of the identity. ## What a US `TEN_DLC` market holds Two halves, both singular: `brand`, the identity the registration is filed against, and `campaign`, the programme filed against it. Each carries `inherit`. | Body | Effect | | --- | --- | | `"brand": { … }` | supplies or corrects the identity, and takes one of your own | | `"brand": { "inherit": true }` | runs on your organization's, giving up your own | | `"brand": null` | the same thing, said the short way | | `"campaign": { … }` | supplies or corrects the programme, and takes one of your own | | `"campaign": { "inherit": true }` | runs on your organization's | | key omitted | left exactly as it is | **Nothing here creates a second anything.** One identity and one campaign per market, so a write is an upsert and a replayed request lands on the row it already wrote. Sending the campaign twice does not file two registrations. ## Every other market Markets that register with no regime have neither half — their compliance is documents, which cannot be JSON values and are sent as multipart on `POST /v3/channels/sms`. Only US `TEN_DLC` registers, so this path is `404` everywhere else. ## What it will refuse **A filed identity is `409`.** Once the registration has gone to The Campaign Registry they hold a copy, and a local change would diverge from it silently. The campaign is not frozen — omit `brand` and the same body is accepted. **More than one campaign is `409`.** The schema permits several and an account built on the admin side may hold them; this surface writes one, and editing whichever sorted first would leave the others unmentioned and unedited. Nothing is submitted to a regime here. These are the rows a submission is later assembled from, which is what lets them be corrected without waiting on something externally rejectable. Send `x-profile-id` with an organization key to write one of your profiles' markets. - [Add a WhatsApp account](/reference/api/channels/SentDmServicesEndpointsCustomerAPIv3ChannelsAddWhatsappChannelEndpoint.md): Connects a WhatsApp Business Account shared with us through a Multi-Partner Solution to the calling sender profile. Send `x-profile-id` for the profile the account belongs to. **Two fields, because everything else is derived.** `waba_id` says which of your organization's shared accounts this is — you hold one per client, and nothing else can say which. `phone_number_id` says which number on it to send from — an account may hold several, and choosing for you would mean deciding which of your customer's numbers their traffic leaves from. The solution the account arrived through, the client business portfolio that owns it, the access token and its expiry are all resolved from your organization. They are not accepted here: the first two are Meta's answer about provenance, and the token is minted per client business and rotates roughly every sixty days, so a value you sent would be stale before it was useful. `phone_number_id` is optional. Omit it to connect the account now and settle the number later — the channel reads as `provisioning` and the profile keeps sending from your organization's account until a number is named. The same resolution runs behind `channels.whatsapp` on `POST /v3/sender-profiles`, so connecting at create and connecting afterwards fill the same fields. Returns **the account**, not every channel you have — adding one cannot change a market or an RCS agent, and `GET /v3/channels` is the whole picture. Giving an account up is not self-service: ask support, because deregistering a number lands in your own Meta business. - [Add an RCS agent](/reference/api/channels/SentDmServicesEndpointsCustomerAPIv3ChannelsAddRcsChannelEndpoint.md): 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. - **Compliance** - [Get compliance requirements for a market](/reference/api/compliance/SentDmServicesEndpointsCustomerAPIv3ComplianceGetComplianceRequirementsEndpoint.md): **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. - **Profiles (Deprecated)** - [List profiles in organization](/reference/api/profiles/SentDmServicesEndpointsCustomerAPIv3ProfilesGetProfilesEndpoint.md): **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. - [Get profile by ID](/reference/api/profiles/SentDmServicesEndpointsCustomerAPIv3ProfilesGetProfileEndpoint.md): **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 detailed information about a specific sender profile within an organization, including brand and KYC information if a brand has been configured. - [Create a new profile](/reference/api/profiles/SentDmServicesEndpointsCustomerAPIv3ProfilesCreateProfileEndpoint.md): **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. Creates a new sender profile within an organization. Profiles represent different brands, departments, or use cases, each with their own messaging configuration and settings. Requires admin role in the organization. ## WhatsApp Business Account Every profile owns its own WhatsApp Business Account — accounts are never shared between profiles or inherited from the organization. Provide a `whatsapp_business_account` object with `waba_id`, `phone_number_id`, and `access_token`. Obtain these from Meta Business Manager by creating a System User with `whatsapp_business_messaging` and `whatsapp_business_management` permissions. Omit the field and the profile is created without WhatsApp, staying incomplete until it has an account of its own. ## Brand Include the optional `brand` field to create the brand for this profile at the same time. Cannot be used when `inherit_tcr_brand` is `true`. ## Payment Details When `billing_model` is `"profile"` or `"profile_and_organization"` you may include a `payment_details` object containing the card number, expiry (MM/YY), CVC, and billing ZIP code. Payment details are **never stored** on our servers and are forwarded directly to the payment processor. Providing `payment_details` when `billing_model` is `"organization"` is not allowed. - [Update profile settings](/reference/api/profiles/SentDmServicesEndpointsCustomerAPIv3ProfilesUpdateProfileEndpoint.md): **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. Updates a profile's configuration and settings. Requires admin role in the organization. Only provided fields will be updated (partial update). ## Brand Management Include the optional `brand` field to create or update the brand associated with this profile. The brand holds KYC and TCR compliance data (legal business info, contact details, messaging vertical). Once a brand has been submitted to TCR it cannot be modified. Setting `inherit_tcr_brand: true` and providing `brand` in the same request is not allowed. ## Payment Details When `billing_model` is `"profile"` or `"profile_and_organization"` you may include a `payment_details` object containing the card number, expiry (MM/YY), CVC, and billing ZIP code. Payment details are **never stored** on our servers and are forwarded directly to the payment processor. Providing `payment_details` when `billing_model` is `"organization"` is not allowed. ## Deprecated fields `sending_phone_number_profile_id` and `sending_whatsapp_number_profile_id` are **accepted and ignored**. Sender borrowing is gone: a profile cannot send from another profile's number, because two profiles behind one sender makes an inbound reply and a delivery receipt ambiguous about whose they are. Sending either **changes nothing and still returns `200`** — they are kept on the contract so an existing integration keeps working. Reads carry both keys too and always answer `null`, which is how you can confirm the value did not take. Give the profile a sender of its own instead — `POST /v3/channels/sms` or `POST /v3/channels/whatsapp`, sent with the `x-profile-id` header naming it. - [Delete a profile](/reference/api/profiles/SentDmServicesEndpointsCustomerAPIv3ProfilesDeleteProfileEndpoint.md): **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. Soft deletes a sender profile. The profile will be marked as deleted but data is retained. Anything it still held is released first: phone numbers return to our inventory and can go to whoever asks next, its own WhatsApp account is deregistered, and its routing rules stop being used. Requires admin role in the organization. - [Complete profile setup](/reference/api/profiles/SentDmServicesEndpointsCustomerAPIv3ProfilesCompleteProfileEndpoint.md): **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. Final step in the profile compliance workflow. Validates all prerequisites (KYC, brand, campaigns, required documents), connects the profile to the SMS and WhatsApp channels, and marks it onboarded. Prerequisites are always validated first: if any fail the call returns 400 naming every unmet one, and nothing is started. If they pass and the profile is already onboarded, the call returns 200 and does nothing. Otherwise it returns 202 and calls the provided webhook URL when background processing finishes. Callable with the organization's API key or the profile's own key. The key's user must be an admin or owner of the profile, or of the organization it belongs to. Prerequisites (all but the last are checked before the already-onboarded short-circuit, matching the previous contract; the last is checked after it, so a profile that is already onboarded is never rejected by it): - Profile must have a name, short name, and description (short name max 50 characters, description max 5000) - webHookUrl must be supplied on the request - A KYC form submission is required - A brand is required, either on the profile or inherited from the parent organization - TCR applications must have at least one campaign, own or inherited - Destination countries marked as main must have their required compliance documents uploaded - TCR applications must state whether they inherit the organization's TCR brand and campaign Outcome: - Once the prerequisites pass and background processing succeeds, the profile's conversionFlowStatus becomes ONBOARDED and its public status reads `approved` - A profile with no WhatsApp channel, or one still awaiting TCR registration or country documents, is onboarded like any other. Those are answered by the brand and campaign records, not by a status on the profile - If background processing fails, the profile keeps the status it already had and the webhook reports the reason - **Brands (Deprecated)** - [Get campaigns for a profile's brand](/reference/api/brands/SentDmServicesEndpointsCustomerAPIv3BrandsCampaignsGetBrandCampaignsEndpoint.md): **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 campaigns linked to the profile's brand, including use cases and sample messages. Returns inherited campaigns if inherit_tcr_campaign=true. - [Create a campaign for a profile's brand](/reference/api/brands/SentDmServicesEndpointsCustomerAPIv3BrandsCampaignsCreateBrandCampaignEndpoint.md): **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. Creates a new campaign scoped under the brand of the specified profile. Each campaign must include at least one use case with sample messages. - [Update a campaign](/reference/api/brands/SentDmServicesEndpointsCustomerAPIv3BrandsCampaignsUpdateBrandCampaignEndpoint.md): **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. Updates an existing campaign under the brand of the specified profile. Cannot update campaigns that have already been submitted to TCR. - [Delete a campaign](/reference/api/brands/SentDmServicesEndpointsCustomerAPIv3BrandsCampaignsDeleteBrandCampaignEndpoint.md): **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. Deletes a campaign by ID from the brand of the specified profile. The profile must belong to the authenticated organization. - **Users** - [List users](/reference/api/users/SentDmServicesEndpointsCustomerAPIv3UsersGetUsersEndpoint.md): Retrieves all users who have access to the organization or profile identified by the API key, including their roles and status. Shows invited users (pending acceptance) and active users. Requires developer role or higher. - [Get user by ID](/reference/api/users/SentDmServicesEndpointsCustomerAPIv3UsersGetUserEndpoint.md): Retrieves detailed information about a specific user in an organization or profile. Requires developer role or higher. - [Invite a user](/reference/api/users/SentDmServicesEndpointsCustomerAPIv3UsersInviteUserEndpoint.md): Sends an invitation to a user to join the organization or profile with a specific role. Requires admin role. The user will receive an invitation email with a token to accept. Invitation tokens expire after 7 days. - [Update user role](/reference/api/users/SentDmServicesEndpointsCustomerAPIv3UsersUpdateUserEndpoint.md): Updates a user's role in the organization or profile. Requires admin role. You cannot change your own role or demote the last admin. - [Remove user](/reference/api/users/SentDmServicesEndpointsCustomerAPIv3UsersRemoveUserEndpoint.md): Removes a user's access to an organization or profile. Requires admin role. You cannot remove yourself or remove the last admin. - **Webhooks** - [Get webhooks list](/reference/api/webhooks/SentDmServicesEndpointsCustomerAPIv3WebhooksGetWebhooksEndpoint.md): Retrieves a paginated list of webhooks for the authenticated customer. - [Get a webhook](/reference/api/webhooks/SentDmServicesEndpointsCustomerAPIv3WebhooksGetWebhookEndpoint.md): Retrieves a single webhook by ID for the authenticated customer. - [Create a webhook](/reference/api/webhooks/SentDmServicesEndpointsCustomerAPIv3WebhooksCreateWebhookEndpoint.md): Creates a new webhook endpoint for the authenticated customer. - [Update a webhook](/reference/api/webhooks/SentDmServicesEndpointsCustomerAPIv3WebhooksUpdateWebhookEndpoint.md): Updates an existing webhook for the authenticated customer. - [Delete a webhook](/reference/api/webhooks/SentDmServicesEndpointsCustomerAPIv3WebhooksDeleteWebhookEndpoint.md): Deletes a webhook for the authenticated customer. - [Toggle webhook status](/reference/api/webhooks/SentDmServicesEndpointsCustomerAPIv3WebhooksToggleWebhookStatusEndpoint.md): Activates or deactivates a webhook for the authenticated customer. - [Rotate webhook signing secret](/reference/api/webhooks/SentDmServicesEndpointsCustomerAPIv3WebhooksRotateWebhookSecretEndpoint.md): Generates a new signing secret for the specified webhook. The old secret is immediately invalidated. - [Test a webhook](/reference/api/webhooks/SentDmServicesEndpointsCustomerAPIv3WebhooksTestWebhookEndpoint.md): Sends a test event to the specified webhook endpoint to verify connectivity. - [Get webhook events](/reference/api/webhooks/SentDmServicesEndpointsCustomerAPIv3WebhooksGetWebhookEventsEndpoint.md): Retrieves a paginated list of delivery events for the specified webhook. - [Get available webhook event types](/reference/api/webhooks/SentDmServicesEndpointsCustomerAPIv3WebhooksGetWebhookEventTypesEndpoint.md): Retrieves all available webhook event types that can be subscribed to. - **Account** - [Get authenticated account](/reference/api/accounts/SentDmServicesEndpointsCustomerAPIv3AccountGetAccountEndpoint.md): Returns the account associated with the provided API key. The response includes account identity, contact information, messaging channel configuration, and — depending on the account type — either a list of child profiles or the profile's own settings. **Account types:** - `organization` — Has child profiles. The `profiles` array is populated. - `user` — Standalone account with no profiles. - `profile` — Child of an organization. Includes `organization_id`, `short_name`, `status`, and `settings`. **Channels:** The `channels` object always includes `sms`, `whatsapp`, and `rcs`. Each channel has a `configured` boolean. Configured channels expose additional details such as `phone_number`. **Sending number:** `sending_phone_number` is the account's US SMS sender. It is intentionally the same value as `channels.sms.phone_number` — the two are kept in step, and it is published under both names because `sending_phone_number` is what this value is called on `GET /v3/profiles`. Read either. One difference: `sending_phone_number` is always present, including as `null`, while `channels.sms.phone_number` is omitted when there is no sender. `sending_phone_number_profile_id` names the account that holds that number in inventory — normally this account, and a different one where a number is shared. Both are `null` when the account has no US SMS sender. - **Number Lookup** - [Get phone number details](/reference/api/number-lookup/SentDmServicesEndpointsCustomerAPIv3NumbersGetNumberEndpoint.md): Retrieves detailed information about a phone number including carrier, line type, porting status, and VoIP detection. Uses the customer's messaging provider for rich data, with fallback to the internal index. - **Changelog** - [Changelog](/reference/changelog.md): A chronological record of platform updates, new features, and important changes to Sent's APIs and services - **Help** - [Email Support](mailto:support@sent.dm) - [Help Center](https://help.sent.dm) - Legacy API Reference: Legacy API documentation - **API Reference** - [Sent Legacy v2 API](/reference-legacy/api.md): Complete Legacy v2 API documentation for Sent's intelligent multi-channel messaging platform - [Authentication](/reference-legacy/api/authentication.md): How to authenticate Legacy Sent API (v2) requests with the x-sender-id and x-api-key headers, plus credential setup, 401 error responses, and key management. - [Data Models](/reference-legacy/api/data-models.md): Request and response schemas for the legacy Sent API v2, covering contact, template, and message objects, pagination wrappers, and webhook event payloads. - [Error Reference](/reference-legacy/api/errors.md): HTTP status codes and the problem-details error response format returned by the legacy Sent API v2, with example JSON error payloads for each status code. - [Error Catalog](/reference-legacy/api/error-catalog.md): Lookup catalog of legacy Sent API v2 errors: authentication, validation, balance, not-found, rate-limit, and server errors with causes and remediation. - [Rate Limits](/reference-legacy/api/rate-limits.md): Rate limits for the legacy Sent API v2: the per-minute limit on send endpoints, the quick-message daily cap, and the headers returned on 429 responses. - [Glossary](/reference-legacy/glossary.md): Definitions of key terms for the legacy Sent API v2, covering authentication credentials, contacts, channels, message templates, and delivery statuses. - **Messages** - [Send message to contact](/reference-legacy/api/message/send-to-contact.md): Sends a message to a specific contact using a template. The message can be sent via SMS or WhatsApp depending on the contact's capabilities. Optionally specify a webhook URL to receive delivery status updates. The customer ID is extracted from the authentication token. - [Send message to phone number](/reference-legacy/api/message/send-to-phone.md): Sends a message to a phone number using a template. The phone number doesn't need to be a pre-existing contact. The message can be sent via SMS or WhatsApp. Optionally specify a webhook URL to receive delivery status updates. The customer ID is extracted from the authentication token. - [Send quick message](/reference-legacy/api/message/quick-message.md): Sends a message to a phone number using the default template. This endpoint is rate limited to 5 messages per customer per day. The customer ID is extracted from the authentication token. - [Get message details by ID](/reference-legacy/api/message/get-by-id.md): Retrieves comprehensive details about a specific message using the message ID. Returns complete message data including delivery status, channel information, template details, contact information, and pricing. The customer ID is extracted from the authentication token to ensure the message belongs to the authenticated customer. - **Contacts** - [Get paginated contacts for authenticated customer](/reference-legacy/api/contacts/list-contacts.md): Retrieves a paginated list of contacts for the authenticated customer. Supports server-side pagination with configurable page size. The customer ID is extracted from the authentication token. - [Get contact by ID for authenticated customer](/reference-legacy/api/contacts/get-by-id.md): Retrieves a specific contact by their unique identifier for the authenticated customer. The customer ID is extracted from the authentication token. Returns detailed contact information including phone number and creation timestamp. - [Get contact by phone number for authenticated customer](/reference-legacy/api/contacts/get-by-phone.md): Retrieves a contact by their phone number for the authenticated customer. Phone number should be in international format (e.g., +1234567890). The customer ID is extracted from the authentication token. - **Templates** - [Get all templates for authenticated customer with enhanced metadata and filtering](/reference-legacy/api/templates/list-templates.md): Retrieves all message templates available for the authenticated customer with comprehensive template definitions including headers, body, footer, and interactive buttons. Supports advanced filtering by search term, status, and category, plus pagination. The customer ID is extracted from the authentication token. - [Get template by ID with enhanced metadata](/reference-legacy/api/templates/get-by-id.md): Retrieves a specific message template by its unique identifier for the authenticated customer with comprehensive template definitions including headers, body, footer, and interactive buttons. The customer ID is extracted from the authentication token. - [Create a new template with enhanced metadata and optional submission for review](/reference-legacy/api/templates/create-template.md): Creates a new message template for the authenticated customer with comprehensive template definitions including headers, body, footer, and interactive buttons. Supports automatic metadata generation using AI (display name, language, category). Optionally submits the template for WhatsApp review. The customer ID is extracted from the authentication token. - [Delete template by ID](/reference-legacy/api/templates/delete-template.md): Deletes a message template by ID for the authenticated customer. Templates with no messages are hard deleted; templates with message history are soft deleted. - **Number Lookup** - [Lookup phone number information](/reference-legacy/api/number-lookup/lookup.md): Retrieves detailed information about a phone number including validation, formatting, country information, and available messaging channels. The customer ID is extracted from the authentication token. - **Help** - [Email Support](mailto:support@sent.dm) - [Help Center](https://help.sent.dm) - Troubleshooting: Common issues and step-by-step solutions - [Troubleshooting](/troubleshooting.md): Diagnose and fix the most common Sent issues: WhatsApp, RCS, and SMS delivery failures, account activation, template rejections, authentication, and compliance. - **Account & Onboarding** - [Account Activation & KYC Review](/troubleshooting/account-activation.md): Resolve delays with account approval, KYC verification, TCR submission, and post-approval onboarding issues - [Login, Signup & OTP Verification](/troubleshooting/authentication.md): Troubleshoot common issues with signing up, logging in, OTP delivery, phone verification, and account access on Sent.dm - **Messaging** - [Messages Not Delivered](/troubleshooting/messages-not-delivered.md): Diagnose and fix WhatsApp, RCS, and SMS delivery failures: API-vs-dashboard mismatches, Meta anti-spam errors, country filtering, sender routing, and failover. - [WhatsApp Template Issues](/troubleshooting/template-issues.md): Troubleshoot template creation errors, approval delays, categorization problems, and parameter mismatches for WhatsApp messaging on Sent - **WhatsApp** - [WhatsApp Onboarding & Business Account Connection](/troubleshooting/whatsapp-setup.md): Troubleshoot WhatsApp Business Account connection errors, phone number conflicts, Meta verification issues, and onboarding requirements - [Troubleshoot WhatsApp Delivery Failures by Error Code](/troubleshooting/whatsapp-delivery-errors.md): Diagnose failed WhatsApp messages by error code, from undeliverable recipients to invalid template names and parameters, and see when Sent falls back to SMS. - **Numbers & Compliance** - [Phone Number & Sender ID Issues](/troubleshooting/phone-numbers.md): Troubleshoot common problems with phone number availability, sender IDs, regional number provisioning, and messages sending from the wrong number. - [Compliance & 10DLC Issues](/troubleshooting/compliance.md): Troubleshoot compliance form submissions, 10DLC registration errors, A2P requirements, and country-specific messaging regulations on Sent.dm