Manage phone numbers

View as Markdown

Every message and call is sent from a Dial phone number. Your first number is included with onboarding; you can list your numbers and purchase more at any time.

List your numbers

Each number has an id (used as fromNumberId), the number itself in E.164, its country, its capabilities, an optional nickname (a human-readable label you choose), and its inboundInstruction (the system prompt its AI voice agent uses on inbound calls).

$dial number list --json

Purchase a number

Request a new number, optionally in a specific area code. Only US numbers can be provisioned at this time. An inboundInstruction is optional — it becomes the new number’s inbound voice-agent prompt, and a default greeting is used if you omit it.

Every purchase requires explicitProgrammaticConsent (CLI: --explicit-programmatic-consent): a short, human-readable attestation that the account holder has explicitly consented to provisioning this number programmatically. It’s stored on the number for the provisioning audit trail. Omitting it is rejected with 400.

$dial number purchase \
> --inbound-instruction "You are my receptionist. Greet the caller and find out what they need." \
> --explicit-programmatic-consent "Account holder approved via our signup flow" \
> --area-code 415 --json

The purchased number is returned with its id. Pass that id as fromNumberId when you send a message or place a call.

Purchase an iMessage number

Add --include-imessage (CLI), includeImessage: true (Node), or include_imessage=True (Python) — or include imessage in capabilities over REST — to provision an iMessage number. Two things differ from a standard number:

  • Pay-as-you-go only. iMessage numbers can’t be added to a flat-rate subscription; an account on a subscription is rejected with 403. Switch to pay-as-you-go to add one.
  • Messaging is free. Every message from an iMessage number — the iMessage itself, and any automatic RCS/SMS fallback — is billed at $0 (it appears in your usage as the imessage.message fare). You pay only the number’s monthly ownership; the per-message SMS tiers don’t apply. Calls are billed at the usual per-minute rate.
  • Asynchronous setup. The number is returned immediately with setupStatus: provisioning. Poll List your numbers until its setupStatus is ready before you send or call from it. (areaCode is ignored for iMessage numbers.)
$dial number purchase \
> --include-imessage \
> --inbound-instruction "You are my receptionist. Greet the caller and find out what they need." \
> --explicit-programmatic-consent "Account holder approved via our signup flow" \
> --json

Set the inbound instruction

Change how a number’s AI voice agent behaves on inbound calls at any time. The change takes effect on the next inbound call; calls in progress are unaffected.

$dial number set +14155550123 \
> --inbound-instruction "You are ACME's receptionist. Greet the caller and route them."

The CLI takes the number in E.164 and resolves it to its id for you; the REST API takes the number id in the path.

Set the inbound language

By default the agent detects the language from the caller’s country prefix on each inbound call, and handles both that language and en-US. Set the number’s inboundLanguage — a BCP-47 tag such as es-ES — to pin every inbound call to a single language instead. Clear it (empty string in the CLI, null over REST) to go back to per-call detection. Takes effect on the next inbound call.

$dial number set +14155550123 --inbound-language es-ES

You can also set it at purchase time with --inbound-language (REST: inboundLanguage).

Give a number a nickname

Attach a human-readable label to a number — useful once an account holds several (e.g. “Support line”, “Sales — EU”). Nicknames are free text up to 100 characters and don’t have to be unique. Clear one by setting it to an empty string (CLI) or null (REST).

$dial number set +14155550123 --nickname "Support line"

nickname, inboundInstruction, and inboundLanguage all go through the same update call — send any subset of them in one request.

Set the iMessage display identity

Numbers with the imessage capability can carry a display identity — a first name, last name, and avatar photo shown beside the number’s messages in recipients’ Messages apps. Names are up to 30 characters each; clear one by setting it to an empty string (CLI) or null (REST). The photo accepts jpeg, png, gif, or webp up to 5 MB — a square image of 512×512 or larger is recommended (it’s shown as a circle). Photos can be replaced but not removed. Setting any identity field on a number without the imessage capability is rejected with 400.

Upload the photo as a multipart/form-data file part, or pass a public image URL as avatarUrl (JSON or multipart) for Dial to download server-side. Either way, Dial mirrors the photo into its own storage and returns its stable public URL as the number’s avatarUrl. Identity changes can take a few minutes to propagate to recipients’ devices.

$dial number set +14155550123 --first-name Maya --last-name Chen --avatar ./avatar.png

Register a US number for 10DLC

US carriers block outbound SMS and MMS sent from an unregistered 10-digit number to a US phone number. It isn’t filtering or a delay — the message doesn’t arrive. Registering the number for 10DLC lifts the block.

What the block does not affect: inbound texts to your number, voice calls in either direction, and messaging to numbers outside the US. Those work whether or not the number is registered.

Which numbers this applies to

A number is eligible when it’s US, has the sms capability, and does not have the imessage capability — iMessage numbers send over Apple Messages for Business rather than carrier SMS, so 10DLC never applies to them. Registration is currently offered on pay-as-you-go accounts.

Read tenDlc on the number to know where you stand. It’s null when 10DLC doesn’t apply, and otherwise carries a status:

statusMeaning
not_registeredNothing submitted yet — outbound US SMS/MMS from this number is blocked.
in_reviewSubmitted; Dial is checking the details.
with_carrierFiled with the carrier registry. Decisions usually land in 3–5 business days.
approvedRegistered — the number can send to US numbers.
rejectedChanges needed. reason says exactly what; fix it and resubmit for free.

What it costs

$25.00 one-time per number, taken from your credit balance when the submission is accepted. A balance below the fee is rejected with 402. Resubmitting after a rejection is free — a number is charged at most once, ever.

Submitting

A registration has two halves, mirroring what the carrier registry registers: a brand — who is registering, the identity carriers vet — and a campaign — what you send and how people agreed to receive it. Your number is registered by joining the campaign.

Register as a sole proprietor if you operate under your own name and have no EIN: fewer fields, lower throughput, quicker approval. Register as a business if you’re a registered company with an EIN. The full field list for each is in the API reference, under POST /api/v1/numbers/{id}/10dlc.

Carriers require a privacy policy and a terms page on every campaign, and they read them. A business gives its own privacyPolicyUrl and termsUrl, and reviewers expect to find them on the websiteUrl you registered — a policy somewhere unrelated to the brand is a rejection. A sole proprietor usually has no website, so both are optional: leave them out, send "acceptPublishedNotice": true, and Dial publishes a privacy notice and a terms page for the brand — written from what you submitted, naming you as the operator of the messaging program — and registers those URLs. Read them back from the registration and link them wherever people opt in. Your own URLs, if you send them, always win.

One field is easy to get wrong: a sole proprietor gives a vertical — the trade they operate in — while a business gives a businessIndustry. They look interchangeable and aren’t. The registry validates them against different vocabularies, so PROFESSIONAL is a vertical while PROFESSIONAL_SERVICES is an industry, and several industries have no vertical at all. Take the value from the list for the field you’re actually sending.

cURL
$curl -X POST https://api.getdial.ai/v1/numbers/pn_123/10dlc \
> -H "Authorization: Bearer sk_live_..." \
> -H "Content-Type: application/json" \
> -d '{
> "kind": "business",
> "brand": {
> "brandName": "Northwind Supply Co.",
> "firstName": "Maya", "lastName": "Chen",
> "email": "maya@northwind.io", "phone": "+14155550110",
> "street": "480 Bryant St", "city": "San Francisco", "country": "US", "state": "CA", "zip": "94107",
> "businessType": "Limited Liability Corporation",
> "businessIndustry": "RETAIL",
> "registrationIdType": "EIN", "registrationNumber": "84-3921776",
> "websiteUrl": "https://northwind.io",
> "jobPosition": "Other", "businessTitle": "Head of Operations",
> "businessRegionsOfOperation": "USA_AND_CANADA", "companyType": "private"
> },
> "campaign": {
> "useCase": "CUSTOMER_CARE",
> "description": "We text customers who placed an order to confirm delivery windows and let them reschedule. Every recipient checked the SMS box at checkout.",
> "messageFlow": "Customers tick an unchecked SMS consent box at checkout under the heading Text me delivery updates, beside message frequency and STOP instructions.",
> "samples": [
> "Northwind Supply: your order #40218 is out for delivery today between 2-4pm. Reply STOP to opt out.",
> "Northwind Supply: thanks for your order! Track it at northwind.io/track. Reply STOP to unsubscribe."
> ],
> "privacyPolicyUrl": "https://northwind.io/privacy",
> "termsUrl": "https://northwind.io/terms",
> "containsUrls": true, "containsPhones": false
> }
> }'

Then read the registration back — brand, campaign, and where it stands — with GET /api/v1/numbers/pn_123/10dlc.

The number you register is always a US number — that’s what 10DLC is — but your business doesn’t have to be US-based. A business may be registered from any country the registry accepts, using its own country’s tax ID; give the country of your registered address and its state — the two-letter code in the US and Canada, the region name elsewhere. Sole proprietor registration is the exception: it’s available in the US and Canada only.

The brand’s phone may not be one of your Dial numbers. Carriers won’t verify a number issued by a messaging provider, so use a mobile the person named on the registration answers directly. For a sole proprietor that number receives a verification text — reply YES within 24 hours or the registration is turned down.

Carriers reject vague answers. Say concretely who is messaged, why, and how they agreed to it; keep marketing language out of it. Sample messages must name your brand and end with an opt-out instruction — at least two are required, and repeating one is fine if that’s the only message you’ll ever send. If you write your own privacy policy, it has to state that mobile information and messaging consent are never shared or sold to third parties or affiliates for marketing — the single most common reason a campaign is turned down. If your registration is rejected, the reason tells you precisely what to change — a resubmission costs nothing.

Dial emails you when the registration is approved or rejected. Once approved, keep your message content matching what you described — carriers audit it, and violations can suspend the number.

Release a number, and what it costs

Releasing a number returns it to the carrier and removes it from your account, immediately and irreversibly. A released number can’t be reclaimed.

On pay-as-you-go there’s nothing more to it — you simply stop being charged the monthly ownership fee for it.

On a flat-rate subscription, a release lowers the subscription by one number and Stripe prorates the change. The quantity never drops below one number, though, which means:

  • Releasing your last number leaves the subscription active at the single-number rate — it isn’t cancelled. Cancel the subscription itself (POST /api/v1/billing/subscription/cancel) to stop paying.
  • While you hold no numbers, the next number you provision is free — the subscription is already paying for one, so there’s no prorated charge. Holding zero numbers and holding one cost exactly the same.
  • The new number is covered by the subscription as soon as the purchase returns, so you can send and call from it right away.

Swapping a number — release, then provision a replacement — is therefore free on a subscription, however many times you do it.

iMessage numbers are pay-as-you-go only and are never part of a flat-rate subscription, so none of the quantity rules above apply to them.

Non-payment and number release

Each number carries a small monthly ownership fee. On pay-as-you-go, that fee is drawn from your account balance, which is allowed to go negative — so a lapsed top-up doesn’t interrupt service immediately.

You have a 30-day grace period, measured from the moment your balance first goes negative. During grace, ownership fees keep being charged and your numbers keep working. Topping your balance back to zero or above resets the grace period.

If your balance is still negative when the grace period ends, Dial stops charging for ownership and instead releases your numbers — returning them to the carrier and removing them from your account. Once the grace period ends, all of your numbers are released together (Dial checks daily), so add credit before the grace period ends to keep them. A released number is gone and cannot be reclaimed; purchase a new one to continue.

Numbers covered by an active subscription are unaffected by your balance — they are never released for non-payment.