{"openapi":"3.0.3","info":{"title":"SimpleSMS","description":"Programmable SMS and phone numbers for developers. Send and receive texts, verify phone numbers, and provision numbers with one REST API. Test keys (ssms_sk_test_...) work instantly against the sandbox; live keys are enabled after a short live-access review.","version":"1.0.0","contact":{"url":"https://joinsimplesms.com"}},"servers":[{"url":"https://api.joinsimplesms.com/v1"}],"security":[{"apiKey":[]}],"paths":{"/messages":{"post":{"operationId":"sendMessage","summary":"Send an SMS","description":"Sends an SMS from one of your numbers. In test mode, delivery is simulated (see magic numbers). Supports the Idempotency-Key header, including with scheduled_at. A live send from a US local number that is not yet linked to an approved registration (sender.state other than active) is delivered only to your verified numbers; to anyone else it answers 403 sender_not_registered with an X-SimpleSMS-Sender-State header (test_only | pending | action_needed).","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Makes retries safe for 24 hours: the same key and body replays the original successful response (with Idempotent-Replayed: true); a different body returns 409. Failed requests release the key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to","from","body"],"properties":{"to":{"type":"string","example":"+15005550006"},"from":{"type":"string","example":"+15005550100","description":"One of your numbers, or a sender pool id (pool_...): SimpleSMS picks a pool member, the same one for each recipient every time."},"body":{"type":"string","maxLength":1600},"customer_id":{"type":"string","description":"Optional. Attribute to one of your customers. Defaults to the customer the from-number is assigned to; a number assigned to another customer is rejected (400)."},"scheduled_at":{"type":"string","description":"Optional. Future ISO timestamp (or epoch ms), up to 30 days out. The message is queued and the response is a scheduled_message object instead of a message."},"media":{"type":"array","items":{"type":"string","format":"uri"},"description":"Reserved for MMS; currently returns 400 mms_not_enabled."}}}}}},"responses":{"201":{"description":"Message accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"202":{"description":"Accepted and queued: a temporary carrier failure is being retried automatically (status queued, next_attempt_at set)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Idempotency conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The carrier permanently rejected the message (carrier_error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listMessages","summary":"List messages","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","maximum":100,"default":25}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"number","in":"query","schema":{"type":"string"},"description":"Filter to messages to or from this number"},{"name":"to","in":"query","schema":{"type":"string"},"description":"Exact destination number (E.164)"},{"name":"from","in":"query","schema":{"type":"string"},"description":"Exact sending number (E.164)"},{"name":"status","in":"query","schema":{"type":"string","enum":["queued","sent","delivered","failed","received"]}},{"name":"direction","in":"query","schema":{"type":"string","enum":["outbound","inbound"]}},{"name":"created_after","in":"query","schema":{"type":"string"},"description":"Inclusive. ISO timestamp or epoch ms."},{"name":"created_before","in":"query","schema":{"type":"string"},"description":"Exclusive. ISO timestamp or epoch ms."},{"name":"customer_id","in":"query","schema":{"type":"string"},"description":"Filter to one customer's messages"}],"responses":{"200":{"description":"Messages, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Message"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/messages/{id}":{"get":{"operationId":"getMessage","summary":"Retrieve a message","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/batches":{"post":{"operationId":"createBatch","summary":"Send a batch","description":"One body to up to 10,000 recipients, each with its own merge variables (or to contacts by tag), sent as individual messages through the normal pipeline. Numbers are normalized, deduplicated and checked against opt-outs before queueing; rejected rows are returned with reasons. Set dry_run to validate without sending.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["from","body"],"properties":{"from":{"type":"string","example":"+15005550100"},"body":{"type":"string","maxLength":1600,"example":"Hi {{first_name}}, your order {{order_id}} has shipped."},"name":{"type":"string","maxLength":80},"recipients":{"type":"array","maxItems":10000,"items":{"type":"object","required":["to"],"properties":{"to":{"type":"string","example":"+14155550132"},"variables":{"type":"object","additionalProperties":{"type":"string"},"example":{"first_name":"Jane","order_id":"A-1042"}}}}},"tags":{"type":"array","items":{"type":"string"},"description":"Send to contacts carrying any of these tags (instead of recipients)."},"contact_ids":{"type":"array","items":{"type":"string"}},"segment_id":{"type":"string","description":"Send to the contacts in this saved segment, evaluated when the batch is created (instead of recipients)."},"topic_id":{"type":"string","example":"tp_marketing","description":"Subscription topic. Recipients unsubscribed from it are removed at validation (`topic_unsubscribed`) and skipped at send time, like opt-outs. Omit to apply opt-outs only."},"scheduled_at":{"type":"string","description":"Future ISO timestamp or epoch ms, up to 30 days out."},"dry_run":{"type":"boolean","description":"Validate only: returns a BatchValidation and sends nothing."},"check_line_types":{"type":"boolean","description":"Reject landlines (first 500 unique numbers are checked)."}}}}}},"responses":{"200":{"description":"Dry run result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchValidation"}}}},"201":{"description":"Batch created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"400":{"description":"Invalid request or no valid recipients","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`from` not owned, or key mode does not match the number","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listBatches","summary":"List batches","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","maximum":100,"default":25}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["scheduled","sending","paused","complete","canceled"]}}],"responses":{"200":{"description":"Batches, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Batch"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/batches/{id}":{"get":{"operationId":"getBatch","summary":"Retrieve a batch","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The batch with live counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/batches/{id}/recipients":{"get":{"operationId":"listBatchRecipients","summary":"List a batch’s recipients","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["queued","paused","sent","failed","skipped","canceled"]}},{"name":"limit","in":"query","schema":{"type":"integer","maximum":500,"default":100}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Recipients in upload order","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BatchRecipient"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/batches/{id}/results":{"get":{"operationId":"getBatchResults","summary":"Results of a batch","description":"What happened after the queue: `attempted = delivered + failed + pending`. `delivered` and `failed` come from carrier delivery receipts; `pending` was accepted by the carrier with no final receipt (`no_receipt` of those never got one). `replies` are inbound messages from recipients to the sending number within `reply_window_hours` of the batch finishing (opt-out keywords are not counted); `stops` are recipients who opted out in that time and are still opted out. `spent_usd` sums the recorded price of each message. `failures` groups failed recipients by reason. Derived from stored messages and cached for up to a minute while numbers can still move; `partial: true` means a read bound was hit and delivered / replies are floors.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchResults"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/batches/{id}/pause":{"post":{"operationId":"pauseBatch","summary":"Pause a batch","description":"Holds every message not yet handed to the carrier. Messages already in flight still send.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated batch, plus affected and sweep_complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Not allowed in the batch’s current status (or a retry is already running)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/batches/{id}/resume":{"post":{"operationId":"resumeBatch","summary":"Resume a paused batch","description":"Re-queues held messages, paced from now (or from scheduled_at if still in the future).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated batch, plus affected and sweep_complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Not allowed in the batch’s current status (or a retry is already running)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/batches/{id}/cancel":{"post":{"operationId":"cancelBatch","summary":"Cancel a batch","description":"Cancels a scheduled batch, or stops a sending/paused one: every unsent message is canceled and counted. If sweep_complete is false (very large batches), call again - it is idempotent.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated batch, plus affected and sweep_complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Not allowed in the batch’s current status (or a retry is already running)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/batches/{id}/retry":{"post":{"operationId":"retryBatch","summary":"Retry failed recipients","description":"Re-queues failures that can succeed on a retry (rate limits, quota, carrier errors), up to 3 attempts per recipient. Opt-outs, invalid numbers and recipients this batch already messaged are never retried. Only for complete batches.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated batch, plus affected and sweep_complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Not allowed in the batch’s current status (or a retry is already running)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/scheduled_messages":{"get":{"operationId":"listScheduledMessages","summary":"List scheduled messages","description":"Pending 1:1 messages created with POST /messages scheduled_at. Batches list their own recipients.","responses":{"200":{"description":"Pending scheduled messages, soonest first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ScheduledMessage"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/scheduled_messages/{id}":{"delete":{"operationId":"cancelScheduledMessage","summary":"Cancel a scheduled message","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Canceled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduledMessage"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found or already sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/verify":{"post":{"operationId":"sendVerification","summary":"Send a verification code","description":"Generates a one-time code, sends it, and enforces expiry, attempt limits and anti-pumping controls. You do NOT need to own a phone number; SimpleSMS sends from its own verification pool. Nothing is billed here; a verification is charged only when the code is checked successfully. Supports the Idempotency-Key header, so a retried request does not text a second code.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Makes retries safe for 24 hours: the same key and body replays the original successful response (with Idempotent-Replayed: true); a different body returns 409. Failed requests release the key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["phone"],"properties":{"phone":{"type":"string","example":"+14155550132"},"app_name":{"type":"string","maxLength":24,"description":"Your product name, shown in the message"},"from":{"type":"string","description":"Optional: send from a number you own instead of the SimpleSMS pool"},"customer_id":{"type":"string","description":"Optional: attribute the verification to one of your customers"}}}}}},"responses":{"201":{"description":"Verification created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verification"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Blocked by Shield (charged: false)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Idempotency conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/verify/check":{"post":{"operationId":"checkVerification","summary":"Check a verification code","description":"The only billable moment in Verify. `charged` tells you whether this call was billed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["phone","code"],"properties":{"phone":{"type":"string"},"code":{"type":"string","example":"482193"}}}}}},"responses":{"200":{"description":"Check result","content":{"application/json":{"schema":{"type":"object","properties":{"verified":{"type":"boolean"},"status":{"type":"string","enum":["approved","pending","expired","max_attempts"]},"attempts":{"type":"integer"},"charged":{"type":"boolean"}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No active verification","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/verify/{id}":{"get":{"operationId":"getVerification","summary":"Retrieve a verification","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The verification","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verification"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/available":{"get":{"operationId":"searchAvailableNumbers","summary":"Search available numbers","parameters":[{"name":"area_code","in":"query","schema":{"type":"string","example":"415"}}],"responses":{"200":{"description":"Available numbers","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AvailableNumber"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers":{"get":{"operationId":"listNumbers","summary":"List your numbers","parameters":[{"name":"customer_id","in":"query","schema":{"type":"string"},"description":"Only this customer's numbers"},{"name":"tag","in":"query","schema":{"type":"string"}},{"name":"pool","in":"query","schema":{"type":"string"},"description":"Pool id"},{"name":"mode","in":"query","schema":{"type":"string","enum":["test","live"]}},{"name":"q","in":"query","schema":{"type":"string"},"description":"Matches digits of the number or its label"}],"responses":{"200":{"description":"Your active numbers","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Number"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"purchaseNumber","summary":"Purchase a number","description":"Supports the Idempotency-Key header: a retried purchase replays the original 201.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Makes retries safe for 24 hours: the same key and body replays the original successful response (with Idempotent-Replayed: true); a different body returns 409. Failed requests release the key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["phone_number"],"properties":{"phone_number":{"type":"string","example":"+15005550132"},"customer_id":{"type":"string","description":"Optional: assign the number to one of your customers"},"registration_id":{"type":"string","description":"Optional (live numbers): the registration this number should send for. Without it the number follows your account's registration."}}}}}},"responses":{"201":{"description":"Number purchased","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Number"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Idempotency conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{id}/registration":{"post":{"operationId":"attachNumberRegistration","summary":"Attach a number to a registration","description":"Ties a live US local number to one of your registrations. Needed only when you have more than one approved registration, or to retry a link that failed; otherwise numbers follow your registration on their own. If the registration is approved the number is linked with the carriers (sender.state pending, then active); a registration holds at most 49 numbers. Emits number.sender_updated.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The E.164 number"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["registration_id"],"properties":{"registration_id":{"type":"string","example":"reg_a1B2c3D4e5F6"}}}}}},"responses":{"200":{"description":"The number with its new sender","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Number"}}}},"400":{"description":"Unknown registration, or a number that is not registered (sandbox, toll-free)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The registration already has 49 numbers, or the number is active elsewhere and this registration is not approved yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{id}":{"get":{"operationId":"getNumber","summary":"Retrieve a number","description":"One of your active numbers, with `sender`: how it stands with the carriers.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The E.164 number"}],"responses":{"200":{"description":"The number","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Number"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateNumber","summary":"Assign a number to a customer","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The E.164 number"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customer_id"],"properties":{"customer_id":{"type":"string","nullable":true,"description":"A customer id, or null to unassign"}}}}}},"responses":{"200":{"description":"The updated number","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Number"}}}},"400":{"description":"Unknown customer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"releaseNumber","summary":"Release a number","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The E.164 number"}],"responses":{"200":{"description":"Number released","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Number"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts":{"post":{"operationId":"upsertContact","summary":"Create or update a contact","description":"One contact per phone number. Creates the contact (201) or updates the one that already has this number (200). Values you leave out are kept and tags are added, never removed; use PATCH to replace them.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactInput"}}}},"responses":{"200":{"description":"The existing contact, updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"201":{"description":"The new contact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listContacts","summary":"List contacts","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","maximum":100,"default":25}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"tag","in":"query","schema":{"type":"string"},"description":"Only contacts carrying this tag"},{"name":"phone_number","in":"query","schema":{"type":"string"},"description":"Find the contact with this number (0 or 1 results)"},{"name":"segment_id","in":"query","schema":{"type":"string"},"description":"Only contacts in this saved segment, evaluated now"},{"name":"q","in":"query","schema":{"type":"string"},"description":"Matches name, email, company, or digits of the number"}],"responses":{"200":{"description":"Contacts, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts/import":{"post":{"operationId":"importContacts","summary":"Bulk create or update contacts","description":"Up to 500 per request, keyed on phone number, with the same merge rule as POST /contacts. Rows that cannot be imported come back in skipped; the rest still land. `dry_run: true` returns the summary (found, valid, malformed, duplicates, landlines, already opted out, will create / update, eligible) and writes nothing. A row with `opt_in.status: true` (or a date or source) stores opt-in evidence in the consent ledger; `opt_in.status: false` records the number as opted out. An import never opts anyone back in.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contacts"],"properties":{"contacts":{"type":"array","maxItems":500,"items":{"$ref":"#/components/schemas/ContactInput"}},"dry_run":{"type":"boolean"},"check_line_types":{"type":"boolean","description":"dry_run only. Looks up line types to count landlines; live lookups are paid, so only the first 500 numbers are checked."},"import_id":{"type":"string","description":"From a previous response, to group several requests as one import."},"name":{"type":"string","description":"A label for the import (first request only)."}}}}}},"responses":{"200":{"description":"Import result, or the dry-run preview","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["contact_import","contact_import_preview"]},"created":{"type":"integer"},"updated":{"type":"integer"},"skipped":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","description":"Position of the row in the request"},"value":{"type":"string"},"reason":{"type":"string"}}}},"import_id":{"type":"string","example":"imp_a1B2c3D4e5"},"opted_out":{"type":"integer","description":"Rows recorded as opted out because they were marked unsubscribed."},"summary":{"type":"object","description":"dry_run only.","properties":{"found":{"type":"integer"},"valid":{"type":"integer"},"malformed":{"type":"integer"},"duplicates":{"type":"integer"},"landlines":{"type":"integer","nullable":true,"description":"null unless check_line_types was set"},"already_opted_out":{"type":"integer"},"marked_unsubscribed":{"type":"integer"},"will_create":{"type":"integer"},"will_update":{"type":"integer"},"eligible":{"type":"integer","description":"Would receive a broadcast today"}}},"rejected":{"type":"array","description":"dry_run only.","items":{"type":"object","properties":{"index":{"type":"integer"},"phone_number":{"type":"string"},"reason":{"type":"string","enum":["malformed","duplicate","landline"]},"detail":{"type":"string"}}}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts/bulk":{"post":{"operationId":"bulkContacts","summary":"Tag, untag, or delete many contacts","description":"One action for up to 500 contact ids. Ids that do not exist are counted in missing; the rest are applied.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["action","ids"],"properties":{"action":{"type":"string","enum":["add_tags","remove_tags","delete"]},"ids":{"type":"array","maxItems":500,"items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string","maxLength":40},"description":"Required for add_tags and remove_tags"}}}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["contact_bulk"]},"action":{"type":"string"},"updated":{"type":"integer"},"deleted":{"type":"integer"},"missing":{"type":"integer"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts/{id}":{"get":{"operationId":"getContact","summary":"Retrieve a contact","description":"Includes `consent_status`, each topic's subscription, and the saved segments the contact is in right now. `id` may also be the contact's phone number.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The contact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateContact","summary":"Update a contact","description":"Only the fields sent change. tags and fields replace what is stored; null clears name or notes, and null or an empty string clears any other optional property.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phone_number":{"type":"string","description":"E.164, US or Canada"},"name":{"type":"string","maxLength":120,"nullable":true},"tags":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":40}},"fields":{"type":"object","additionalProperties":{"type":"string","maxLength":500},"description":"Up to 20 string values"},"notes":{"type":"string","maxLength":2000,"nullable":true},"first_name":{"type":"string","maxLength":80,"nullable":true},"last_name":{"type":"string","maxLength":80,"nullable":true},"email":{"type":"string","maxLength":254,"nullable":true},"company":{"type":"string","maxLength":120,"nullable":true},"state":{"type":"string","maxLength":40,"nullable":true},"source":{"type":"string","maxLength":60,"nullable":true}}}}}},"responses":{"200":{"description":"The contact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"phone_number already used by another contact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteContact","summary":"Delete a contact","description":"Messages, consent records and topic preferences for the number are untouched.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","enum":["contact"]},"deleted":{"type":"boolean"}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/customers":{"post":{"operationId":"createCustomer","summary":"Create a customer","description":"A business you send on behalf of. Assign numbers to it and its messages, verifications, events and usage carry its id. Optional; nothing requires customers.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"nullable":true},"external_id":{"type":"string","maxLength":200,"nullable":true,"description":"Your id for them; unique per account"},"metadata":{"type":"object","additionalProperties":{"type":"string","maxLength":500},"description":"Up to 50 string values"}}}}}},"responses":{"201":{"description":"The customer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Customer"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"external_id already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listCustomers","summary":"List customers","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","maximum":100,"default":25}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"external_id","in":"query","schema":{"type":"string"},"description":"Find the customer with this external_id (0 or 1 results)"}],"responses":{"200":{"description":"Customers, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Customer"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/customers/{id}":{"get":{"operationId":"getCustomer","summary":"Retrieve a customer","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The customer, with phone_numbers assigned to it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Customer"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateCustomer","summary":"Update a customer","description":"Only the fields sent change. metadata replaces the whole object; null clears a field.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"nullable":true},"external_id":{"type":"string","maxLength":200,"nullable":true,"description":"Your id for them; unique per account"},"metadata":{"type":"object","additionalProperties":{"type":"string","maxLength":500},"description":"Up to 50 string values"}}}}}},"responses":{"200":{"description":"The customer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Customer"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"external_id already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteCustomer","summary":"Delete a customer","description":"Unassigns its numbers (they stay on your account). Messages, events and usage already attributed keep the id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","enum":["customer"]},"deleted":{"type":"boolean"}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/customers/{id}/usage":{"get":{"operationId":"getCustomerUsage","summary":"A customer's usage","description":"UTC days, inclusive, up to 366. Follows the key: test keys report sandbox traffic, live keys live traffic.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"start","in":"query","schema":{"type":"string","format":"date"},"description":"Default: first day of this month"},{"name":"end","in":"query","schema":{"type":"string","format":"date"},"description":"Default: today"}],"responses":{"200":{"description":"Usage","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerUsage"}}}},"400":{"description":"Invalid range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/bulk":{"post":{"operationId":"bulkUpdateNumbers","summary":"Act on many numbers at once","description":"Tag, untag, label, pool, unpool or release up to 1000 numbers (100 for release). Returns 200 with a result per id even when some fail. Release requires `confirm: \"RELEASE <count of ids>\"`; test keys cannot release live numbers.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids","action"],"properties":{"ids":{"type":"array","items":{"type":"string"},"maxItems":1000,"example":["+15005550132","+15005550154"]},"action":{"type":"string","enum":["add_to_pool","remove_from_pool","add_tags","remove_tags","set_label","release"]},"pool_id":{"type":"string","description":"add_to_pool / remove_from_pool"},"tags":{"type":"array","items":{"type":"string"},"description":"add_tags / remove_tags. Lowercased; up to 20 per number."},"label":{"type":"string","nullable":true,"maxLength":64,"description":"set_label; null clears"},"confirm":{"type":"string","example":"RELEASE 2","description":"release only"}}}}}},"responses":{"200":{"description":"Per-id results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkResult"}}}},"400":{"description":"Malformed request or missing release confirmation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/bulk-purchase":{"post":{"operationId":"bulkPurchaseNumbers","summary":"Buy many numbers in an area code","description":"Quota is checked for the whole quantity up front (429, nothing bought). After that, carrier refusals are reported per number and backfilled from spare inventory; `shortfall` counts any the area code could not supply. Test keys mint sandbox numbers.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["area_code","quantity"],"properties":{"area_code":{"type":"string","example":"415"},"quantity":{"type":"integer","minimum":1,"maximum":50},"pool_id":{"type":"string","description":"Add the new numbers to this pool"},"tags":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"At least one number purchased","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["bulk_purchase"]},"requested":{"type":"integer"},"purchased":{"type":"array","items":{"$ref":"#/components/schemas/Number"}},"failed":{"type":"array","items":{"type":"object","properties":{"phone_number":{"type":"string"},"error":{"type":"string"},"message":{"type":"string"}}}},"shortfall":{"type":"integer"}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/export":{"get":{"operationId":"exportNumbers","summary":"Export numbers as CSV","parameters":[{"name":"tag","in":"query","schema":{"type":"string"}},{"name":"pool","in":"query","schema":{"type":"string"}},{"name":"mode","in":"query","schema":{"type":"string","enum":["test","live"]}},{"name":"q","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"phone_number,mode,label,tags,pools,pool_ids,created_at","content":{"text/csv":{"schema":{"type":"string"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/pools":{"get":{"operationId":"listPools","summary":"List sender pools","responses":{"200":{"description":"Your pools","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Pool"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createPool","summary":"Create a sender pool","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":64},"description":{"type":"string","maxLength":280}}}}}},"responses":{"201":{"description":"Pool created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Pool"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/pools/{id}":{"get":{"operationId":"getPool","summary":"Retrieve a pool","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The pool","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Pool"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updatePool","summary":"Rename a pool","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"200":{"description":"The pool","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Pool"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deletePool","summary":"Delete a pool","description":"Its numbers stay on your account; sends that name this pool start failing.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/pools/{id}/clone":{"post":{"operationId":"clonePool","summary":"Clone a pool","description":"New pool with the same description and members. Numbers can belong to several pools.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"}}}}}},"responses":{"201":{"description":"The new pool","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Pool"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/lookup/{phone}":{"get":{"operationId":"lookupPhone","summary":"Look up a phone number","description":"Carrier, line type, and caller name for any US/Canada number.","parameters":[{"name":"phone","in":"path","required":true,"schema":{"type":"string","example":"+14155550132"}}],"responses":{"200":{"description":"Lookup result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Lookup"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts/{id}/topics":{"get":{"operationId":"getContactTopics","summary":"A contact's topic subscriptions","description":"`id` is a contact id or a phone number (preferences belong to the number, so a number that is not a contact still answers). `consent_status` is the global opt-out state: when it is `opted_out` nothing is sent, whatever the topics say.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Each topic and whether this number is subscribed","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["topic_subscriptions"]},"phone":{"type":"string"},"contact_id":{"type":"string","nullable":true},"consent_status":{"type":"string","enum":["opted_out","opted_in","no_record"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/TopicSubscription"}}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts/{id}/topics/{topic}":{"put":{"operationId":"setContactTopic","summary":"Subscribe or unsubscribe a contact from a topic","description":"`topic` is a topic id or name. Recorded in the consent ledger and the audit log. No record means subscribed, so only an unsubscribe narrows who is sent to. Subscribing to a topic does not lift an opt-out.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Contact id or phone number"},{"name":"topic","in":"path","required":true,"schema":{"type":"string"},"description":"Topic id (tp_...) or name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["subscribed"],"properties":{"subscribed":{"type":"boolean"},"source":{"type":"string","description":"Where the change came from, e.g. \"preference_page\". Default \"api\"."}}}}}},"responses":{"200":{"description":"The new state; `changed` is false when it already was","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["topic_subscription"]},"phone":{"type":"string"},"contact_id":{"type":"string","nullable":true},"topic_id":{"type":"string"},"name":{"type":"string"},"subscribed":{"type":"boolean"},"changed":{"type":"boolean"}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such contact, number, or topic","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/segments":{"post":{"operationId":"createSegment","summary":"Create a segment","description":"A segment is a saved, named filter over contacts (an audience; not an SMS message part). It is evaluated when used, so it always reflects current contacts. Up to 100 segments, 10 rules each.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentInput"}}}},"responses":{"201":{"description":"The segment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Segment"}}}},"400":{"description":"Invalid rules, or the segment limit is reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listSegments","summary":"List segments","responses":{"200":{"description":"Every segment, by name","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Segment"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/segments/{id}":{"get":{"operationId":"getSegment","summary":"Retrieve a segment","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"seg_a1B2c3D4e5F6"}}],"responses":{"200":{"description":"The segment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Segment"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateSegment","summary":"Update a segment","description":"Send `name` / `description` alone, or `rules` (and `match`) to replace the whole rule list.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentInput"}}}},"responses":{"200":{"description":"The segment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Segment"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteSegment","summary":"Delete a segment","description":"Deletes the filter, not the contacts.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","enum":["segment"]},"deleted":{"type":"boolean"}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/segments/{id}/preview":{"get":{"operationId":"previewSegment","summary":"Count a segment","description":"How many contacts the segment matches now and how many would receive a broadcast: opted-out contacts are removed, then (with `topic_id`) those unsubscribed from that topic. `eligible + opted_out + topic_unsubscribed = matched`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"topic_id","in":"query","schema":{"type":"string"},"description":"Topic id or name"}],"responses":{"200":{"description":"Counts","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["segment_preview"]},"segment_id":{"type":"string"},"topic_id":{"type":"string","nullable":true},"contacts_total":{"type":"integer"},"matched":{"type":"integer"},"opted_out":{"type":"integer"},"topic_unsubscribed":{"type":"integer"},"eligible":{"type":"integer"}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/topics":{"get":{"operationId":"listTopics","summary":"List subscription topics","description":"Every account starts with Marketing (tp_marketing), Account alerts (tp_account_alerts) and Product updates (tp_product_updates). Up to 20 topics.","responses":{"200":{"description":"Topics, oldest first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Topic"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createTopic","summary":"Create a topic","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":60},"description":{"type":"string","maxLength":200,"nullable":true}}}}}},"responses":{"201":{"description":"The topic","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Topic"}}}},"400":{"description":"Invalid request, or the topic limit is reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A topic with that name exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/topics/{id}":{"get":{"operationId":"getTopic","summary":"Retrieve a topic","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"tp_marketing"}}],"responses":{"200":{"description":"The topic","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Topic"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateTopic","summary":"Rename or describe a topic","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":60},"description":{"type":"string","maxLength":200,"nullable":true}}}}}},"responses":{"200":{"description":"The topic","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Topic"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A topic with that name exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteTopic","summary":"Delete a topic","description":"Recipients' recorded preferences for the topic are kept as consent history, and batches already created with it keep honoring them.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","enum":["topic"]},"deleted":{"type":"boolean"}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/consent":{"get":{"operationId":"listConsent","summary":"List opted-out numbers (suppression list)","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","maximum":100,"default":25}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Suppressions in numeric order","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Consent"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/consent/{phone}":{"get":{"operationId":"getConsent","summary":"Consent state and append-only history for one number","parameters":[{"name":"phone","in":"path","required":true,"schema":{"type":"string","example":"+14155550132"}}],"responses":{"200":{"description":"Consent record","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsentDetail"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"setConsent","summary":"Set consent state from your own system (CRM sync)","parameters":[{"name":"phone","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["opted_out","opted_in"]},"note":{"type":"string","maxLength":200},"proof":{"$ref":"#/components/schemas/OptInProof"}}}}}},"responses":{"200":{"description":"Updated consent state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Consent"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/consent/import":{"post":{"operationId":"importConsent","summary":"Bulk-import a suppression list (up to 500 numbers)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["phone_numbers"],"properties":{"phone_numbers":{"type":"array","items":{"type":"string"},"maxItems":500}}}}}},"responses":{"200":{"description":"Import counts","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","example":"consent_import"},"imported":{"type":"integer"},"skipped":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"reason":{"type":"string"}}}}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/consent/export":{"get":{"operationId":"exportConsent","summary":"Export the suppression list, or the full consent ledger with opt-in proof, as CSV","parameters":[{"name":"type","in":"query","schema":{"type":"string","enum":["suppressions","ledger"],"default":"suppressions"}}],"responses":{"200":{"description":"suppressions: phone,status,updated_at,via,method,detected. ledger: phone,at,type,via,method,detected,note,proof_source,proof_collected_at,proof_page_url,proof_disclosure,proof_ip,proof_user_agent,proof_registration_id,proof_campaign_id","content":{"text/csv":{"schema":{"type":"string"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/registrations":{"get":{"operationId":"listRegistrations","summary":"List brand + campaign registrations","responses":{"200":{"description":"Registrations, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Registration"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createRegistration","summary":"Create a registration and run the website disclosure check","description":"Fetches the website, privacy policy, terms (discovered from homepage links when not given) and opt-in page, and checks them against carrier requirements. Also checks your example messages (sample_messages). Returns status ready or checks_failed, with findings, guidance, and generated copy. A registration is ready only when the website check passes, the example check passes, and the examples are yours (samples_source = customer): without sample_messages you get starter drafts that must be edited or confirmed first.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationInput"}}}},"responses":{"201":{"description":"Registration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Registration"}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/registrations/prefill":{"post":{"operationId":"prefillRegistration","summary":"Suggest a registration from a website","description":"Reads the public pages of the website (homepage plus the sign-up, contact, privacy and terms pages it links to) and returns suggestions for a registration: business name, legal name when the site states one, use case, description, opt-in / privacy / terms URLs with ranked candidates, support email, contact phone, address and industry. Creates and files nothing. EIN and entity type are never suggested. Names, contact details and URLs are read with fixed rules; where AI drafting is available (ai: true) a third-party AI model drafts the description, use case, industry and three starter example messages from the same public page text, and every field it returns is validated. Review the fields, then send them to POST /registrations (drafted examples as starter_messages, or as sample_messages once they are yours). One read per website per account every 10 minutes; 10 websites a minute.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["website"],"properties":{"website":{"type":"string","format":"uri","example":"https://acmeplumbing.com"}}}}}},"responses":{"200":{"description":"Suggestions (reachable: false when the site could not be read)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationPrefill"}}}},"400":{"description":"Invalid website","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/registrations/{id}":{"get":{"operationId":"getRegistration","summary":"Get a registration","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"reg_a1B2c3D4e5F6"}}],"responses":{"200":{"description":"Registration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Registration"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/registrations/{id}/recheck":{"post":{"operationId":"recheckRegistration","summary":"Re-run the checks (optionally correcting input fields)","description":"Allowed in draft, checks_failed, ready and rejected. Any RegistrationInput field may be sent to correct it, including sample_messages and description; samples_confirmed: true adopts the starter examples as yours. A body that only changes the examples re-runs the example check and keeps the website verdict.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationInput"}}}},"responses":{"200":{"description":"Registration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Registration"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"invalid_state: not recheckable now (message says why)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/registrations/{id}/submit":{"post":{"operationId":"submitRegistration","summary":"Submit a ready registration for carrier review (or resubmit after a rejection)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Registration, status submitted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Registration"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"invalid_state: not ready (message says what to do)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/registrations/{id}/submissions":{"get":{"operationId":"listRegistrationSubmissions","summary":"List the filed copies of a registration","description":"One entry per submission, oldest first: exactly what was sent for carrier review (business details, example messages, description, opt-in story) and how the checks stood. Read-only. A copy is written when you submit and never changed; a resubmission adds a new one.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"reg_a1B2c3D4e5F6"}}],"responses":{"200":{"description":"Filed copies, oldest first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RegistrationSubmission"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/events":{"get":{"operationId":"listEvents","summary":"List events","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","maximum":100,"default":25}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"type","in":"query","schema":{"type":"string","example":"message.delivered"}}],"responses":{"200":{"description":"Events, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/events/{id}/replay":{"post":{"operationId":"replayEvent","summary":"Replay an event to one webhook endpoint","description":"Sends the stored event to the endpoint you name, now, and returns its answer. Not retried. Works for paused endpoints and ones not subscribed to the event type.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"evt_a1B2c3D4e5F6g7H8"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["endpoint_id"],"properties":{"endpoint_id":{"type":"string","example":"we_a1B2c3D4e5F6"}}}}}},"responses":{"200":{"description":"What the endpoint answered","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["webhook_replay"]},"event_id":{"type":"string"},"endpoint_id":{"type":"string"},"delivery_id":{"type":"string"},"ok":{"type":"boolean"},"status_code":{"type":"integer","nullable":true},"error":{"type":"string","nullable":true,"enum":["timeout","unreachable"]},"latency_ms":{"type":"integer"}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such event or endpoint","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks":{"get":{"operationId":"listWebhookEndpoints","summary":"List webhook endpoints","description":"Your endpoints (manage them in the console). Signing secrets are not returned over the API.","responses":{"200":{"description":"Endpoints","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/deliveries":{"get":{"operationId":"listWebhookDeliveries","summary":"List webhook delivery attempts","description":"Every attempt to push an event to your endpoints, newest first, kept 30 days: status code, latency, attempt number and the first 2 KB of the response body.","parameters":[{"name":"endpoint_id","in":"query","schema":{"type":"string"}},{"name":"event_id","in":"query","schema":{"type":"string"},"description":"Every attempt for one event"},{"name":"limit","in":"query","schema":{"type":"integer","maximum":100,"default":25}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Deliveries, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such endpoint","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/deliverability":{"get":{"operationId":"getDeliverability","summary":"Delivery rates by day, carrier, or sending number","description":"Final outcomes (delivered/failed) aggregated over a UTC date range of up to 90 days. Test keys report sandbox traffic, live keys live traffic. Scope: messages:read.","parameters":[{"name":"group_by","in":"query","schema":{"type":"string","enum":["day","carrier","number"],"default":"day"}},{"name":"start_date","in":"query","schema":{"type":"string","format":"date"},"description":"Default: 6 days before end_date"},{"name":"end_date","in":"query","schema":{"type":"string","format":"date"},"description":"Default: today (UTC)"}],"responses":{"200":{"description":"Deliverability report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deliverability"}}}},"400":{"description":"Invalid range or group_by","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/spend-limit":{"get":{"operationId":"getSpendLimit","summary":"Get the monthly spend limit and this month's estimated spend","description":"Scope: billing.","responses":{"200":{"description":"Spend limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpendLimit"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateSpendLimit","summary":"Set or remove the monthly spend limit and alert thresholds","description":"Live outbound messages that would exceed the cap are rejected with 403 spend_limit_reached and not charged. Thresholds fire spend.threshold_reached once each per month. Scope: billing.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"monthly_limit_usd":{"type":"number","nullable":true,"minimum":1,"maximum":1000000,"description":"null removes the cap"},"alert_thresholds":{"type":"array","maxItems":5,"items":{"type":"integer","minimum":1,"maximum":100},"example":[50,80,100]}}}}}},"responses":{"200":{"description":"Updated spend limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpendLimit"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/audit-logs":{"get":{"operationId":"listAuditLogs","summary":"List audit log entries","description":"Account changes (keys, team, webhooks, spend limit, numbers, consent, settings) with actor and IP, newest first. Filters apply before paging. One request scans at most 5,000 entries, so a rarely matching filter can return a short or empty page with has_more true: follow next_cursor until has_more is false. Scope: audit_logs:read.","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"action","in":"query","description":"One action, or a group prefix with a trailing dot (team., api_key.)","schema":{"type":"string","example":"api_key.created"}},{"name":"actor","in":"query","description":"Actor id (exact) or part of the actor email (case-insensitive)","schema":{"type":"string","example":"dev@example.com"}},{"name":"target_type","in":"query","description":"Target type, e.g. api_key, member, invite, webhook, number, phone","schema":{"type":"string","example":"webhook"}},{"name":"created_after","in":"query","description":"Entries at or after this time (ISO 8601)","schema":{"type":"string","format":"date-time","example":"2026-09-01T00:00:00Z"}},{"name":"created_before","in":"query","description":"Entries at or before this time (ISO 8601); a bare date means the end of that day (UTC)","schema":{"type":"string","format":"date-time","example":"2026-09-30T23:59:59Z"}}],"responses":{"200":{"description":"Audit log entries, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AuditLog"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"400":{"description":"Invalid filter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/exports/{kind}":{"get":{"operationId":"exportCsv","summary":"Export messages, delivery results, events, opt-outs, webhook deliveries, usage or the audit log as CSV","description":"Streams a CSV (UTF-8 with BOM). At most 50,000 rows per export (header X-Export-Row-Cap); narrow the date range if you hit it. Cells that would be spreadsheet formulas are prefixed with a single quote.","parameters":[{"name":"kind","in":"path","required":true,"schema":{"type":"string","enum":["messages","deliveries","events","opt_outs","webhook_deliveries","usage","usage_monthly","audit_log"]}},{"name":"from","in":"query","description":"ISO date/time or epoch ms (messages, deliveries, events, webhook_deliveries)","schema":{"type":"string","example":"2026-01-01"}},{"name":"to","in":"query","description":"Inclusive; a bare date means the end of that day (UTC)","schema":{"type":"string","example":"2026-01-31"}},{"name":"status","in":"query","description":"messages, deliveries","schema":{"type":"string","enum":["queued","sent","delivered","failed","received"]}},{"name":"direction","in":"query","description":"messages","schema":{"type":"string","enum":["outbound","inbound"]}},{"name":"number","in":"query","description":"messages, deliveries: digits matched against either side","schema":{"type":"string"}},{"name":"to_number","in":"query","description":"messages, deliveries: exact recipient (E.164). `to`/`from` are the date range here.","schema":{"type":"string"}},{"name":"from_number","in":"query","description":"messages, deliveries: exact sender (E.164)","schema":{"type":"string"}},{"name":"customer_id","in":"query","description":"messages, deliveries","schema":{"type":"string"}},{"name":"batch","in":"query","description":"messages, deliveries: batch id (bc_...)","schema":{"type":"string"}},{"name":"q","in":"query","description":"messages: body/failure text; events: id/payload text","schema":{"type":"string"}},{"name":"type","in":"query","description":"events, webhook_deliveries","schema":{"type":"string","example":"message.failed"}},{"name":"endpoint_id","in":"query","description":"webhook_deliveries (default: all endpoints)","schema":{"type":"string"}},{"name":"ok","in":"query","description":"webhook_deliveries","schema":{"type":"boolean"}},{"name":"months","in":"query","description":"usage: daily rows for the last N months","schema":{"type":"integer","minimum":1,"maximum":12,"default":3}},{"name":"action","in":"query","description":"audit_log: one action, or a group prefix with a trailing dot (team.)","schema":{"type":"string"}},{"name":"actor","in":"query","description":"audit_log: actor id or part of the actor email","schema":{"type":"string"}},{"name":"target_type","in":"query","description":"audit_log","schema":{"type":"string"}},{"name":"created_after","in":"query","description":"audit_log: same as on GET /audit-logs (from is accepted too)","schema":{"type":"string"}},{"name":"created_before","in":"query","description":"audit_log: same as on GET /audit-logs (to is accepted too)","schema":{"type":"string"}}],"responses":{"200":{"description":"CSV body","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Unknown kind or invalid filter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/track":{"post":{"operationId":"trackEvent","summary":"Track a customer event","description":"Records something a person did in your app and starts or advances the automations listening for it. Pass phone, user_id, or both; a call with both links them so later events need only user_id. Test keys reach sandbox automations, live keys live ones. Supports Idempotency-Key. 100 calls per 10 seconds per key. Scope: automations. (GET /events is the webhook event log, a different thing.)","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["event"],"properties":{"event":{"type":"string","maxLength":64,"example":"trial_started","description":"Letters, digits, and _ . : -"},"user_id":{"type":"string","maxLength":128,"example":"123"},"phone":{"type":"string","example":"+14155550132"},"properties":{"type":"object","description":"Up to 20 scalar values; usable as merge fields and in conditions.","example":{"plan":"pro"}}}}}}},"responses":{"201":{"description":"Recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackedEvent"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/automations":{"get":{"operationId":"listAutomations","summary":"List automations (at most 50 per account)","description":"Scope: automations.","responses":{"200":{"description":"Automations, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Automation"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createAutomation","summary":"Create an automation (as a draft)","description":"The response lists `issues`: everything that stops the flow from being activated. Scope: automations.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationInput"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Automation"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/automations/{id}":{"get":{"operationId":"getAutomation","summary":"Retrieve an automation","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Automation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Automation"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateAutomation","summary":"Edit an automation","description":"Editing an active automation publishes a new version at once and must leave it valid; runs in progress finish on the version they started with. Pause first to save work in progress.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationInput"}}}},"responses":{"200":{"description":"Updated automation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Automation"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteAutomation","summary":"Delete an automation","description":"Runs in progress end with end_reason flow_deleted the next time they wake; nothing more is sent.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","enum":["automation"]},"deleted":{"type":"boolean"}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/automations/{id}/activate":{"post":{"operationId":"activateAutomation","summary":"Activate an automation","description":"Answers 400 with `issues` when the flow is not ready. At most 20 automations can be active at once.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Active automation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Automation"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/automations/{id}/pause":{"post":{"operationId":"pauseAutomation","summary":"Pause an automation","description":"Stops new runs and holds runs in progress where they are until it is activated again.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paused automation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Automation"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/automations/{id}/runs":{"get":{"operationId":"listAutomationRuns","summary":"List an automation's runs, newest first","description":"Runs are kept for 30 days after they end.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Runs","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AutomationRun"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/automations/{id}/runs/{run_id}":{"get":{"operationId":"getAutomationRun","summary":"Retrieve a run with its timeline","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"run_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Run","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationRun"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"cancelAutomationRun","summary":"Cancel a run in progress","description":"The run stays readable, ended with end_reason canceled. 409 if it is advancing at this moment.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"run_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Canceled run","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationRun"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/templates":{"get":{"operationId":"listTemplates","summary":"List message templates (at most 100 per account)","responses":{"200":{"description":"Templates by name","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Template"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createTemplate","summary":"Create a template with {{merge}} fields","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","body"],"properties":{"name":{"type":"string","maxLength":60},"body":{"type":"string","maxLength":1600,"example":"Hi {{first_name}}, your order shipped."}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Template"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/templates/{id}":{"get":{"operationId":"getTemplate","summary":"Retrieve a template","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Template"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateTemplate","summary":"Rename or edit a template","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":60},"body":{"type":"string","maxLength":1600}}}}}},"responses":{"200":{"description":"Updated template","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Template"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteTemplate","summary":"Delete a template","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string"},"deleted":{"type":"boolean"}}}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/test/inbound":{"post":{"operationId":"simulateInbound","summary":"Simulate an inbound SMS (test keys only)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to","from","body"],"properties":{"to":{"type":"string","description":"One of your sandbox numbers"},"from":{"type":"string"},"body":{"type":"string"}}}}}},"responses":{"201":{"description":"Simulated inbound message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"401":{"description":"Missing, malformed, or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Live keys not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"Your API key, e.g. Authorization: Bearer ssms_sk_test_.... Keys may be restricted to scopes (messages:send, messages:read, numbers:read, numbers:write, verify, consent, lookup, webhooks, customers, contacts, registrations, billing, automations, audit_logs:read); a restricted key outside its scopes gets 403 insufficient_scope. Keys without scopes have full access."}},"schemas":{"Message":{"type":"object","properties":{"id":{"type":"string","example":"msg_a1B2c3D4e5F6g7H8"},"object":{"type":"string","enum":["message"]},"to":{"type":"string","example":"+15005550006"},"from":{"type":"string","example":"+15005550100"},"body":{"type":"string"},"direction":{"type":"string","enum":["outbound","inbound"]},"status":{"type":"string","enum":["queued","sent","delivered","failed","received"]},"test":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"media":{"type":"array","items":{"type":"string","format":"uri"},"description":"MMS attachments (inbound today)."},"sent_by":{"type":"string","description":"Console user or API key that composed it."},"failure_reason":{"type":"string","description":"The carrier's raw text for a failed send. Kept for compatibility; see `failure`."},"attempts":{"type":"integer","description":"Live sends: carrier submissions so far. More than 1 means it was retried."},"next_attempt_at":{"type":"string","format":"date-time","description":"Present while queued for an automatic carrier retry."},"receipt_status":{"type":"string","enum":["missing"],"description":"The carrier accepted the message but sent no delivery report within 72 hours. status stays sent."},"customer_id":{"type":"string","description":"The customer this is attributed to. Present only when set."},"timeline":{"type":"array","description":"Every status transition, oldest first. Inbound messages have a single `received`.","items":{"type":"object","properties":{"status":{"type":"string","enum":["accepted","validated","queued","sent_to_carrier","carrier_accepted","retry_scheduled","delivered","failed","received"]},"at":{"type":"string","format":"date-time"},"attempt":{"type":"integer","description":"Carrier attempt this step belongs to (from sent_to_carrier on)."}}}},"segments":{"type":"integer","description":"Parts the body is split into (GSM-7: 160, then 153 each; UCS-2: 70, then 67).","example":1},"encoding":{"type":"string","enum":["gsm7","ucs2"]},"price":{"type":"object","nullable":true,"description":"What this message costs, in USD. One all-in rate per outbound message; carrier fees are included (a 0 line). Null on messages sent before prices were recorded.","properties":{"total":{"type":"number","example":0.009},"currency":{"type":"string","enum":["usd"]},"breakdown":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"amount":{"type":"number"}}}}}},"destination_carrier":{"type":"string","nullable":true,"description":"The recipient's mobile carrier, when a cached lookup knows it."},"failure":{"allOf":[{"$ref":"#/components/schemas/Failure"}],"nullable":true,"description":"Null unless status is `failed`."}}},"Batch":{"type":"object","properties":{"id":{"type":"string","example":"bc_a1B2c3D4e5F6"},"object":{"type":"string","enum":["batch"]},"name":{"type":"string"},"status":{"type":"string","enum":["scheduled","sending","paused","complete","canceled"]},"from":{"type":"string"},"body":{"type":"string"},"source":{"type":"string","enum":["api","csv","contacts"]},"test":{"type":"boolean"},"scheduled_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"},"completed_at":{"type":"string","format":"date-time","nullable":true},"counts":{"type":"object","description":"total = queued + sent + failed + opted_out + canceled, always. \"sent\" = accepted by the carrier; what happened next (delivered, failed, replies) is GET /v1/batches/{id}/results. \"opted_out\" also counts recipients unsubscribed from the batch topic.","properties":{"total":{"type":"integer"},"queued":{"type":"integer"},"sent":{"type":"integer"},"failed":{"type":"integer"},"opted_out":{"type":"integer"},"canceled":{"type":"integer"}}},"rejected":{"type":"object","nullable":true,"description":"Rows dropped at validation (not part of total), by reason."},"variables":{"type":"array","items":{"type":"string"}},"retries":{"type":"integer"}}},"BatchRecipient":{"type":"object","properties":{"id":{"type":"string","example":"r00042"},"object":{"type":"string","enum":["batch_recipient"]},"to":{"type":"string"},"status":{"type":"string","enum":["queued","paused","sent","failed","skipped","canceled"]},"error":{"type":"string","nullable":true,"example":"carrier_error"},"detail":{"type":"string","nullable":true},"retryable":{"type":"boolean"},"attempts":{"type":"integer"},"message_id":{"type":"string","nullable":true},"variables":{"type":"object","additionalProperties":{"type":"string"}}}},"BatchValidation":{"type":"object","properties":{"object":{"type":"string","enum":["batch_validation"]},"counts":{"type":"object","properties":{"rows":{"type":"integer"},"valid":{"type":"integer"},"invalid":{"type":"integer"},"duplicates":{"type":"integer"},"opted_out":{"type":"integer"},"topic_unsubscribed":{"type":"integer","description":"Unsubscribed from the batch topic_id; 0 without a topic"},"missing_variable":{"type":"integer"},"landline":{"type":"integer"},"empty_after_merge":{"type":"integer"}}},"unknown_variables":{"type":"array","items":{"type":"string"}},"segments":{"type":"object","properties":{"total":{"type":"integer"},"max":{"type":"integer"},"encoding":{"type":"string","enum":["GSM-7","UCS-2"]}}},"estimated_cost_usd":{"type":"number"},"preview":{"type":"array","items":{"type":"object","properties":{"to":{"type":"string"},"body":{"type":"string"},"segments":{"type":"integer"}}}},"rejected":{"type":"array","items":{"type":"object","properties":{"row":{"type":"integer","description":"0-based index into recipients"},"to":{"type":"string"},"reason":{"type":"string","enum":["invalid","duplicate","opted_out","missing_variable","landline","empty_after_merge"]},"detail":{"type":"string"}}}}}},"ScheduledMessage":{"type":"object","properties":{"id":{"type":"string","example":"job_1759400000000a1B2c3D4e5"},"object":{"type":"string","enum":["scheduled_message"]},"to":{"type":"string"},"from":{"type":"string"},"body":{"type":"string"},"run_at":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["queued","canceled"]}}},"Failure":{"type":"object","description":"Why a message was not delivered, readable. See /docs/errors#delivery-failures.","properties":{"code":{"type":"string","enum":["carrier_filtered","unreachable","invalid_number","opted_out","content_blocked","rate_limited","landline","carrier_rejected","spend_limit_reached","sender_not_registered","unknown"]},"title":{"type":"string","example":"Filtered as spam"},"explanation":{"type":"string"},"action":{"type":"string","description":"What to do next; starts with \"Recommended:\"."},"carrier_code":{"type":"string","nullable":true,"description":"The carrier's own error code, when it sent one."}}},"Verification":{"type":"object","properties":{"id":{"type":"string","example":"ver_a1B2c3D4e5F6g7H8"},"object":{"type":"string","enum":["verification"]},"phone":{"type":"string"},"status":{"type":"string","enum":["pending","approved","expired","max_attempts","blocked"]},"attempts":{"type":"integer"},"test":{"type":"boolean"},"charged":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time"},"customer_id":{"type":"string","description":"The customer this is attributed to. Present only when set."}}},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_api_key","tenant_suspended","live_access_required","test_mode_only","forbidden","not_found","invalid_request","rate_limited","quota_exceeded","idempotency_conflict","verification_blocked","verification_not_found","insufficient_scope","spend_limit_reached","sender_not_registered","carrier_error","invalid_state","internal_error"]},"message":{"type":"string"},"param":{"type":"string","description":"The offending parameter, when there is one"},"required_scope":{"type":"string","description":"insufficient_scope only: the scope this endpoint needs"},"request_id":{"type":"string","description":"Id of this request (req_…), also returned in the X-Request-Id header on every response. Find it in the console under Logs, and quote it to support."}}}}},"Number":{"type":"object","properties":{"id":{"type":"string","example":"+15005550132"},"object":{"type":"string","enum":["number"]},"phone_number":{"type":"string"},"status":{"type":"string","enum":["active","released"]},"mode":{"type":"string","enum":["test","live"]},"created_at":{"type":"string","format":"date-time"},"customer_id":{"type":"string","nullable":true,"description":"The customer this number is assigned to"},"label":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"}},"pools":{"type":"array","items":{"type":"string"},"description":"Pool ids"},"sender":{"type":"object","nullable":true,"description":"How the number stands with the carriers. null on sandbox numbers and on numbers that need no registration (toll-free, Canadian). Only an active number can text anyone; in every other state it can text only your verified numbers.","properties":{"state":{"type":"string","enum":["test_only","pending","active","action_needed"],"description":"test_only: no registration submitted. pending: a registration is in review, or approved and being linked. active: linked to an approved registration. action_needed: see reason."},"registration_id":{"type":"string","nullable":true,"description":"The registration it is (being) linked to"},"reason":{"type":"string","nullable":true,"description":"What to do, in plain words, when state is action_needed"},"updated_at":{"type":"string","format":"date-time"}}}}},"ContactInput":{"type":"object","required":["phone_number"],"properties":{"phone_number":{"type":"string","description":"E.164, US or Canada"},"name":{"type":"string","maxLength":120,"description":"Display name. Defaults to first + last name."},"tags":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":40}},"fields":{"type":"object","additionalProperties":{"type":"string","maxLength":500},"description":"Up to 20 string values (account id, plan, location...), usable in segments and as {{field:key}} merge fields"},"notes":{"type":"string","maxLength":2000},"first_name":{"type":"string","maxLength":80},"last_name":{"type":"string","maxLength":80},"email":{"type":"string","maxLength":254},"company":{"type":"string","maxLength":120},"state":{"type":"string","maxLength":40,"example":"TN"},"source":{"type":"string","maxLength":60,"description":"Where the contact came from. Defaults to \"api\"."},"opt_in":{"type":"object","description":"Import only (POST /v1/contacts/import). Stored as consent evidence; never lifts an opt-out.","properties":{"status":{"type":"boolean","description":"true = opted in; false = unsubscribed (recorded as an opt-out)"},"at":{"type":"string","description":"When they opted in: ISO timestamp, date, or epoch ms"},"source":{"type":"string","description":"web_form, keyword, paper, checkout or verbal are stored as proof; anything else is kept as a note"}}}}},"Contact":{"type":"object","properties":{"id":{"type":"string","example":"ct_a1B2c3D4e5F6"},"object":{"type":"string","enum":["contact"]},"phone_number":{"type":"string","example":"+14155550132"},"name":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"},"description":"Free-form labels; they double as broadcast audiences"},"fields":{"type":"object","additionalProperties":{"type":"string"}},"notes":{"type":"string","nullable":true},"first_name":{"type":"string","nullable":true},"last_name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"company":{"type":"string","nullable":true},"state":{"type":"string","nullable":true},"source":{"type":"string","nullable":true},"import_id":{"type":"string","nullable":true,"description":"The last import that touched this contact"},"opt_in":{"type":"object","nullable":true,"properties":{"source":{"type":"string","nullable":true},"collected_at":{"type":"string","format":"date-time","nullable":true}}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"consent_status":{"type":"string","enum":["opted_out","opted_in","no_record"],"description":"Only on retrieve"},"topics":{"type":"array","items":{"$ref":"#/components/schemas/TopicSubscription"},"description":"Only on retrieve"},"segments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}},"description":"Only on retrieve"}}},"TopicSubscription":{"type":"object","properties":{"topic_id":{"type":"string","example":"tp_marketing"},"name":{"type":"string","example":"Marketing"},"subscribed":{"type":"boolean","description":"true unless an unsubscribe is recorded"},"updated_at":{"type":"string","format":"date-time","nullable":true},"source":{"type":"string","nullable":true}}},"Topic":{"type":"object","properties":{"id":{"type":"string","example":"tp_marketing"},"object":{"type":"string","enum":["topic"]},"name":{"type":"string"},"description":{"type":"string","nullable":true},"builtin":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"SegmentRule":{"type":"object","required":["field"],"properties":{"field":{"type":"string","enum":["tag","first_name","last_name","name","email","company","state","source","field","import","status","topic","created_at"]},"key":{"type":"string","description":"The custom field name (field = \"field\") or the topic id (field = \"topic\")"},"op":{"type":"string","enum":["is","is_not","contains","not_contains","exists","not_exists","before","after"],"description":"Text fields take is / is_not / contains / not_contains / exists / not_exists; tag takes is / is_not / exists / not_exists; status, topic and import take is / is_not; created_at takes before / after. Comparisons ignore case."},"value":{"type":"string","description":"status: subscribed or opted_out. topic: subscribed or unsubscribed. created_at: an ISO date. import: an import id."}}},"SegmentInput":{"type":"object","properties":{"name":{"type":"string","maxLength":80},"description":{"type":"string","maxLength":200,"nullable":true},"match":{"type":"string","enum":["all","any"],"default":"all"},"rules":{"type":"array","maxItems":10,"items":{"$ref":"#/components/schemas/SegmentRule"},"example":[{"field":"tag","op":"is","value":"vip"},{"field":"state","op":"is","value":"TN"},{"field":"field","key":"plan","op":"is","value":"pro"},{"field":"topic","key":"tp_marketing","op":"is","value":"subscribed"}]}}},"Segment":{"type":"object","properties":{"id":{"type":"string","example":"seg_a1B2c3D4e5F6"},"object":{"type":"string","enum":["segment"]},"name":{"type":"string"},"description":{"type":"string","nullable":true},"match":{"type":"string","enum":["all","any"]},"rules":{"type":"array","items":{"$ref":"#/components/schemas/SegmentRule"}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"BatchResults":{"type":"object","properties":{"object":{"type":"string","enum":["batch_results"]},"batch_id":{"type":"string"},"recipients":{"type":"integer"},"attempted":{"type":"integer"},"delivered":{"type":"integer"},"failed":{"type":"integer"},"pending":{"type":"integer"},"no_receipt":{"type":"integer"},"skipped":{"type":"object","properties":{"opted_out":{"type":"integer"},"topic_unsubscribed":{"type":"integer"}}},"canceled":{"type":"integer"},"queued":{"type":"integer"},"replies":{"type":"integer"},"repliers":{"type":"integer"},"stops":{"type":"integer"},"spent_usd":{"type":"number"},"failures":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"title":{"type":"string"},"explanation":{"type":"string"},"action":{"type":"string"},"count":{"type":"integer"}}}},"reply_window_hours":{"type":"integer"},"window_open":{"type":"boolean"},"partial":{"type":"boolean"},"test":{"type":"boolean"},"computed_at":{"type":"string","format":"date-time"}}},"Customer":{"type":"object","properties":{"id":{"type":"string","example":"cus_a1B2c3D4e5F6g7"},"object":{"type":"string","enum":["customer"]},"name":{"type":"string","nullable":true},"external_id":{"type":"string","nullable":true},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"phone_numbers":{"type":"array","items":{"type":"string"},"description":"Only on retrieve"}}},"CustomerUsage":{"type":"object","properties":{"object":{"type":"string","enum":["customer_usage"]},"customer_id":{"type":"string"},"mode":{"type":"string","enum":["test","live"]},"start":{"type":"string","format":"date"},"end":{"type":"string","format":"date"},"messages_sent":{"type":"integer"},"messages_failed":{"type":"integer"},"messages_received":{"type":"integer"},"verifications_sent":{"type":"integer"},"verifications_approved":{"type":"integer"},"numbers":{"type":"integer","description":"Numbers assigned now"},"phone_numbers":{"type":"array","items":{"type":"string"}},"daily":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"messages_sent":{"type":"integer"},"messages_failed":{"type":"integer"},"messages_received":{"type":"integer"},"verifications_sent":{"type":"integer"},"verifications_approved":{"type":"integer"}}}}}},"AvailableNumber":{"type":"object","properties":{"object":{"type":"string","enum":["available_number"]},"phone_number":{"type":"string"},"locality":{"type":"string"},"region":{"type":"string"}}},"Lookup":{"type":"object","properties":{"phone_number":{"type":"string"},"valid":{"type":"boolean"},"line_type":{"type":"string","nullable":true,"example":"mobile"},"carrier":{"type":"object","properties":{"name":{"type":"string","nullable":true},"type":{"type":"string","nullable":true}}},"caller_name":{"type":"string","nullable":true}}},"Consent":{"type":"object","properties":{"object":{"type":"string","enum":["consent"]},"phone":{"type":"string","example":"+14155550132"},"status":{"type":"string","enum":["opted_out","opted_in","no_record"]},"updated_at":{"type":"string","format":"date-time"},"via":{"type":"string","example":"sms_phrase"},"method":{"type":"string","enum":["keyword","phrase","ai","api","import"]},"detected":{"type":"string","description":"The keyword or phrase that triggered detection"},"confidence":{"type":"number","description":"AI-tier detections only, 0 to 1"}}},"ConsentDetail":{"allOf":[{"$ref":"#/components/schemas/Consent"},{"type":"object","properties":{"history":{"type":"array","description":"Append-only consent history, newest first","items":{"type":"object","properties":{"at":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["opt_out","opt_in","exempt_send","import","api_set","topic_unsubscribe","topic_subscribe"],"description":"`import` is opt-in evidence from a contact import; `topic_*` are per-topic preferences. Neither changes the opt-out status."},"via":{"type":"string"},"method":{"type":"string"},"detected":{"type":"string"},"confidence":{"type":"number"},"note":{"type":"string"},"proof":{"$ref":"#/components/schemas/OptInProof"}}}}}}]},"WebhookEndpoint":{"type":"object","properties":{"id":{"type":"string","example":"we_a1B2c3D4e5F6"},"object":{"type":"string","enum":["webhook_endpoint"]},"url":{"type":"string","format":"uri"},"events":{"oneOf":[{"type":"string","enum":["*"]},{"type":"array","items":{"type":"string"}}]},"active":{"type":"boolean"},"description":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"Pool":{"type":"object","properties":{"id":{"type":"string","example":"pool_a1B2c3D4e5F6"},"object":{"type":"string","enum":["pool"]},"name":{"type":"string"},"description":{"type":"string","nullable":true},"numbers":{"type":"array","items":{"type":"string"},"description":"Active member numbers (E.164)"},"cloned_from":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"BulkResult":{"type":"object","properties":{"object":{"type":"string","enum":["bulk_result"]},"action":{"type":"string"},"requested":{"type":"integer"},"succeeded":{"type":"integer"},"failed":{"type":"integer"},"results":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"ok":{"type":"boolean"},"error":{"type":"string","enum":["invalid_id","duplicate","not_found","too_many_tags","mode_mismatch","carrier_error"]},"message":{"type":"string"}}}}}},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","enum":["webhook_delivery"]},"endpoint_id":{"type":"string"},"event_id":{"type":"string"},"event_type":{"type":"string"},"attempt":{"type":"integer","description":"1 is the first push; up to 6 with retries"},"ok":{"type":"boolean"},"status_code":{"type":"integer","nullable":true},"error":{"type":"string","nullable":true,"enum":["timeout","unreachable"]},"latency_ms":{"type":"integer"},"response_body":{"type":"string","nullable":true,"description":"First 2 KB of what your endpoint answered"},"replay":{"type":"boolean","description":"Sent by a manual replay"},"created_at":{"type":"string","format":"date-time"}}},"OptInProof":{"type":"object","description":"Opt-in evidence (Messaging Policy 1.4). Accepted only with status opted_in.","required":["source"],"properties":{"source":{"type":"string","enum":["web_form","keyword","paper","checkout","verbal"]},"collected_at":{"type":"string","format":"date-time","description":"When the person consented; defaults to now"},"page_url":{"type":"string","format":"uri","description":"Required for web_form"},"disclosure":{"type":"string","maxLength":2000,"description":"Exact disclosure wording shown"},"ip":{"type":"string"},"user_agent":{"type":"string","maxLength":500},"registration_id":{"type":"string","example":"reg_a1B2c3D4e5F6"},"campaign_id":{"type":"string"}}},"RegistrationInput":{"type":"object","required":["business_name","website","use_case"],"properties":{"business_name":{"type":"string","maxLength":120},"website":{"type":"string","format":"uri"},"use_case":{"type":"string","enum":["2fa","account_notification","customer_care","delivery_notification","fraud_alert","higher_education","marketing","mixed","polling_voting","public_service_announcement","security_alert","low_volume"]},"opt_in_url":{"type":"string","format":"uri","description":"Page where people enter their number"},"privacy_url":{"type":"string","format":"uri","description":"Discovered from homepage links when omitted"},"terms_url":{"type":"string","format":"uri","description":"Discovered from homepage links when omitted"},"support_email":{"type":"string","format":"email","description":"Used in the generated HELP reply"},"sample_messages":{"type":"array","nullable":true,"minItems":2,"maxItems":5,"items":{"type":"string","minLength":20,"maxLength":320},"description":"Real examples of the texts you will send, as a recipient would get them (no template variables). Carriers compare them with your traffic. Each must name your business; marketing and mixed use cases need opt-out wording in at least one. More than 5, or one over 320 characters, is a 400; too few or too short comes back as findings. Omit to get starter drafts; null or [] goes back to them."},"starter_messages":{"type":"array","nullable":true,"maxItems":5,"items":{"type":"string","maxLength":320},"description":"Draft examples suggested for this business (fields.sample_messages from POST /registrations/prefill). Shown instead of the template starter drafts; samples_source stays starter and they are never filed until you edit or confirm them. Drafts that would not pass the example check for the business name and use case are ignored."},"samples_confirmed":{"type":"boolean","description":"true = the starter drafts are right as they are; they become your examples. Ignored when sample_messages is sent."},"description":{"type":"string","nullable":true,"maxLength":500,"description":"What you send and to whom (40 to 500 characters). Omit or null to file the generated one."},"brand":{"type":"object","properties":{"legal_name":{"type":"string"},"entity_type":{"type":"string","enum":["PRIVATE_PROFIT","PUBLIC_PROFIT","NON_PROFIT","GOVERNMENT","SOLE_PROPRIETOR"]},"ein":{"type":"string","example":"12-3456789"},"street":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"postal_code":{"type":"string"},"country":{"type":"string"},"vertical":{"type":"string"},"contact_email":{"type":"string"},"contact_phone":{"type":"string"}}}}},"Finding":{"type":"object","properties":{"id":{"type":"string","enum":["site_reachable","business_identity","privacy_policy_exists","privacy_no_sharing","terms_exist","terms_sms_program","optin_reachable","optin_phone_field","optin_brand","optin_message_types","optin_frequency","optin_rates","optin_stop","optin_help","optin_links","optin_not_prechecked"]},"title":{"type":"string"},"status":{"type":"string","enum":["pass","fail","warn"]},"evidence":{"type":"object","properties":{"url":{"type":"string","nullable":true},"snippet":{"type":"string","nullable":true}}},"why":{"type":"string"},"fix":{"type":"object","nullable":true,"properties":{"summary":{"type":"string"},"copy":{"type":"string","nullable":true,"description":"Exact text to paste"}}},"flagged_by_rejection":{"type":"boolean"}}},"SampleFinding":{"type":"object","description":"A finding of the example-message check. Same shape as Finding.","properties":{"id":{"type":"string","enum":["samples_confirmed","samples_count","samples_length","samples_brand","samples_opt_out","samples_links","samples_placeholders","samples_distinct","samples_use_case","samples_description"]},"title":{"type":"string"},"status":{"type":"string","enum":["pass","fail","warn"]},"evidence":{"type":"object","properties":{"url":{"type":"string","nullable":true},"snippet":{"type":"string","nullable":true}}},"why":{"type":"string"},"fix":{"type":"object","nullable":true,"properties":{"summary":{"type":"string"},"copy":{"type":"string","nullable":true,"description":"Exact text to paste"}}}}},"RegistrationPrefill":{"type":"object","properties":{"object":{"type":"string","enum":["registration_prefill"]},"reachable":{"type":"boolean","description":"false = the website could not be read; fields then holds only the website"},"error":{"type":"string","nullable":true,"description":"Why the site could not be read"},"fields":{"type":"object","description":"Suggestions, shaped like RegistrationInput. Only fields we found are present.","properties":{"website":{"type":"string","format":"uri"},"business_name":{"type":"string"},"use_case":{"type":"string"},"description":{"type":"string","maxLength":500},"opt_in_url":{"type":"string","format":"uri"},"privacy_url":{"type":"string","format":"uri"},"terms_url":{"type":"string","format":"uri"},"support_email":{"type":"string","format":"email"},"sample_messages":{"type":"array","items":{"type":"string"},"description":"Starter drafts written for this business (AI drafting only). Send them as starter_messages."},"brand":{"type":"object","description":"Never includes ein or entity_type.","properties":{"legal_name":{"type":"string"},"street":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"postal_code":{"type":"string"},"country":{"type":"string"},"vertical":{"type":"string","enum":["PROFESSIONAL","REAL_ESTATE","HEALTHCARE","HUMAN_RESOURCES","ENERGY","ENTERTAINMENT","RETAIL","TRANSPORTATION","AGRICULTURE","INSURANCE","POSTAL","EDUCATION","HOSPITALITY","FINANCIAL","LEGAL","CONSTRUCTION","NGO","MANUFACTURING","GOVERNMENT","TECHNOLOGY","COMMUNICATION"]},"contact_email":{"type":"string"},"contact_phone":{"type":"string"}}}}},"suggested":{"type":"array","items":{"type":"string"},"description":"Dotted names of every field filled in, e.g. business_name, brand.city"},"sources":{"type":"object","additionalProperties":{"type":"string","enum":["page","ai"]},"description":"Where each suggested field came from: page = read from your pages by fixed rules; ai = drafted or chosen by an AI model"},"candidates":{"type":"object","description":"Pages that could be the opt-in, privacy policy and terms, best first","properties":{"opt_in":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"confidence":{"type":"number","minimum":0,"maximum":1},"reason":{"type":"string"}}}},"privacy":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"confidence":{"type":"number","minimum":0,"maximum":1},"reason":{"type":"string"}}}},"terms":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"confidence":{"type":"number","minimum":0,"maximum":1},"reason":{"type":"string"}}}}}},"about":{"type":"string","nullable":true,"description":"What the site says the business is (its meta description)"},"ai":{"type":"boolean","description":"true when an AI model drafted any of these suggestions"}}},"RegistrationSubmission":{"type":"object","description":"An immutable copy of what one submission filed.","properties":{"object":{"type":"string","enum":["registration_submission"]},"registration_id":{"type":"string","example":"reg_a1B2c3D4e5F6"},"number":{"type":"integer","description":"1 for the first submission, 2 for the first resubmission, and so on"},"submitted_at":{"type":"string","format":"date-time"},"filed_by":{"type":"string","enum":["delivered_compliance","registry"]},"reference":{"type":"string"},"sample_messages":{"type":"array","items":{"type":"string"}},"samples_source":{"type":"string","enum":["starter","customer"]},"description":{"type":"string"},"brand":{"type":"object","description":"The business details as filed"},"campaign":{"type":"object","description":"Use case, description, opt-in story, example messages and keyword replies as filed"},"website_check":{"type":"object","nullable":true,"properties":{"checked_at":{"type":"string","format":"date-time"},"passed":{"type":"integer"},"failed":{"type":"integer"},"warnings":{"type":"integer"},"urls":{"type":"object"},"not_passing":{"type":"array","items":{"type":"string"},"description":"Ids of findings that were warnings (a failing finding blocks submission)"}}},"sample_check":{"type":"object","properties":{"passed":{"type":"integer"},"failed":{"type":"integer"},"warnings":{"type":"integer"},"not_passing":{"type":"array","items":{"type":"string"}}}}}},"Registration":{"type":"object","properties":{"id":{"type":"string","example":"reg_a1B2c3D4e5F6"},"object":{"type":"string","enum":["registration"]},"status":{"type":"string","enum":["draft","checks_failed","ready","submitted","in_review","approved","rejected"]},"business_name":{"type":"string"},"website":{"type":"string"},"use_case":{"type":"string"},"opt_in_url":{"type":"string","nullable":true},"privacy_url":{"type":"string","nullable":true},"terms_url":{"type":"string","nullable":true},"support_email":{"type":"string","nullable":true},"brand":{"type":"object"},"sample_messages":{"type":"array","items":{"type":"string"},"description":"The examples as they stand: yours, or starter drafts (see samples_source). These are what a submission files."},"samples_source":{"type":"string","enum":["starter","customer"],"description":"starter: our drafts, not yet edited or confirmed; the registration cannot be ready. customer: yours."},"description":{"type":"string","nullable":true,"description":"Your own description; null when the generated one (generated.campaign.description) is filed"},"sample_check":{"type":"object","description":"The example-message check. Deterministic rules, no AI. Recomputed on every read.","properties":{"passed":{"type":"integer"},"failed":{"type":"integer"},"warnings":{"type":"integer"},"ok":{"type":"boolean"},"findings":{"type":"array","items":{"$ref":"#/components/schemas/SampleFinding"}}}},"guidance":{"type":"object","description":"The five answers every state gives","properties":{"what_happened":{"type":"string"},"why":{"type":"string"},"next_actor":{"type":"string","enum":["you","delivered","carriers","nobody"]},"next_step":{"type":"string"},"after":{"type":"string"}}},"check":{"type":"object","nullable":true,"properties":{"checked_at":{"type":"string","format":"date-time"},"passed":{"type":"integer"},"failed":{"type":"integer"},"warnings":{"type":"integer"},"urls":{"type":"object"},"findings":{"type":"array","items":{"$ref":"#/components/schemas/Finding"}}}},"rejection":{"type":"object","nullable":true,"properties":{"code":{"type":"string"},"title":{"type":"string"},"explanation":{"type":"string"},"fix":{"type":"string"},"note":{"type":"string","nullable":true},"related_findings":{"type":"array","items":{"type":"string"}},"rejected_at":{"type":"string","format":"date-time"}}},"generated":{"type":"object","description":"Deterministic compliant copy and the registry draft","properties":{"opt_in_cta":{"type":"string"},"privacy_clause":{"type":"string"},"sms_terms":{"type":"string"},"sample_messages":{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":5,"description":"Starter drafts from templates. What is filed is the top-level sample_messages (also in generated.campaign.sample_messages)."},"help_reply":{"type":"string"},"stop_reply":{"type":"string"},"opt_in_confirmation":{"type":"string"},"brand":{"type":"object","properties":{"missing":{"type":"array","items":{"type":"string"}}}},"campaign":{"type":"object","properties":{"use_case":{"type":"string"},"description":{"type":"string"},"message_flow":{"type":"string"},"sample_messages":{"type":"array","items":{"type":"string"}},"opt_in_keywords":{"type":"array","items":{"type":"string"}},"opt_in_message":{"type":"string"},"opt_out_keywords":{"type":"array","items":{"type":"string"}},"opt_out_message":{"type":"string"},"help_keywords":{"type":"array","items":{"type":"string"}},"help_message":{"type":"string"},"embedded_link":{"type":"boolean"},"embedded_phone":{"type":"boolean"},"number_pooling":{"type":"boolean"},"direct_lending":{"type":"boolean"},"age_gated":{"type":"boolean"},"affiliate_marketing":{"type":"boolean"},"privacy_policy_url":{"type":"string"},"terms_url":{"type":"string"}}}}},"submissions":{"type":"integer"},"history":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","format":"date-time"},"status":{"type":"string"},"actor":{"type":"string","enum":["customer","delivered","system"]},"label":{"type":"string"},"reason_code":{"type":"string"},"note":{"type":"string"}}}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"DeliverabilityRow":{"type":"object","properties":{"key":{"type":"string","description":"Date (YYYY-MM-DD), carrier key, or 10-digit sending number","example":"2026-10-01"},"delivered":{"type":"integer"},"failed":{"type":"integer"},"total":{"type":"integer"},"delivery_rate":{"type":"number","nullable":true,"example":0.9907},"failure_reasons":{"type":"object","additionalProperties":{"type":"integer"}}}},"Deliverability":{"type":"object","properties":{"object":{"type":"string","enum":["deliverability"]},"mode":{"type":"string","enum":["test","live"]},"start_date":{"type":"string","format":"date"},"end_date":{"type":"string","format":"date"},"group_by":{"type":"string","enum":["day","carrier","number"]},"totals":{"$ref":"#/components/schemas/DeliverabilityRow"},"data":{"type":"array","items":{"$ref":"#/components/schemas/DeliverabilityRow"}}}},"SpendLimit":{"type":"object","properties":{"object":{"type":"string","enum":["spend_limit"]},"monthly_limit_usd":{"type":"number","nullable":true},"alert_thresholds":{"type":"array","items":{"type":"integer"}},"applies_to":{"type":"array","items":{"type":"string","enum":["outbound_sms"]}},"estimated_cost_per_message_usd":{"type":"number"},"current_month":{"type":"object","properties":{"month":{"type":"string","example":"2026-10"},"spent_usd":{"type":"number"},"remaining_usd":{"type":"number","nullable":true}}},"updated_at":{"type":"string","format":"date-time","nullable":true}}},"AuditLog":{"type":"object","properties":{"id":{"type":"string","example":"aud_a1B2c3D4e5F6g7H8"},"object":{"type":"string","enum":["audit_log"]},"action":{"type":"string","enum":["api_key.created","api_key.revoked","api_key.rolled","team.invite_created","team.invite_accepted","team.invite_revoked","team.member_left","team.member_removed","team.role_changed","webhook.created","webhook.updated","webhook.deleted","webhook.secret_rotated","spend_limit.updated","number.purchased","number.released","number.assigned","number.registration_set","number.sender_linked","number.sender_unlinked","registration.approved","live_access.approved","consent.updated","consent.imported","settings.updated","contacts.imported","contact.topic_updated","segment.created","segment.updated","segment.deleted","topic.created","topic.updated","topic.deleted","automation.created","automation.updated","automation.activated","automation.paused","automation.deleted"]},"actor":{"type":"object","properties":{"type":{"type":"string","enum":["user","api_key","system"]},"id":{"type":"string"},"email":{"type":"string"},"name":{"type":"string"}}},"target":{"type":"object","properties":{"type":{"type":"string"},"id":{"type":"string"}}},"metadata":{"type":"object"},"ip":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"Event":{"type":"object","properties":{"id":{"type":"string","example":"evt_a1B2c3D4e5F6g7H8"},"object":{"type":"string","enum":["event"]},"type":{"type":"string","enum":["message.sent","message.delivered","message.failed","message.received","message.opted_out","message.opted_in","message.help_requested","message.blocked","broadcast.complete","number.purchased","number.released","number.sender_updated","verification.sent","verification.approved","verification.failed","verification.blocked","verification.sent_to_opted_out","registration.updated","deliverability.degraded","spend.threshold_reached","automation.run.started","automation.run.completed","automation.run.failed","batch.created","batch.paused","batch.resumed","batch.canceled","batch.retried","batch.complete"]},"created_at":{"type":"string","format":"date-time"},"data":{"type":"object"}}},"TrackedEvent":{"type":"object","properties":{"id":{"type":"string","example":"tev_a1B2c3D4e5F6g7H8"},"object":{"type":"string","enum":["tracked_event"]},"event":{"type":"string"},"user_id":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true,"description":"Null when user_id is not linked to a number yet (nothing could start)."},"properties":{"type":"object"},"test":{"type":"boolean"},"runs_started":{"type":"array","items":{"type":"string"},"description":"Ids of the runs this event started."},"runs_notified":{"type":"integer","description":"Runs in progress for this person that recorded the event."},"created_at":{"type":"string","format":"date-time"}}},"AutomationStep":{"type":"object","required":["type"],"description":"One of: send_sms {body, from?}; wait {seconds}; wait_for_event {event, timeout_seconds, on_received, on_timeout}; condition {check, on_met, on_not_met}; end. Branches are \"continue\", \"end\", or \"goto:<id of a later step>\".","properties":{"id":{"type":"string","description":"Stable handle for goto branches; assigned when omitted."},"type":{"type":"string","enum":["send_sms","wait","wait_for_event","condition","end"]},"body":{"type":"string","maxLength":1600,"description":"send_sms. Merge fields: event properties by name, {{first_name}}, {{name}}, {{phone}}, {{field:<custom>}}."},"from":{"type":"string","description":"send_sms: overrides the flow sender."},"seconds":{"type":"integer","minimum":60,"maximum":2592000},"event":{"type":"string"},"timeout_seconds":{"type":"integer","minimum":60,"maximum":2592000},"on_received":{"type":"string","example":"end"},"on_timeout":{"type":"string","example":"continue"},"check":{"type":"object","description":"{kind: event_received, event} | {kind: property, property, op, value?} | {kind: contact_field, field, op, value?}. op: eq, neq, contains, gt, lt, exists, not_exists."},"on_met":{"type":"string","example":"continue"},"on_not_met":{"type":"string","example":"end"}}},"AutomationInput":{"type":"object","properties":{"name":{"type":"string","maxLength":80},"from":{"type":"string","nullable":true,"description":"One of your numbers. A sandbox number makes it a sandbox flow."},"topic_id":{"type":"string","nullable":true,"description":"Skip recipients unsubscribed from this topic."},"trigger":{"type":"object","properties":{"event":{"type":"string","example":"trial_started"},"filters":{"type":"array","maxItems":5,"items":{"type":"object","properties":{"property":{"type":"string"},"op":{"type":"string"},"value":{}}}}}},"steps":{"type":"array","maxItems":20,"items":{"$ref":"#/components/schemas/AutomationStep"}}}},"Automation":{"type":"object","properties":{"id":{"type":"string","example":"auto_a1B2c3D4e5F6"},"object":{"type":"string","enum":["automation"]},"name":{"type":"string"},"status":{"type":"string","enum":["draft","active","paused"]},"trigger":{"type":"object"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/AutomationStep"}},"from":{"type":"string","nullable":true},"topic_id":{"type":"string","nullable":true},"test":{"type":"boolean","nullable":true,"description":"Sandbox or live, decided by the sender number."},"version":{"type":"integer","description":"Published version; runs are pinned to the one they started on."},"unpublished_changes":{"type":"boolean"},"stats":{"type":"object","properties":{"runs_started":{"type":"integer"},"runs_active":{"type":"integer"},"runs_completed":{"type":"integer"},"runs_failed":{"type":"integer"},"runs_opted_out":{"type":"integer"},"triggers_skipped":{"type":"integer","description":"Triggers ignored because that person already had a run in progress."},"messages_sent":{"type":"integer"},"last_triggered_at":{"type":"string","format":"date-time","nullable":true}}},"issues":{"type":"array","description":"What stops this flow from running. Empty when it can be activated.","items":{"type":"object","properties":{"where":{"type":"string","description":"A step id, \"trigger\" or \"flow\"."},"field":{"type":"string"},"message":{"type":"string"}}}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"AutomationRun":{"type":"object","properties":{"id":{"type":"string","example":"run_1790000000000a1B2c3D4"},"object":{"type":"string","enum":["automation_run"]},"automation_id":{"type":"string"},"automation_version":{"type":"integer"},"status":{"type":"string","enum":["running","waiting","completed","failed"]},"to":{"type":"string"},"user_id":{"type":"string","nullable":true},"test":{"type":"boolean"},"trigger_event":{"type":"string"},"step":{"type":"integer","description":"Index of the step the run is on."},"waiting_until":{"type":"string","format":"date-time","nullable":true},"waiting_for_event":{"type":"string","nullable":true},"end_reason":{"type":"string","nullable":true,"enum":["finished","end_step","branch_end","opted_out","flow_deleted","version_removed","expired","canceled","error",null]},"messages_sent":{"type":"integer"},"messages_failed":{"type":"integer"},"timeline":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["started","sent","send_failed","send_unconfirmed","send_skipped","wait_started","wait_done","waiting_for_event","event_received","timed_out","condition_met","condition_not_met","ended"]},"step_id":{"type":"string"},"detail":{"type":"string"},"message_id":{"type":"string"}}}},"started_at":{"type":"string","format":"date-time"},"ended_at":{"type":"string","format":"date-time","nullable":true}}},"Template":{"type":"object","properties":{"id":{"type":"string","example":"tpl_a1B2c3D4e5F6"},"object":{"type":"string","enum":["template"]},"name":{"type":"string"},"body":{"type":"string","description":"Merge fields: {{name}}, {{first_name}}, {{phone}}, {{field:<custom>}}"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}}}