> ## Documentation Index
> Fetch the complete documentation index at: https://www.vobiz.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# US 10DLC campaigns

> Create and register a 10DLC campaign through the Vobiz Messaging API - describe the use case, upload supporting documents, submit for carrier review, poll network statuses, attach local numbers, and update, appeal or deregister a campaign.

A **campaign** describes one messaging program: who receives the messages, how they opted in, what the messages say and which numbers send them. Campaigns belong to a [brand](/docs/sms/compliance/us-10dlc-brands). The US 10DLC registry and the carriers review each campaign before the numbers attached to it can carry A2P traffic.

<Tip>
  Building with code? The full request and response for every call here are in the [campaign endpoints](/docs/sms/api/10dlc/create-campaign) of the [Messaging API](/docs/sms/overview).
</Tip>

In the console, campaigns live under **SMS & RCS → Registration → Campaigns**. This page covers the same flow through the API.

<Note>
  The brand must be registered first. Campaigns submitted under a brand whose `registrationStatus` is not `ACTIVE` are rejected with a reason that asks you to fix the brand.
</Note>

## Campaign fields

Send these on [`POST /10dlc/campaigns`](/docs/sms/api/10dlc/create-campaign) and [`PUT /10dlc/campaigns/{id}`](/docs/sms/api/10dlc/update-campaign).

| Field | Type | Required | Description |
| - | - | - | - |
| `referenceId` | string | no | Your idempotency reference. A retry with the same value reconciles to the same campaign. Ignored on `PUT`. |
| `name` | string | yes | Internal name for the campaign. |
| `brandId` | string (UUID) | yes | The Vobiz brand `id`. Unknown ids return `404 {"error": "brand not found"}`. Resolved server-side on `PUT`. |
| `campaignType` | string | no | Defaults to `TEN_DIGIT_LONG_CODE`. Immutable after creation. Toll-free types go through [`POST /10dlc/campaigns/toll-free`](/docs/sms/compliance/us-toll-free). |
| `programSummary` | string | | What the program does, who receives messages and how they opt in. |
| `confirmationMessage` | string | | The message sent after a recipient opts in. |
| `helpMessage` | string | | The reply to HELP. |
| `stopMessage` | string | | The reply to STOP. |
| `customerCarePhone` | string | | Support phone number in E.164 format. |
| `customerCareEmail` | string | | Monitored support mailbox. |
| `termsAndConditionsUrl` | string | | Public terms page. |
| `privacyPolicyUrl` | string | | Public privacy policy. |
| `exampleMessages` | string\[] | | Representative messages. Start each with the brand name and include opt-out language. |
| `useCases` | string\[] | | Registry use-case codes. See [values](#registry-values). |
| `messageTypes` | string\[] | | Content types you send, for example `["SMS"]` or `["SMS", "MMS"]`. |
| `optIns` | object | | How consent is collected, in the registry's structure. A web form looks like `{"web": {"url": "https://example.com/signup", "callToAction": "By checking this box you agree to receive ..."}}`. |
| `lowVolume` | boolean | | Low expected volume. Default `false`. |
| `ageGated` | boolean | | Content restricted to adults. Default `false`. |
| `directLending` | boolean | | Loan or lending content. Default `false`. |
| `embeddedLink` | boolean | | Messages contain links. Default `false`. |
| `embeddedPhone` | boolean | | Messages contain phone numbers. Default `false`. |
| `numbers` | string\[] | | Numbers to attach at creation, as digits with the country code and no `+`, for example `14155550100`. You can also add them later. |
| `supportingDocuments` | string\[] | | Document `id` values from [`POST /10dlc/documents`](/docs/sms/api/10dlc/upload-document): opt-in screenshots, consent forms. |
| `mmsSampleFiles` | string\[] | | Document `id` values for sample MMS media. |

### Registry values

The US 10DLC registry accepts these `useCases`. Vobiz passes them through as you send them.

`TWO_FACTOR_AUTH`, `ALERTS`, `FRAUD_ALERTS`, `CHAT`, `PROMOTIONAL_MARKETING`, `EDUCATION`, `DONATION`, `PUBLIC_SERVICE_ANNOUNCEMENT`, `VOTING_POLLING`, `POLITICAL`, `M2M`, `SWEEPSTAKE`

`campaignType` on this endpoint is `TEN_DIGIT_LONG_CODE`.

## Supporting documents

Upload files before you reference them from a campaign.

* [`POST /10dlc/documents`](/docs/sms/api/10dlc/upload-document) is `multipart/form-data` with the file in the field named `document`. Files up to 10 MB are accepted; larger files return `413 {"error": "document exceeds 10MB"}`. The response is `201` with `id`, `documentId`, `documentName`, `contentType`, `contentLength` and `createdAt`.
* Put the `id` values in `supportingDocuments` or `mmsSampleFiles`. Referencing a document that is not on your account returns `400 {"error": "invalid request: supportingDocuments/mmsSampleFiles reference unknown documents; upload them via POST /v1/10dlc/documents first"}`.
* [`GET /10dlc/documents/{documentId}`](/docs/sms/api/10dlc/get-document) streams the file back. The path takes the `documentId` value, not `id`.

```bash cURL theme={null}
curl -X POST "https://api.vobiz.ai/api/v1/sms/10dlc/documents" \
  -H "X-Auth-ID: MA_XXXXXXXX" \
  -H "X-Auth-Token: YOUR_AUTH_TOKEN" \
  -F "document=@opt-in-form.png"
```

## Register a campaign

<Steps>
  <Step title="Create the campaign">
    `POST /10dlc/campaigns` stores a draft on your account. Nothing is submitted yet.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST "https://api.vobiz.ai/api/v1/sms/10dlc/campaigns" \
        -H "X-Auth-ID: MA_XXXXXXXX" \
        -H "X-Auth-Token: YOUR_AUTH_TOKEN" \
        -H "Content-Type: application/json" \
        -d '{
          "brandId": "9b2e1c40-8a3d-4f5e-9c1a-7d6b2e8f4a01",
          "name": "Account alerts",
          "useCases": ["ALERTS"],
          "messageTypes": ["SMS"],
          "programSummary": "Acme sends account and billing alerts to customers who opt in on the Acme dashboard. Message frequency varies. Reply STOP to opt out, HELP for help.",
          "exampleMessages": [
            "Acme: Your invoice #4821 is due on 30 Oct. View it at https://example.com/billing. Reply STOP to opt out, HELP for help."
          ],
          "confirmationMessage": "Acme: You are subscribed to account alerts. Msg frequency varies. Msg & data rates may apply. Reply HELP for help, STOP to opt out.",
          "helpMessage": "Acme: For help email support@example.com. Reply STOP to opt out.",
          "stopMessage": "Acme: You have been unsubscribed and will receive no more messages.",
          "optIns": {
            "web": {
              "url": "https://example.com/signup",
              "callToAction": "By checking this box you agree to receive account alerts from Acme by SMS. Msg & data rates may apply. Reply STOP to opt out."
            }
          },
          "customerCarePhone": "+14155550100",
          "customerCareEmail": "support@example.com",
          "termsAndConditionsUrl": "https://example.com/terms",
          "privacyPolicyUrl": "https://example.com/privacy",
          "embeddedLink": true,
          "supportingDocuments": ["3c9d7e21-5b4a-4f0e-8d2c-1a6b9e7f3d02"]
        }'
      ```

      ```python Python theme={null}
      import requests

      BASE = "https://api.vobiz.ai/api/v1/sms"
      HEADERS = {
          "X-Auth-ID": "MA_XXXXXXXX",
          "X-Auth-Token": "YOUR_AUTH_TOKEN",
          "Content-Type": "application/json",
      }

      campaign = {
          "brandId": "9b2e1c40-8a3d-4f5e-9c1a-7d6b2e8f4a01",
          "name": "Account alerts",
          "useCases": ["ALERTS"],
          "messageTypes": ["SMS"],
          "programSummary": "Acme sends account and billing alerts to customers who opt in on the Acme dashboard. Message frequency varies. Reply STOP to opt out, HELP for help.",
          "exampleMessages": [
              "Acme: Your invoice #4821 is due on 30 Oct. View it at https://example.com/billing. Reply STOP to opt out, HELP for help."
          ],
          "confirmationMessage": "Acme: You are subscribed to account alerts. Msg frequency varies. Msg & data rates may apply. Reply HELP for help, STOP to opt out.",
          "helpMessage": "Acme: For help email support@example.com. Reply STOP to opt out.",
          "stopMessage": "Acme: You have been unsubscribed and will receive no more messages.",
          "optIns": {"web": {"url": "https://example.com/signup", "callToAction": "By checking this box you agree to receive account alerts from Acme by SMS. Msg & data rates may apply. Reply STOP to opt out."}},
          "customerCarePhone": "+14155550100",
          "customerCareEmail": "support@example.com",
          "termsAndConditionsUrl": "https://example.com/terms",
          "privacyPolicyUrl": "https://example.com/privacy",
          "embeddedLink": True,
          "supportingDocuments": ["3c9d7e21-5b4a-4f0e-8d2c-1a6b9e7f3d02"],
      }

      r = requests.post(f"{BASE}/10dlc/campaigns", headers=HEADERS, json=campaign)
      r.raise_for_status()
      print(r.json()["id"], r.json()["stage"])
      ```

      ```javascript Node theme={null}
      const BASE = "https://api.vobiz.ai/api/v1/sms";
      const headers = {
        "X-Auth-ID": "MA_XXXXXXXX",
        "X-Auth-Token": "YOUR_AUTH_TOKEN",
        "Content-Type": "application/json",
      };

      const campaign = {
        brandId: "9b2e1c40-8a3d-4f5e-9c1a-7d6b2e8f4a01",
        name: "Account alerts",
        useCases: ["ALERTS"],
        messageTypes: ["SMS"],
        programSummary: "Acme sends account and billing alerts to customers who opt in on the Acme dashboard. Message frequency varies. Reply STOP to opt out, HELP for help.",
        exampleMessages: [
          "Acme: Your invoice #4821 is due on 30 Oct. View it at https://example.com/billing. Reply STOP to opt out, HELP for help.",
        ],
        confirmationMessage: "Acme: You are subscribed to account alerts. Msg frequency varies. Msg & data rates may apply. Reply HELP for help, STOP to opt out.",
        helpMessage: "Acme: For help email support@example.com. Reply STOP to opt out.",
        stopMessage: "Acme: You have been unsubscribed and will receive no more messages.",
        optIns: { web: { url: "https://example.com/signup", callToAction: "By checking this box you agree to receive account alerts from Acme by SMS. Msg & data rates may apply. Reply STOP to opt out." } },
        customerCarePhone: "+14155550100",
        customerCareEmail: "support@example.com",
        termsAndConditionsUrl: "https://example.com/terms",
        privacyPolicyUrl: "https://example.com/privacy",
        embeddedLink: true,
        supportingDocuments: ["3c9d7e21-5b4a-4f0e-8d2c-1a6b9e7f3d02"],
      };

      const res = await fetch(`${BASE}/10dlc/campaigns`, {
        method: "POST",
        headers,
        body: JSON.stringify(campaign),
      });
      if (!res.ok) throw new Error(await res.text());
      const created = await res.json();
      console.log(created.id, created.stage);
      ```
    </CodeGroup>

    The response is `201` with the [campaign object](#the-campaign-object).
  </Step>

  <Step title="Submit it for review">
    [`POST /10dlc/campaigns/{id}/register`](/docs/sms/api/10dlc/register-campaign) submits the campaign. The body is optional: `{"priorityId": "<uuid>"}` selects one of the registration priority options listed by [`GET /10dlc/campaigns/priorities`](/docs/sms/api/10dlc/campaign-priorities). A non-UUID value returns `400 {"error": "invalid request: priorityId must be a UUID"}`. The response is `200` with the refreshed campaign.
  </Step>

  <Step title="Poll the network statuses">
    [`GET /10dlc/campaigns/{id}/network-statuses`](/docs/sms/api/10dlc/campaign-network-statuses) returns one entry per US carrier network with `network` (for example `T_MOBILE`, `ATT`, `VERIZON`), `state` (`ACTIVE` once approved), and, where the network assigns them, `messageClass`, `throughput` and `brandTier`. [`GET /10dlc/campaigns/{id}`](/docs/sms/api/10dlc/get-campaign) refreshes `stage` and `rejectionReasons` from the registry before returning. Subscribe to `10dlc.campaign.updated` on the [WebSocket](/docs/sms/websocket) to be told when the stage changes.
  </Step>

  <Step title="Add numbers">
    Once `stage` is `REGISTERED`, attach the numbers that will send under this campaign with [`POST /10dlc/campaigns/{id}/numbers`](/docs/sms/api/10dlc/add-campaign-numbers):

    ```json theme={null}
    {
      "numbers": ["14155550100"],
      "numberKeys": []
    }
    ```

    Pass at least one of `numbers` (digits, country code first, no `+`) or `numberKeys` (the `numberKey` from [`GET /numbers/available`](/docs/sms/api/numbers/search-available-numbers)). Sending neither returns `400 {"error": "invalid request: numbers or numberKeys is required"}`. The response is `200 {"status": "ok"}`. [`GET /10dlc/campaigns/{id}/numbers`](/docs/sms/api/10dlc/list-campaign-numbers) lists what is attached according to the registry.
  </Step>

  <Step title="Send">
    [`GET /numbers`](/docs/sms/api/numbers/list-numbers) now shows the number with `registration.status: approved`. Send with [`POST /messages`](/docs/sms/api/messages/send-message) using that number as `from`.
  </Step>
</Steps>

## Manage a campaign

| Action | Endpoint | Notes |
| - | - | - |
| Update a draft or rejected campaign | [`PUT /10dlc/campaigns/{id}`](/docs/sms/api/10dlc/update-campaign) | Full body as create. The registry accepts edits while the stage is `DRAFT` or `REJECTED`. `campaignType` cannot change. |
| Push changes to a registered campaign | [`POST /10dlc/campaigns/{id}/update-registration`](/docs/sms/api/10dlc/update-campaign-registration) | Body `{"numbers": [...], "numberKeys": [...]}`, at least one non-empty. Submits the number changes to the registry for an approved campaign. |
| Appeal a rejection | [`POST /10dlc/campaigns/{id}/appeal`](/docs/sms/api/10dlc/appeal-campaign) | Body `{"reason": "..."}` is required (`400 {"error": "invalid request: reason is required"}`). Explain what you corrected and point at the evidence. |
| Deregister | [`POST /10dlc/campaigns/{id}/deregister`](/docs/sms/api/10dlc/deregister-campaign) | No body. Withdraws the campaign from the registry. Numbers attached to it lose their approval. |
| Remove numbers | [`DELETE /10dlc/campaigns/{id}/numbers`](/docs/sms/api/10dlc/remove-campaign-numbers) | Same body as add. `200 {"status": "ok"}`. |
| Delete | [`DELETE /10dlc/campaigns/{id}`](/docs/sms/api/10dlc/delete-campaign) | `204`. The registry accepts deletion of `DRAFT`, `REJECTED` and `DEREGISTERED` campaigns; deregister a registered campaign first. |
| List | [`GET /10dlc/campaigns`](/docs/sms/api/10dlc/list-campaigns) | Every campaign on the account, including toll-free verifications, as an array, newest first. |

<Warning>
  Deregistering or deleting a registered campaign stops A2P delivery from every number attached to it. Do this only with your own credentials and when you intend to stop sending.
</Warning>

## The campaign object

```json theme={null}
{
  "id": "a1f0c2d3-4e5b-4c6d-8e7f-9a0b1c2d3e4f",
  "accountId": "MA_XXXXXXXX",
  "brandId": "9b2e1c40-8a3d-4f5e-9c1a-7d6b2e8f4a01",
  "name": "Account alerts",
  "campaignType": "TEN_DIGIT_LONG_CODE",
  "stage": "REGISTERED",
  "programSummary": "Acme sends account and billing alerts ...",
  "confirmationMessage": "Acme: You are subscribed to account alerts. ...",
  "helpMessage": "Acme: For help email support@example.com. Reply STOP to opt out.",
  "stopMessage": "Acme: You have been unsubscribed and will receive no more messages.",
  "customerCarePhone": "+14155550100",
  "customerCareEmail": "support@example.com",
  "exampleMessages": ["Acme: Your invoice #4821 is due on 30 Oct. ..."],
  "termsAndConditionsUrl": "https://example.com/terms",
  "privacyPolicyUrl": "https://example.com/privacy",
  "useCases": ["ALERTS"],
  "messageTypes": ["SMS"],
  "optIns": { "web": { "url": "https://example.com/signup", "callToAction": "..." } },
  "lowVolume": false,
  "ageGated": false,
  "directLending": false,
  "embeddedLink": true,
  "embeddedPhone": false,
  "numbers": ["14155550100"],
  "lastSyncedAt": "2026-10-17T08:46:48.342867Z",
  "createdAt": "2026-10-06T14:28:25.542048Z",
  "updatedAt": "2026-10-14T17:19:03.970547Z"
}
```

### Stage values

`stage` is a string set by the registry. Treat it as an open list; these are the values you will see most often:

| Stage | Meaning |
| - | - |
| `DRAFT` | Created on Vobiz, not yet submitted |
| `SUBMITTED`, `IN_REVIEW` | Under review by the registry and carriers |
| `APPEALED` | An appeal is pending |
| `REGISTERED` | Approved. Numbers attached to the campaign can send A2P traffic |
| `REGISTERED_PENDING_UPDATE` | Approved, with an update under review |
| `REGISTERED_PENDING_DEREGISTRATION` | A deregistration is in progress |
| `REJECTED`, `REJECTED_EXTERNALLY` | Rejected by the registry or by a carrier. Read `rejectionReasons` |
| `DEREGISTERED` | Withdrawn |
| `ARCHIVED`, `BLOCKED`, `SUSPENDED` | Closed or suspended by the registry |

When a campaign is rejected, `rejectionReasons` carries the registry's feedback: a `rejectionDate`, a `rejectionReasons` array of plain-text reasons, and `rejectionDetails` entries with `errorCode`, `description`, `rejectionCategory` and, when present, `recommendedAction`.

## What to expect

* Review involves the registry and each carrier separately, so `network-statuses` can show some carriers approved while others are still pending. The campaign `stage` reflects the overall outcome.
* Review time varies with the use case, the brand's vetting tier and the reviewers' queue. Register before you need to send.
* A campaign under a brand that is not `ACTIVE` is rejected with a reason pointing at the brand. Fix the [brand](/docs/sms/compliance/us-10dlc-brands) and register the campaign again.
* Errors from the registry return `422` with `providerError`, an opaque diagnostic string you can quote to support. See the [error reference](/docs/sms/errors).

## Next steps

<CardGroup cols={2}>
  <Card title="Toll-free verification" icon="phone" href="/docs/sms/compliance/us-toll-free">
    The equivalent flow for 8XX numbers.
  </Card>

  <Card title="Campaign endpoints" icon="code" href="/docs/sms/api/10dlc/create-campaign">
    Full request and response schemas.
  </Card>
</CardGroup>

## Build it with the Messaging API

<CardGroup cols={2}>
  <Card title="Campaign endpoints" icon="code" href="/docs/sms/api/10dlc/create-campaign">
    Create, register and attach numbers by API.
  </Card>

  <Card title="WebSocket events" icon="bolt" href="/docs/sms/websocket">
    Get `10dlc.campaign.updated` as review progresses.
  </Card>

  <Card title="Sending SMS" icon="message" href="/docs/sms/channels/sms">
    Send from your registered numbers.
  </Card>

  <Card title="Messaging webhooks" icon="webhook" href="/docs/sms/webhooks">
    Track delivery once traffic flows.
  </Card>
</CardGroup>


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