---
title: "SMS quotes"
description: "Buy carrier resources by API: quote (`sms:manage`, nothing charged), show the person the price, then confirm with the quote's single-use token and an `Idempotency-Key` (`sms:purchase`, which no key preset includes). API purchases count against a monthly cap the workspace owner sets in the dashboard; with none set they are refused. A toll-free number, releasing a number and identity documents stay in the dashboard."
url: https://www.unitpost.com/docs/api/sms-quotes
section: API reference
updated: 2026-10-13
---
# SMS quotes

## SMS quotes

> Buy carrier resources by API: quote (`sms:manage`, nothing charged), show the person the price, then confirm with the quote's single-use token and an `Idempotency-Key` (`sms:purchase`, which no key preset includes). API purchases count against a monthly cap the workspace owner sets in the dashboard; with none set they are refused. A toll-free number, releasing a number and identity documents stay in the dashboard.

Full schemas: [OpenAPI 3.1](https://www.unitpost.com/api/v1/openapi.json). HTML reference: https://www.unitpost.com/docs/sms#sms-quotes.

## Operations

### `POST /api/v1/sms/quotes`

Create an SMS purchase quote

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.

Reference: https://www.unitpost.com/docs/sms/post-sms-quotes ([Markdown](https://www.unitpost.com/docs/sms/post-sms-quotes.md))

### `GET /api/v1/sms/quotes/{id}`

Retrieve an SMS purchase quote

A quote's price and state: `open` until confirmed or expired, `ordered` with what the order made (`order.registration_id` or `order.number_id`), `pending` while the outcome is unknown (the carrier didn't answer: a fee due now is held, monthly fees are committed), or `failed` when the confirm bought nothing (nothing was charged). A `pending` quote settles from the billing ledger when it is read: `ordered` once the fee is captured or the number or campaign goes live, `failed` once the fee is refunded or the commitments are released. An `ordered` number or campaign whose commitments are released before it ever goes live reads `failed` too and stops counting against the cap. Never the confirm token. Requires the `sms:read` capability.

Reference: https://www.unitpost.com/docs/sms/get-sms-quotes-id ([Markdown](https://www.unitpost.com/docs/sms/get-sms-quotes-id.md))

### `POST /api/v1/sms/quotes/{id}/confirm`

Confirm an SMS purchase quote

Buy what the quote binds, with its single-use `confirm_token`. It charges the workspace: confirm only after the person agreed to the quoted price. Requires an `Idempotency-Key`: a retry with the same key answers what the first call answered and never charges twice. The order runs exactly as in the dashboard: the plan's purchase rules, the one-time fee taken from the plan's allowance before carriers are called and refunded if they refuse the submission, the monthly fee from when the number leases or carriers approve the campaign. Every API purchase counts against the monthly API spend cap the workspace owner sets in the dashboard (the fee due now plus the first month, per UTC month); with no cap set, API purchases are refused. The owner gets an email per purchase, and the activity log names the key. Refusals charge nothing: a changed price (`price_changed`), an expired quote (`quote_expired`), a brand or messaging program edited since (`quote_stale`), a quote already used (`quote_already_used`), an order for the same purchase still in flight (`conflict`, naming its quote). These refusals are answered before the shared hourly limits are spent. A confirm that recorded nothing leaves the quote open (and frees its `Idempotency-Key`); one that reached carriers spends it: `failed` when carriers refused it (quote again), `pending` when their answer is unknown (follow the quote; don't buy the same thing meanwhile). Requires the `sms:purchase` capability.

Reference: https://www.unitpost.com/docs/sms/post-sms-quotes-id-confirm ([Markdown](https://www.unitpost.com/docs/sms/post-sms-quotes-id-confirm.md))

## Related

- [SMS campaigns](https://www.unitpost.com/docs/api/sms-campaigns): Marketing SMS to a segment from a published SMS template. Draft → send now or schedule, with pause, resume, cancel and reschedule. Sends run the same checks as the dashboard; consent and recipient-local quiet hours apply per recipient. Paid plans only, like every SMS send.
- [SMS topics](https://www.unitpost.com/docs/api/sms-topics): SMS subscription categories recipients can opt out of, independent from email topics. STOP still opts a number out of every SMS.
- [API keys](https://www.unitpost.com/docs/api/api-keys): Create and revoke the API keys your integrations authenticate with. Each key has a scope: `full`, `sending`, `read_only`, or an explicit `capabilities` list (paid plans for `read_only` and custom lists); a request outside the key's capabilities returns 403 `insufficient_scope`. No key can manage keys, the team, the workspace or billing. Creating and revoking keys is session-gated (dashboard cookie + `apikeys:manage`) and NOT usable with a Bearer API key; listing keys and a key's usage take a key or app holding `apikeys:read`, which no preset includes.
