Skip to main content
photon account 10dlc registers and maintains your organization’s 10DLC brands and campaigns. Registration starts the moment a command succeeds — there is no local draft and no separate submit step.
An approved brand does not authorize A2P messaging on its own. A campaign must also be approved, and a sending phone number must be assigned to that campaign, before you can send traffic. Phone-number assignment happens outside this CLI.
Brands and campaigns belong to the selected organization: your stored organization, your only organization, or --org for one invocation. The global --project option does not scope them. Browse the automatic command reference.

The workflow

Use truthful business and contact information that matches government, tax-authority, and other official records. Mismatches delay registration or get it rejected.
1

Register a brand

Supply a complete organization or sole-proprietor profile. Registration begins as soon as create is accepted.
2

Verify the OTP, for a sole proprietor

Send and verify the code for the registrant phone once the brand status says verification is available.
3

Monitor the brand

brand view shows registration feedback so you can fix rejected information. Use brand edit to start a correction. Photon may verify the correction automatically or ask for another OTP.
4

Register a campaign

Describe the real use cases, consent flow, and representative messages.
Photon may hold the campaign awaiting brand verification or qualification, then submit it automatically once the brand is eligible.
5

Assign a phone number

Assign a sending number to the approved campaign through the appropriate Photon workflow before you send A2P traffic.
create and edit confirm before reading private input. Registration warns that it begins immediately; correction warns that the current profile stays active until Photon accepts the replacement. Scripts must pass --force.

Brand profiles

create requires a complete profile. In an interactive terminal with no --profile-file, it walks you through every required field:
The wizard keeps your answers out of CLI diagnostics and the operation journal, but your terminal may still echo what you type. Use a private file or a trusted pipe if the terminal is recorded or visible to others.
Protect registration data at rest, and keep it out of shell arguments, environment variables, shell history, and shared temporary directories:
The CLI accepts up to 16 KiB, rejects unknown fields and control characters, normalizes EIN and US state formatting, requires five-digit ZIP codes, and allows only HTTP(S) website URLs with no embedded credentials or fragment.
Every field is required. entityType accepts only private_profit or non_profit.
A reduced schema. The phone must be a US +1 number that can receive SMS.
agriculture, communication, construction, education, energy, entertainment, financial, gambling, government, healthcare, hospitality, human_resources, insurance, legal, manufacturing, ngo, political, postal, professional, real_estate, retail, technology, transportation.

Correct a brand

A normal edit is a partial profile. It must carry type as the discriminator plus at least one editable field:
In the guided flow the CLI reads the redacted brand, infers its immutable profile type, and prompts for every field that type supports. Current values are shown, with phone and EIN redacted to their last four digits. Address components are prompted separately, so changing one preserves the others. If you leave every prompt blank, nothing is submitted. edit --replace sends a complete profile, so it requires --profile-file in an interactive terminal — that keeps write-only EIN and phone values explicit rather than reconstructed from redacted data. Brand type is immutable either way. Edits return immediately as {"brand": ...}, and the existing profile stays active until Photon accepts the correction. Privacy policy and terms URLs belong to the campaign, not the brand profile.

Register a campaign

Before you prepare campaign input, read the CTIA Messaging Principles and Best Practices and The Campaign Registry’s campaign guidance. Describe the real subscriber experience: how consent is obtained, how the sender is identified, how HELP and STOP work, where the privacy policy and terms live, and what your messages actually look like.
The CLI validates the structural contract and offers guidance. It does not guarantee approval and does not replace legal or compliance review.
Check the current catalog before choosing use cases:
Supported codes are 2FA, ACCOUNT_NOTIFICATION, CUSTOMER_CARE, DELIVERY_NOTIFICATION, FRAUD_ALERT, HIGHER_EDUCATION, MARKETING, POLLING_VOTING, PUBLIC_SERVICE_ANNOUNCEMENT, and SECURITY_ALERT. Select 1–5 distinct purposes; order does not matter. The catalog response also reports the current minimum and maximum selection counts.
At most 64 KiB. name is a caller-owned label of 1–64 characters that Photon never submits to the registry. Descriptions are 40–4,096 characters and message flows are 40–2,048 characters. Supply 2–5 ordered representative messages of 20–255 characters, with at least one sample per selected use case. Internal newlines are preserved; other control and format characters are rejected. Unknown and legacy registry fields are rejected.All four attestations must be explicitly true. An embedded link sample must be a safe absolute HTTP(S) URL with no credentials or fragment, and is allowed only when embeddedLinks is true.
The guided wizard asks for 1–5 comma-separated use cases, then collects at least two representative messages — raising that minimum to match the number of use cases you picked — and offers to collect up to five.
The confirmation warns that your selected use cases cannot be changed after submission and that an accepted attempt carries a non-refundable fee. Automation needs both --force and the explicit JSON attestations.A failed registration charge is terminal — no campaign is created. Fix the organization payment method, then register again with a fresh idempotency key. Do not replay the failed one.
When the API reports billing as pending, the CLI waits for the interval Photon specifies and replays the same request with an identical body and idempotency key until it gets a full campaign response or you press Ctrl-C. Campaign idempotency keys are 8–128 printable non-whitespace ASCII characters.

Filter campaigns

Status filters accept awaiting_brand_verification, awaiting_brand_qualification, submitting, reviewing, action_required, activating, ready, suspended, expired, and support_required. The two awaiting states mean Photon will submit automatically once the brand prerequisite completes. Returned status strings stay opaque so new server states still display.

Update a campaign

Run campaign view first. The response includes etag, capabilities.editableFields, capabilities.canResubmit, hasUnsubmittedChanges, and review feedback. Use the returned ETag to protect against overwriting a newer campaign revision.
Fetch a fresh ETag after every successful edit. For other fields, use an update file instead of edit flags. Read the current campaign again and put its ETag into campaign-update.json:
The file contains etag, updateMask, and the fields to replace:
Editable fields also include description, sample messages, opt-in/opt-out/HELP messages and keywords, terms URL, and embedded-link and phone-number settings. The API determines which fields are editable in the current state. Repeat --sample-message 2–5 times to replace the full sample set. How edits take effect depends on the campaign state:
  • Name changes are local and allowed in every state.
  • Eligible rejected campaigns save content changes locally until resubmission.
  • Ready campaigns allow asynchronous sample updates; the approved samples stay live until the registry applies the replacement.
  • Other states lock campaign content. Check capabilities.editableFields before editing and capabilities.canResubmit before resubmitting.

Resubmit a campaign

Edit the campaign first, then fetch its current ETag. Resubmit only when capabilities.canResubmit is true. The old campaign correct endpoint was replaced by separate edit and resubmit operations.
etag is required. appealReason is optional and, when supplied, must be 20–2,000 characters. Resubmission does not accept campaign edits. Automation may pipe the same JSON through stdin. The CLI confirms before resubmission, which may incur another registration fee.

Sole-proprietor OTP

Inspect the redacted OTP status after registering a sole proprietor, then send and verify in the order Photon indicates. In an interactive terminal, verify prompts for the 4–10-character alphanumeric code without echoing it.
--code exists for automation and convenience, but command arguments can be visible in shell history and process listings. Prefer the hidden prompt or a trusted pipe on shared systems. There are no --pin or --pin-file options.
Raw OTP codes, full phone numbers, EINs, profile contents, and registration feedback are excluded from errors, --debug diagnostics, and the local journal. brand view deliberately still shows registration feedback, since that is what you need to correct a rejection.

Output and recovery

JSON uses stable, selected envelopes: IDs are exposed as brandId and campaignId. Undocumented response fields are omitted, and statuses stay opaque strings. Brand create, brand edit, and OTP verification are not journaled, because replaying them would require sensitive input. Their idempotency key exists only in memory. If an outcome is uncertain, the error includes that key — check the current state, then rerun the exact command and private input with the same --idempotency-key. OTP send and campaign mutations do use the journal. Campaign records keep the normalized input and its digest but never file paths, and descriptions, message flows, samples, and appeal text are redacted from operation view, errors, and diagnostics. That means a replay needs only the operation ID:
See Recoverable operations for the full model.