Skip to main content
photon project platform manages the resources a project sends and receives on — SMS numbers, iMessage lines, email domains, WhatsApp Business numbers, and voice routing. Browse the automatic command reference.

List inventory

Each list command asks for a currently enabled ability, so one resource can appear in more than one list — a line that does both iMessage and voice shows up in both.
SMS, email, and iMessage lists also fetch pending provisioning work and show it in a separate section when there is any. Voice lists resources only.
nextPageToken applies to resources only — provisioning operations are paginated for you.

Buy a number

sms purchase provisions one US local SMS number. --country US is the default; use --area-code 415 to request a particular area code. imessage purchase provisions one dedicated iMessage line. Both confirm first unless you pass --force:
An idempotency key identifies one logical resource forever. Reusing a key resumes that same purchase rather than buying a second number. Use a fresh key when you want another resource.
The CLI sends the purchase once, then polls the resulting operation until it succeeds, fails, or is cancelled. iMessage provisioning can take hours, so there is no client-side timeout. Success returns the resource:
Ctrl-C stops the local wait only — the purchase keeps running on Photon. The journal keeps the remote operation ID, so photon operation replay <local-id> resumes polling without buying anything else. See Recoverable operations.

Release an SMS number

sms delete checks that the resource still has SMS ability, then releases it:
There is no dedicated iMessage or voice release command.

Cancel provisioning in progress

platform operation cancel asks Photon to withdraw an in-progress remote provision:
Pending email-domain and dedicated iMessage provisioning can be cancelled; SMS provider orders cannot. Photon returns OPERATION_NOT_CANCELLABLE if the operation is past the point of no return or finished first. Cancelling here does not remove the local journal record.

Connect an email domain

email connect starts SES and DNS verification. The CLI normalizes case, a trailing root dot, and internationalized names before sending, and rejects schemes, paths, ports, wildcards, IP addresses, and malformed labels locally:
It submits once, then polls until Photon publishes six DNS records and prints them straight away. If your DNS provider supports Domain Connect, the CLI also prints a signed automatic-setup URL and opens it in a browser — pass --no-browser to print it without opening. The manual records are always printed as a fallback. In human output the command then keeps waiting until Photon verifies the records. Ctrl-C or --no-wait stops the local wait without cancelling remote verification. --json returns as soon as DNS is prepared, so automation gets exactly one connection object to act on. It contains dnsRecords and the remote operation, plus automaticSetup with applyUrl, dnsProviderId, and providerDisplayName when Domain Connect is available. If verification already finished, it also contains the resulting resource. Re-read the published instructions at any time with the remote operation ID — this hits Photon directly and needs neither the original idempotency key nor the local journal:
Disconnect by resource ID:

iMessage shared-line assignments

A dedicated iMessage line can be shared. An assignment binds one of your users to the line so their messages are attributed to them:
--phone-number is required and must be E.164. The name and email fields are optional and only affect how the user is presented. assignment list shows active assignments. Add --include-released to see released ones too:
Releasing frees the user’s slot on the line and asks for confirmation first:
JSON uses {"assignments": [...]} for lists and {"assignment": ...} for a single record.

WhatsApp Business

Each project has one connected WhatsApp Business account. The account list command returns zero or one account and includes its capacity, review status, restrictions, and alerts. Account pagination is no longer supported. List the connected account and active senders:

Human onboarding wizard

Run number add without --source in an interactive terminal. The wizard first asks for one simple choice: Bring Your Own Number or Use a Photon SMS Number.
  • Bring Your Own Number opens focused dashboard onboarding and stops. Finish Meta Embedded Signup and verification in the browser; the CLI does not wait or refresh inventory.
  • Use a Photon SMS Number lets you select an eligible existing number or buy a new US local SMS number. Purchased numbers remain in the project if you stop onboarding later.
  • The wizard always asks which connected WABA to use, even when there is only one. Selecting a connected WABA provisions directly. Selecting Connect another WABA with Meta opens Embedded Signup while the terminal retrieves and displays the SMS OTP.

Automation and agent flows

Automation must pass --source; --json without it fails instead of opening the human wizard. Bring-your-own-number onboarding is a browser handoff:
The command attempts to open the dashboard and returns one handoff object with its URL and next steps. Embedded Signup requires human browser interaction, and the dashboard owns verification and final connection. Use --no-browser when an agent cannot launch a browser; the same guide and URL are returned with browserAttempted: false.
Connect an eligible Photon SMS number directly to an already-connected WABA:
Photon owns the SMS-code request, verification, and Meta registration for this direct API path. The CLI records the accepted operation and polls it to a terminal result, so interrupted work can be resumed with photon operation replay <local-operation-id>. To use that Photon number with a new or different WABA, hand it to the dashboard instead:
This command validates that the number is active, SMS-capable, belongs to the project, and is not already linked. It then opens the dashboard and exits. The dashboard owns both Embedded Signup and OTP display; use the dashboard or rerun the interactive CLI if you need guided OTP handling. No provisioning mutation or local operation record is created by this handoff. --new-waba and --waba-id are mutually exclusive. Photon source always requires --voip-resource-id. BYON rejects WABA, Photon-resource, display-name, and idempotency flags. --no-browser applies only to browser handoffs.

WhatsApp sender JSON

WhatsApp sender output uses Meta and Photon’s explicit field names. The old phoneNumber and verifiedName aliases are not emitted:
number list displays phone number, display name, name status, quality, Photon source, and resource ID. Deletion confirms against displayPhoneNumber:

Voice routing profiles

Voice inventory and voice routing answer different questions. voice list shows resources with an active pstn_voice ability. A profile describes where Photon should send an inbound call once that check passes.
A project has one default profile and any number of additional profiles. Use the literal default with profile view, profile edit, or any inbound or outbound command. The CLI uses /profiles/default to read that profile, then sends directional changes through /profiles/{profileId} with the stable ID returned by the read. The default cannot be renamed, deleted, or reassigned, and it must exist before you can create an additional profile. A line with no override follows the project default. Assigning an additional profile creates an override; clearing it returns the line to the current default. profile edit can rename an additional profile and change media encryption on either an additional or the default profile. Inbound and outbound delivery have dedicated commands beneath the profile. Editing requires at least one of --name or --media-encryption; the default cannot be renamed.

SIP routes

A profile can carry one inbound SIP destination. The scheme picks the transport: bare sip: normalizes to UDP, ;transport=tcp selects TCP, ;transport=udp selects UDP, and sips: selects TLS. Photon owns the authoritative SIP syntax and public-host validation, so there are no separate transport options. Use --media-encryption auto or --media-encryption srtp on profile creation or editing; srtp requires encrypted media. Default creation needs only --default; Photon assigns the immutable name Default Profile. Additional profile creation requires --name. Both create direction-neutral profiles, so configure delivery afterward. Use inbound set to create or fully replace the destination, inbound edit to change selected fields, and inbound clear to disable inbound delivery:
Every command reads the current profile first and sends its latest version. Route changes on a profile with assigned lines require confirmation because they take effect for those lines immediately.

Endpoint credentials

Credentials are replaced as an atomic username and password pair. Passwords are never accepted as command-line options. With --sip-username and no --sip-password-file, an interactive terminal prompts with hidden input; non-interactive use reads the exact password from stdin. A password file is read exactly as written — spaces and trailing newlines are significant — so create it deliberately:
Responses show only the username; the password field is never returned. Passwords, SIP destinations, and profile bodies are redacted from --debug output and never written to the local journal. Omitting credential flags preserves the existing write-only secret, --clear-sip-credentials clears both fields, and --sip-username replaces the username and password together. The CLI never sends a masked password from a previous response back to Photon.

Outbound credentials

Outbound calling supports credential lifecycle commands and password-preserving authentication edits:
outbound enable creates the first credential for a profile with no active outbound credential. It defaults to SHA-256 and always sends that explicit choice to Photon. Select --digest-algorithm md5 only for weaker legacy compatibility. Photon supports MD5 over the UDP, TCP, and TLS transports returned in the outbound endpoint list. Enable output reports the active algorithm and each endpoint’s transport, host, and port so the SIP client can use the connection guidance returned by Photon. outbound edit changes the active Digest algorithm while preserving the username and password, including existing validity and rotation grace metadata. Use it to switch algorithms on an enabled profile. MD5 is the weaker legacy option; select it only for compatibility. Selecting SHA-256 can stop a PBX that does not support it from authenticating. The command asks for confirmation; use --force to skip the prompt in automation. The CLI resolves default to its stable profile ID and sends the current profile’s top-level version as expectedVersion. Even a same-value edit goes to Photon so the server can validate that version and return its authoritative result. A stale version produces VOICE_PROFILE_VERSION_CONFLICT: read the current profile and retry. VOICE_OUTBOUND_OPERATION_PENDING instead means credential setup or rotation must finish first. Resume the original enable or rotate request with its original idempotency key, or replay its recovery record; after it completes, read the current profile and retry the edit. Edit output contains the returned outbound connection and authentication metadata and profileVersion, with no password or display-once secret warning. Algorithm edits require no idempotency key, operation journal entry, or secret acknowledgement. outbound rotate replaces an existing credential while preserving the active Digest algorithm, so rotation intentionally has no algorithm flag; normal keeps the previous credential valid for one hour, while emergency removes that grace period. outbound revoke disables outbound calling. It does not delete the profile, inbound route, or line assignments. Enable and rotation output password at most once. Save it from stdout immediately: the CLI never persists it or writes it to debug output. Before the request, the CLI privately journals the exact profile reference, selected enablement digest algorithm, rotation mode, and expectedVersion. If the result is unresolved, rerunning the command with the same supplied idempotency key or using operation replay resends that exact body without rereading the now-mutated profile. An idempotent replay returns password: null; the mutation succeeded, but the display-once password cannot be reproduced. After successful output is flushed, the recovery record is removed. Do not rerun an already-confirmed success with its old key; deliberately rotate with the returned profileVersion and a new idempotency key to issue another password. An omitted idempotency key is generated for the current invocation. A supplied key must identify only that same unresolved enable or rotation action. The CLI also retries one transport interruption within an invocation with the same key and unchanged request body.

Assignments

The CLI reads each current assignment before changing it and sends its version, so a concurrent change surfaces as a conflict rather than a silent overwrite — view the assignment and repeat the command. One changed line uses the single-line endpoint; 2 to 100 use the atomic batch endpoint. Duplicate IDs and batches over 100 are rejected locally, and already-correct lines are no-ops. Assignment output shows default when there is no override. Inbound changes on a profile with assigned lines, outbound algorithm edits, rotation or revocation, assignment changes, and profile deletion all require confirmation. --force skips only that prompt. Deleting an assigned profile additionally needs --unassign-lines, which asks Photon to atomically clear the overrides, return those lines to the default, and delete the profile.

JSON envelopes

profile list accepts mutually exclusive --default and --additional filters.
The active pstn_voice ability remains the source of truth for admission. Saving or assigning a profile does not by itself grant voice access.