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

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.