Changelog

2026-10-05: Opt-outs you can see

  • recipient_opted_out: a send to an opted-out number now answers 403 with its own code (it was the generic forbidden) and says when and how the person opted out, in the message and as opted_out_at, opted_out_via and opted_out_method. failure.code is still opted_out. If you matched on forbidden for this case, match the new code.
  • message.blocked: every refused send emits an event and webhook, is noted in the number's consent history, and is counted on GET /v1/consent/{phone} (blocked_sends, last_blocked_at).
  • message.help_requested: emitted when a recipient texts HELP.
  • Replies in your name: STOP, START and HELP replies now name your business, and a registered number sends exactly the replies its registration filed, with your support contact. They used to name Delivered.
  • START is confirmed: someone who was opted out gets one "you are resubscribed" reply. A repeat STOP no longer sends a second confirmation.
  • consent.get() is also available as contacts.consent(phone) in the Node and Python SDKs.
  • The suppression list fails closed: if it cannot be read, a send answers 503 with Retry-After instead of going out unchecked.

2026-10-05: Delivered is now SimpleSMS

The product has a new name and a new home, joinsimplesms.com. It is the same service, the same account, the same prices and the same terms; nothing you built has to change. Apart from the API host, everything issued under the Delivered name keeps working, with no end date:

  • API host: this one changes. api.deliveredsms.com and mcp.deliveredsms.com are retired and answer 410 host_retired with the new host in the body. Point your base URL at https://api.joinsimplesms.com/v1 (MCP: https://mcp.joinsimplesms.com). Paths, request shapes and your key are unchanged.
  • API keys. dsms_sk_... keys (and resms_sk_...) authenticate forever. Only newly created keys get the new ssms_sk_ prefix.
  • Webhook headers. Every delivery carries simplesms-signature / simplesms-event-id and, with identical values, dsms-signature / dsms-event-id (and the resms- pair). Signing secrets are unchanged.
  • Response header. X-Delivered-Sender-State is still sent, alongside X-SimpleSMS-Sender-State.
  • Node package. npm install deliveredsms still works: it re-exports the new joinsimplesms package, and Delivered / DeliveredError are aliases of SimpleSMS / SimpleSMSError (the same classes).
  • CLI. deliveredsms and dsms still run; the new command is simplesms. A key saved in ~/.deliveredsms.json is still read.
  • Environment variables. The SDKs and CLI read SIMPLESMS_API_KEY and SIMPLESMS_BASE_URL first, then DELIVERED_API_KEY and DELIVERED_BASE_URL.
  • Agent skills. /skills/delivered and /skills/delivered-verify redirect to /skills/simplesms and /skills/simplesms-verify.
  • Your data. Numbers, webhook endpoints, registrations, opt-outs and message history were not migrated or re-created. They are where they were.

What does change, and when you would notice:

  • Texts we send for you name SimpleSMS. The Verify template when you send no app_name (SimpleSMS code: 482193...), and the sandbox suffix on texts to your own phone. Your own message bodies and your own app_name are untouched.
  • Webhook requests identify as SimpleSMS-Webhooks/1.0 in User-Agent (was Delivered-Webhooks/1.0). Verify the signature, not the user agent.
  • The console lives at joinsimplesms.com. You sign in with the same account; the first visit to the new address asks you to sign in once.

To move over at your own pace: point your base URL at api.joinsimplesms.com, install joinsimplesms, rename Delivered to SimpleSMS, and read simplesms-signature in your webhook handler. None of it is required.

2026-10-04: Sender status

  • Numbers show where they stand. Every number carries sender (test_only, pending, active, action_needed with a plain reason). New GET /v1/numbers/{number}, and the number.sender_updated event. See Numbers.
  • Test only until registered. A live US number that is not linked to an approved registration can text your verified numbers and nobody else. Other sends answer 403 sender_not_registered with X-Delivered-Sender-State. This replaces the X-Delivered-Registration / X-Delivered-Warning headers, which are gone: unregistered traffic is now stopped instead of warned about.
  • Automatic linking. When a registration is approved, the account's live numbers are linked to it and become active; numbers bought later link on their own. POST /v1/numbers/{number}/registration chooses a registration explicitly (up to 49 numbers each).
  • One form to go live. Submitting a registration from a sandbox account is also the live-access request. Submit now requires complete business details and answers 400 naming what is missing.

2026-10-04: Automations

  • Event-driven flows: POST /v1/track (events.track in the SDKs) records what a person did; a flow listening for that event sends, waits, waits for another event with a timeout, and branches. See Automations.
  • /v1/automations: create, edit, activate, pause, and read runs with a step-by-step timeline. New key scope automations.
  • Webhook events: automation.run.started, automation.run.completed, automation.run.failed.
  • Console: Automations, with three starter templates and a "Send a test event" button that works in the sandbox.

2026-10-04: Contacts API

  • /v1/contacts: create-or-update by phone number, retrieve, update, delete, and list with tag and phone_number filters. The same address book the console uses. See Contacts.
  • POST /v1/contacts/import: bulk upsert, up to 500 per request, with skipped rows reported by index.
  • POST /v1/contacts/bulk: add tags, remove tags, or delete for up to 500 contacts in one call.
  • New key scope contacts. contacts resource in the Node and Python SDKs.

2026-10-01: Message observability

  • Message timeline: every message records each step with a timestamp (accepted → validated → queued → sent_to_carrier → carrier_accepted → delivered/failed; inbound: received) as timeline on GET /v1/messages/{id}.
  • segments, encoding, price, destination_carrier on every message.
  • Readable failures: failed messages, message.failed events, and refused sends (opt-out, content block, rate limit, spend limit) carry a failure object with a stable code, a plain explanation, and what to do. See delivery failures.
  • List filters: status, direction, to, from, created_after, created_before (alongside customer_id) on GET /v1/messages, with full pages. Automatic carrier retries show up on the timeline per attempt.
  • Sandbox numbers for every failure, opt-out, rate limiting, and a really delayed delivery. The happy-path number now settles to delivered instead of staying sent.
  • Idempotency-Key now applies to scheduled sends too.
  • Console: message filters and a message inspector (timeline latencies, cost, failure, related webhook events).

2026-10-01: Reliability

  • Automatic carrier retries: temporary carrier failures no longer fail a send. POST /v1/messages answers 202 with the message queued and we retry it after 30s, 2m and 10m. New message fields: attempts, next_attempt_at. A message is never submitted twice.
  • Missing delivery reports: a sent message with no delivery report after 72 hours is marked receipt_status: "missing". Its status stays sent.
  • Idempotency-Key on POST /v1/verify and POST /v1/numbers. Failed requests now release their key.
  • Webhook delivery log: status code, latency, attempt and the first 2 KB of your endpoint's response for every attempt, in the console and at GET /v1/webhooks/deliveries. GET /v1/webhooks lists endpoints.
  • Replay to one endpoint: POST /v1/events/{id}/replay, and per-row Replay in the console.
  • Undelivered events: events whose retries ran out are kept for 30 days with one-click replay, instead of being dropped.
  • Status page (and /status.json) for the API, sending, inbound and webhooks.

2026-10-01: Customers and the Python SDK

  • Customers (/v1/customers): for platforms sending on behalf of other businesses. Assign numbers to a customer and its messages, verifications, events and webhooks carry customer_id; GET /v1/customers/{id}/usage reports per-customer usage by day. See Customers.
  • customer_id on POST /v1/messages, POST /v1/verify, POST /v1/numbers, new PATCH /v1/numbers/{number}, and filters on GET /v1/messages and GET /v1/numbers. Numbers now always include customer_id (null when unassigned).
  • Python SDK: pip install joinsimplesms. No dependencies, typed, retries, idempotent sends, webhook verification.
  • Node SDK: consent and customers resources, listAll() iterators, and verifyWebhook().

2026-10-01: Compliance autopilot (registration)

  • Website disclosure check: POST /v1/registrations checks your website, privacy policy, terms and opt-in page against what carrier reviewers look for, with evidence and copy-paste fixes for every finding.
  • Generated copy: opt-in disclosure, privacy clause, SMS terms, samples, HELP/STOP replies, and the full brand + campaign draft.
  • Registration workflow: recheck, submit, carrier review, rejections with plain-language reasons and fixes, resubmission; registration.updated events. See Compliance & registration.
  • Opt-in proof: proof on POST /v1/consent/{phone} and /v1/consent/export?type=ledger.
  • Live sends without an approved registration carry an X-Delivered-Registration warning header. Nothing is blocked.

2026-10-01: Account controls

  • Deliverability: GET /v1/deliverability and Console → Deliverability report delivery rates by day, carrier, and sending number, with failure reasons. Sharp drops raise a deliverability.degraded webhook event.
  • Spend limits: a monthly USD cap on live messaging with alert thresholds (GET/PATCH /v1/spend-limit). Sends past the cap return spend_limit_reached and are not charged; spend.threshold_reached fires at each threshold.
  • Audit log: key, team, webhook, spend-limit, number, consent, and settings changes, with actor and IP. Console → Audit log and GET /v1/audit-logs.
  • Key scopes: restrict a key to the endpoint families it needs; others answer 403 insufficient_scope. Existing keys keep full access.
  • Viewer role: read-only teammates.

2026-09-30: Spam scores retired

  • GET /v1/lookup/{phone}/spam now answers 410 Gone (endpoint_retired). Its scores came from data SimpleSMS no longer uses. GET /v1/lookup/{phone} (line type and carrier) is unchanged. The MCP lookup_spam tool and the CLI's --spam flag are gone; the SDK's lookup.spam() is deprecated and throws endpoint_retired.

2026-09-22: Pricing

  • Outbound SMS is $0.009 per message, all-in. Carrier fees are still included and A2P 10DLC registration is still free; the rate simply now covers what a US text costs to deliver. Verification, numbers, lookups, and the free tier are unchanged.
  • The pricing comparison now includes business-texting products (Text Request, Solutions by Text) alongside the API providers.
  • Revocation in plain English: "please stop texting me" now opts a number out, not just the STOP keyword. Three detection tiers (keyword, phrase, AI with confidence scores), per the FCC's April 2025 reasonable-means rule.
  • Consent ledger: every opt-out, opt-in, import and verification exemption is appended to a per-number history that is never deleted.
  • Consent API: GET/POST /v1/consent/{phone}, paginated GET /v1/consent, bulk /v1/consent/import (up to 500), and CSV /v1/consent/export.
  • Console Compliance page: suppression list with per-number history, import, export, and the verification-exemption audit log.
  • message.opted_out events now carry method and (for AI detections) confidence; verification.sent_to_opted_out is now subscribable as a webhook event.

2026-08-06: Early access launch

  • Sandbox-first API surface: /v1/messages (send, get, list, Idempotency-Key support), /v1/numbers (search, purchase, release), /v1/lookup (+/spam), /v1/events, and POST /v1/test/inbound for simulating inbound SMS.
  • Self-serve console at /console: instant free sandbox keys, no card.
  • Live mode (after live-access review): real number provisioning across 200+ US/Canada area codes and real SMS delivery.
  • Agent surface: OpenAPI (yaml · json), llms.txt, single-file docs (llms-full.txt), markdown twins of every docs page, an MCP server, and an agent skill (simplesms).

Known limitations

  • Live delivery receipts are not yet emitted; a live message's status stays sent (sandbox simulates the full lifecycle). Webhook endpoints shipped 2026-08-13.

Get product updates

New features and API changes, by email. Or follow the Atom feed.