---
title: "Create an SMS purchase quote"
description: "Price a carrier purchase and bind exactly what it buys: a 10DLC brand registration (or the paid resubmission of one carriers sent back), brand vetting, a 10DLC campaign registered from a messaging program with its local number, the number of an approved campaign that has none, or a local number that needs no registration (Canada). `POST /api/v1/sms/quotes`"
url: https://www.unitpost.com/docs/sms/post-sms-quotes
section: "SMS API reference"
updated: 2026-10-13
---
# Create an SMS purchase quote

`POST /api/v1/sms/quotes`

Price a carrier purchase and bind exactly what it buys: a 10DLC brand registration (or the paid resubmission of one carriers sent back), brand vetting, a 10DLC campaign registered from a messaging program with its local number, the number of an approved campaign that has none, or a local number that needs no registration (Canada). Nothing is charged or submitted. The answer names the product, `due_now_cents` (charged at the confirm), `monthly_cents` (from when the number leases or carriers approve the campaign, then monthly), the line items and `expires_at` (10 minutes), and carries a single-use `confirm_token`, shown once. Show the person the price, then [Confirm an SMS purchase quote](https://www.unitpost.com/docs/sms/post-sms-quotes-id-confirm). A toll-free number needs an opt-in evidence file a person provides: `409 dashboard_required`, with `error.dashboard_url`. Something already registered or under review, a number the plan can't hold, a failing card or a fee the plan can't fit are refused here, before a price is shown. Requires the `sms:manage` capability.

## Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `product` | enum | yes | What to buy. `ten_dlc_brand_registration` registers a brand with US carriers (or resubmits one they sent back; the fee is the resubmission's). `ten_dlc_brand_vetting` vets an approved brand for higher throughput. `ten_dlc_campaign` registers a 10DLC campaign from a messaging program, with its local number, which leases once carriers approve it. `ten_dlc_number` orders the number of an approved campaign that has none. `long_code_number` orders a local number that needs no registration (`country: "CA"`). `toll_free_number` answers `409 dashboard_required`: it needs an opt-in evidence file a person provides. One of: `ten_dlc_brand_registration`, `ten_dlc_brand_vetting`, `ten_dlc_campaign`, `ten_dlc_number`, `long_code_number`, `toll_free_number`. |
| `brand_id` | string | no | The SMS brand (`sbrand_…`). |
| `registration_id` | string | no | `ten_dlc_number`: the approved 10DLC campaign registration (`sreg_…`). |
| `messaging_program_id` | string | no | `ten_dlc_campaign`: the messaging program (`prog_…`) the campaign is registered from. |
| `country` | string | no | `long_code_number`: the two-letter country (`CA`). |
| `display_name` | string | no | `long_code_number`: the number's name in the dashboard. |
| `brand_verification_email` | string | no | `ten_dlc_brand_registration`: who at the company follows the registry's email link, on the brand website's domain. Required for a public company, or when carriers ask for it; else the brand's saved one. |

## Response fields (201)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | string | yes | — |
| `id` | string | yes | The quote (`squote_…`). |
| `product` | enum | yes | One of: `ten_dlc_brand_registration`, `ten_dlc_brand_vetting`, `ten_dlc_campaign`, `ten_dlc_number`, `long_code_number`, `toll_free_number`. |
| `status` | enum | yes | `open` until confirmed or `expires_at`; `ordered` once placed; `pending` while the outcome is unknown (the carrier didn't answer: a fee due now is held, monthly fees are committed, and it settles to `ordered` or `failed` from the billing ledger, so read it again; don't buy the same thing meanwhile); `failed` when the confirm bought nothing (nothing was charged; quote again). One of: `open`, `expired`, `confirming`, `ordered`, `pending`, `failed`. |
| `label` | string | yes | What is bought, as the dashboard names it. |
| `brand_id` | string \| null | yes | — |
| `registration_id` | string \| null | yes | The registration the order is for (a brand registration, or the campaign whose number it is). |
| `messaging_program_id` | string \| null | yes | — |
| `country` | string \| null | yes | — |
| `due_now_cents` | integer | yes | Charged at the confirm, from the plan's allowance (one-time fees). |
| `monthly_cents` | integer | yes | Charged when the number leases or carriers approve the campaign, then every month. |
| `currency` | string | yes | — |
| `line_items` | object[] | yes | — |
| `covered_by_unitpost` | boolean | yes | This workspace's carrier fees are covered by Unitpost: nothing is charged. |
| `expires_at` | string | yes | Confirm before this (quotes last 10 minutes). |
| `created_at` | string | yes | — |
| `confirmed_at` | string \| null | yes | — |
| `order` | object \| null | yes | What the confirmed order made; null until then. |
| `confirm_token` | string | no | Only in the create response, once: pass it to the confirm. Stored only as a hash; a lost token means a new quote. |

## Responses

| Status | Description |
| --- | --- |
| 201 | The quote, with its confirm token. |
| 400 | The body isn't JSON. |
| 401 | Missing or invalid API key. |
| 402 | The plan can't fit the fee (`sms_allowance_short`, `sms_plan_too_small`). |
| 403 | Insufficient scope, SMS isn't on this plan (`limit_reached`), the account is under review (`account_under_review`), or the card is failing (`sms_payment_failed`, `sms_full_discount`). |
| 404 | The brand, registration or messaging program isn't in this workspace, or SMS is not enabled. |
| 409 | Nothing to buy (already registered, under review, or the number exists), an order for the same purchase still in flight (`conflict`, naming its quote: follow it), the plan can't hold another number (`number_limit_reached`), a pending plan change, or a step for a person (`dashboard_required`, with `error.dashboard_url`). |
| 422 | A missing or misplaced field for the product, a messaging program carriers would refuse, an unknown key. |
| 429 | Too many quotes; honor Retry-After. |

## Example request

```bash
curl -X POST 'https://www.unitpost.com/api/v1/sms/quotes' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'User-Agent: my-app/1.0' \
  -H 'Content-Type: application/json' \
  -d '{ }'
```

## Example response (201)

```json
{
  "object": "sms_quote",
  "id": "id_123",
  "product": "ten_dlc_brand_registration",
  "status": "open",
  "label": "string",
  "brand_id": "brand_123",
  "registration_id": "registration_123",
  "messaging_program_id": "messaging_program_123",
  "country": "string",
  "due_now_cents": 0,
  "monthly_cents": 0,
  "currency": "usd",
  "line_items": [
    {
      "fee_code": "string",
      "label": "string",
      "amount_cents": 0,
      "cadence": "one_time",
      "starts_when": "on_confirmation"
    }
  ],
  "covered_by_unitpost": false,
  "expires_at": "2026-01-01T00:00:00.000Z",
  "created_at": "2026-01-01T00:00:00.000Z",
  "confirmed_at": "2026-01-01T00:00:00.000Z",
  "order": {
    "registration_id": "registration_123",
    "number_id": "number_123",
    "status": "queued"
  },
  "confirm_token": "string"
}
```

## Links

- HTML reference (with Node.js, Python, Ruby, PHP, Laravel, Go, Java, Rust, .NET and CLI examples): https://www.unitpost.com/docs/sms/post-sms-quotes
- OpenAPI 3.1 (full schemas): https://www.unitpost.com/api/v1/openapi.json
