Developers

Headless SMS Number API

A real US number, every SMS sent to it, one HTTP call. No account, no sign-up, no API key: the payment is the credential. Settled in USDC on Stellar with the x402 protocol.

Read this first

  • No accounts, no recovery. A successful purchase returns a secret token exactly once. Lose it and the number is gone; we only store its hash and cannot reissue it.
  • No refunds. Extensions must be bought before expires_at. At expiry the number is deleted at the carrier and every message is purged. Nothing comes back.
  • We sell numbers, not services. Every SMS from any sender is delivered for the whole duration. Whether a third party accepts a number is up to them.
  • Receive-only. No sending, no voice. Lawful use only (see Terms).

Plans

20m

$2.00

20 minutes · all SMS, any sender

POST /api/v1/numbers/20m

1d

$3.00

24 hours · all SMS, any sender

POST /api/v1/numbers/1d

7d

$5.00

7 days · all SMS, any sender

POST /api/v1/numbers/7d

Any plan can also be bought as an extension: its duration is added to the current expires_at. Prices are in USD and settled as USDC. GET /api/v1/plans returns this table and the payment network.

Flow

curl
# 1. What is in stock (free)
curl https://receivesmsonline.us/api/v1/stock

# 2. Ask for a number → 402 Payment Required with a PAYMENT-REQUIRED header
curl -i -X POST "https://receivesmsonline.us/api/v1/numbers/20m?area_code=415"

# 3. Your x402 client signs a USDC payment on Stellar and retries with PAYMENT-SIGNATURE
#    → 201 { id, number, token, expires_at }
#    (see the Node example: the client library does steps 2 to 3 for you)

# 4. Wait for the code (long-poll up to 30 s)
curl -H "Authorization: Bearer rso_…" "https://receivesmsonline.us/api/v1/numbers/num_9f2c1a7e/messages?wait=30"

# 5. Need more time? Add 24 h to expires_at (paid, same x402 handshake)
curl -X POST -H "Authorization: Bearer rso_…" https://receivesmsonline.us/api/v1/numbers/num_9f2c1a7e/extend/1d
Node (x402 client)
import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client } from "@x402/core/client";
import { ExactStellarScheme } from "@x402/stellar/exact/client";
import { createEd25519Signer } from "@x402/stellar";

// npm i @x402/fetch @x402/core @x402/stellar
// Any funded Stellar account holding USDC. Testnet: stellar:testnet, mainnet: stellar:pubnet.
const network = "stellar:pubnet";
const signer = createEd25519Signer(process.env.STELLAR_SECRET!, network);
// The client caps spend at $1 per payment by default; raise it to cover the plan you buy.
const client = new x402Client()
  .register(network, new ExactStellarScheme(signer))
  .setSpendControls({ maxAmountPerPayment: "$5.00" });
const fetchPaid = wrapFetchWithPayment(fetch, client);

// One call: 402 → sign → retry → 201. Keep the token: it is the only credential.
const r = await fetchPaid("https://receivesmsonline.us/api/v1/numbers/20m?area_code=415", { method: "POST" });
const { id, number, token, expires_at } = await r.json();

// Stream every SMS as it arrives (Server-Sent Events over fetch).
const es = await fetch(`https://receivesmsonline.us/api/v1/numbers/${id}/stream`, { headers: { Authorization: `Bearer ${token}` } });
for await (const chunk of es.body!.pipeThrough(new TextDecoderStream())) process.stdout.write(chunk);

Endpoints

Method · pathAuthReturns
GET /plansnoneplans, prices, payment network
GET /stocknoneavailable numbers per area code
POST /numbers/{20m|1d|7d}
?area_code=415&webhook_url=https://…
x402 payment201 { id, number, plan, token, created_at, expires_at } · 409 out_of_stock (not charged)
GET /numbers/{id}Bearer tokenstatus, expires_at, message_count
GET /numbers/{id}/messages
?since=<msg id | ISO>&wait=0–30
Bearer tokenmessages oldest-first; long-poll with wait
GET /numbers/{id}/streamBearer tokenSSE: message, extended, expired; heartbeat every 15 s
POST /numbers/{id}/extend/{20m|1d|7d}Bearer + x402200 { id, plan_added, expires_at } · 401/410 are not charged
PUT /numbers/{id}/webhookBearer token{ url } or { url: null }
GET /numbers/{id}/messages/{msgId}/media/{n}Bearer tokenMMS attachment, proxied
DELETE /numbers/{id}Bearer token204, immediate teardown, no refund

Base URL https://receivesmsonline.us/api/v1. JSON everywhere, ISO 8601 UTC timestamps, CORS open to all origins. Free endpoints: 60 requests/min per IP. Long-poll: 5 concurrent per token. SSE: 2 per token. A token answers 410 Gone forever once its number expired.

Messages

code is a best-effort extraction of a 4–8 digit code (hyphenated codes are joined). It is generic (no per-service parsing) and null when nothing looks like a code. MMS attachments appear as media URLs on this API.

GET /messages
{
  "messages": [
    {
      "id": "msg_01JB…",
      "from": "+18005551234",
      "text": "Your code is 482-913",
      "code": "482913",
      "received_at": "2026-10-23T05:06:12Z"
    }
  ]
}

Webhooks

Pass webhook_url at purchase or set it later. Each SMS is POSTed once, with up to 3 retries (5 s timeout) while the number is live. Verify the signature with sha256(token) as the HMAC key; we never store the raw token either. https and public hosts only.

delivery
POST https://your.app/hook
X-RSO-Signature: sha256=<HMAC-SHA256(body, key = sha256(token))>

{ "id": "num_9f2c1a7e", "number": "+14155550137", "message": { …same object as above… } }

Payments

Errors

envelope
{ "error": { "code": "out_of_stock", "message": "No numbers available in area code 415." } }

Codes: invalid_request 400 · payment_required 402 · invalid_token 401 · not_found 404 · out_of_stock 409 · expired 410 · rate_limited / too_many_streams 429 · payments_unconfigured 503.

Privacy

Message bodies and codes are encrypted at rest and hard-deleted the minute the number expires (or when you call DELETE). They never appear in our logs. Numbers are single-use: once yours expires it is deleted at the carrier and never resold. Read the Privacy Policy.

Prefer a number you keep? The monthly plan is $3.99 per month with an inbox.