Skip to content

Developer platform

The wholesale market, one API away.

SMS, voice, verification, phone numbers and AI voice agents on one key, over the routes carriers list on the marketplace. Pay the carrier's rate plus a fee capped at $0.001, prepaid from $5, with no contract.

  • One key for SMS, voice, numbers and AI voice
  • Carrier rate plus 2%, capped at $0.001
  • Prepaid from $5, no contract

Live, as this page was served

One request, priced before you send

price-number is public and needs no key. Ask it for any number and every live route that serves it comes back, cheapest first, with its billing increment and caller ID type.

price-number, UK mobile SMS
$ curl "https://packetexchange.io/api/v1/routes/price-number?number=447911123456&type=sms"

200 OKlive response

{
  "number": "447911123456",
  "unit": "msg",
  "total": 3,
  "routes": [
    {
      "rate": "0.020250",
      "matchedPrefix": "44",
      "billingIncrement": "1/1",
      "cliType": "full_cli"
    },
    …
  ]
}
Cheapest live UK mobile SMS$0.0203/msg

Start here

Your first request in four steps

From an empty terminal to a message on a wholesale route. The account is free to open; you pay only for what you send.

  1. Open an account

    An email and a password, or continue with Google. No contract, no monthly fee and no sales call.

  2. Add credit from $5

    Prepaid by card or crypto from $5, or by wire from $100. Each request draws the carrier’s rate plus a fee capped at $0.001.

  3. Create an API key

    Scope it to what it needs, such as sms:send, and keep it in the PACKETEXCHANGE_API_KEY environment variable. Test keys run a request through routing and pricing without sending it, on test credit that comes with an invitation.

  4. Make the request

    Run the sample. The response states what the message cost, and the dashboard logs every request by key.

curl https://packetexchange.io/api/v1/comms/sms \
  -H "Authorization: Bearer $PACKETEXCHANGE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to": "+447700900123", "from": "Acme",
       "message": "Your order 1042 has shipped."}'

200 OKresponse

{
  "success": true,
  "data": {
    "messageId": "…",
    "status": "accepted",
    "segments": 1,
    "cost": "…"
  }
}
Reads your key from PACKETEXCHANGE_API_KEY.PHP, Go, Java, C# and Ruby

What you can build

Everything your app says to a phone

Pick a product to see the call you would make, what comes back and what it costs. Prices are read from the live marketplace.

  1. Verify API · SMS, voice and call-in

    Verify a phone number

    Send a one-time code by text, or by a call that reads it aloud in English, Spanish, French, German, Portuguese or Hindi. We generate the code, keep only a hash of it and tell you if the user typed it right. Or skip the code with call-in: the user calls your own phone number from the DID Store, with no SMS to deliver.

    RequestPOST/api/v1/verify/start
    {
      "to": "+447700900123",
      "channel": "voice",
      "language": "en",
      "brand": "Acme"
    }
    Response200 OK
    {
      "verificationId": "…",
      "channel": "voice",
      "status": "pending",
      "sendStatus": "initiated",
      "expiresAt": "…"
    }

    Then POST /verify/check with the code: approved, denied, expired or max_attempts.

    What it costs
    $0.0203/msgUK mobile SMS, cheapest live route$0.0191/minUK mobile call, cheapest live routeCodes: no per-verification fee and checks are free. You pay for the text or the call that carries the code, plus the platform fee. Call-in: your phone number's monthly price plus $0.01 per approved verification, nothing if it expires.
    Key scope
    verify:write
    Also in this job
    POST/verify/checkGET/verify/{id}POST/verify/call-in/numbersPOST/comms/voice-otp

Why developers choose it

The tools you expect, at the price carriers pay

A typical messaging platform resells the wholesale market with its own margin on top. Here you are on the market itself, with a developer toolkit built around it.

A developer typing on a laptop open at the PacketExchange API reference quick start
  • Wholesale rates, one capped fee

    You pay the rate the carrier listed plus 2%, never more than $0.001 per message or call. No retail markup.

  • Every route and price, side by side

    The marketplace lists each route with its price, caller ID type and the quality its seller states.

  • One key, one balance

    SMS, voice, verification, numbers and AI voice on one prepaid balance, with scopes on every key.

  • Test keys

    Run the full request through routing and pricing without delivering anything or touching your live balance.

  • Signed webhooks you can replay

    Timestamped HMAC signatures, a delivery log, and resend for anything your endpoint missed.

  • Typed SDKs and a full reference

    Node.js and Python clients, and an OpenAPI reference generated from the API itself.

  • Usage per key

    Requests, error rate and latency for each key, so you can see which service is calling.

  • x402 for agents

    An agent tops up its own balance with one signed USDC payment on Base, no card on file.

$0.001the most the platform fee can be, per message or call

The carrier's rate, plus 2% capped at $0.001. Prepaid from $5.

No monthly fee and no per-verification fee on codes. Card, crypto or wire; agents can top up with x402.

API changelog

What changed in the API

Full changelog
  1. Added

    Call-in verification in the Verify API

    POST /verify/start takes a new channel, call_in: instead of sending a code, it returns callNumber and callNumberDisplay, one of your own phone numbers, which your user calls from the phone being verified. Buy the number in the DID Store, in the country of the people you verify, and switch it on with POST /verify/call-in/numbers or in the control panel; while it is on, calls to it are used for verification only and do not ring. GET /verify/call-in/numbers lists your numbers and which are on, and DELETE /verify/call-in/numbers/{phoneNumberId} switches one off. The call is matched by caller ID and ended without being answered, so it is free for the caller, and the verification is approved as soon as it arrives. It costs $0.01 per approved verification from your balance, on top of the number's monthly price; an expired one is free. Each call-in number verifies phone numbers in its own country; starting one for a country where you have no call-in number is refused with a 400 that says how to add one, or to use sms or voice. expirySeconds defaults to 300 for call_in. Every start now accepts an optional reference (your own id, echoed back), and starting again with the same reference or number while one is pending returns the pending verification. GET /verify lists your verifications, filterable by reference, status and channel. On test keys, POST /verify/{id}/simulate-call approves a pending call_in verification without a call. Two new webhook events: verification.approved (for every channel, when a code is approved or a call-in call arrives) and verification.expired (call_in only). POST /verify/check on a call_in verification is a 400, since there is no code. Existing sms and voice integrations are unchanged.

    POST/verify/startGET/verify/{id}GET/verifyGET/verify/call-in/numbersPOST/verify/call-in/numbersDELETE/verify/call-in/numbers/{phoneNumberId}GET/verify/call-in/coveragePOST/verify/{id}/simulate-call

  2. Added

    Send a test SMS over an SMS route before you buy

    POST /routes/check/sms sends one short fixed message ("PacketExchange test message: this route delivered to your phone. Ref K7QD") over exactly the SMS route you name to your own mobile, which the route must cover, and returns a checkId; GET /routes/check/{id} reports accepted (the route took it, no receipt yet), delivered (a carrier receipt confirmed it) or refused (with errorCode, and the carrier's own stat and err values when a receipt said it failed). It is charged at the route's price for one message plus the normal platform fee, from your test credit first; a refused message is not charged and one whose receipt says it failed is refunded. The text and sender are fixed. Limits: 3 test messages to one number an hour, 5 different numbers and 20 test messages per account a day. Test keys return a simulated result and send nothing. Tests appear in GET /routes/checks with mode sms and never count in SMS volume, revenue or quality figures. Route check results gain the accepted, delivered and refused values and the checkType sms.

    POST/routes/check/smsGET/routes/check/{id}GET/routes/checks

  3. Added

    Automatic failover on every Smart Routing call and SIP trunk

    A call placed without a routeId that a route refuses before it is answered (SIP 403, 480, 500, 502, 503, 504 or no response) is now tried straight away on your next route: your routing order for that number, else Smart Routing's next choice, up to three routes. Only the route that connects is billed; a wrong number (404, 484), a busy or declined call and no answer are never retried, and a Voice API call that has started ringing is never moved to another route. The response, the call.completed webhook and GET /comms/calls/{id} name the route that carried the call (routeId) and list the attempts when there was more than one. Calls over your SIP trunk fail over across your purchased routes for the number in the same order when a route answers with a server error or congestion (5xx), and GET /purchases/failover shows your first choice and backups per destination.

    POST/comms/callsGET/comms/calls/{id}GET/purchases/failover

  4. Added

    Measured route quality on every listing

    Marketplace listings now carry a measured object: ASR, ACD, NER (the share of calls the network delivered to the phone: answered, busy, unanswered or declined) and median PDD, measured on real buyer calls over the last 7 days, else 30 days, else the most recent period that had enough. It is null until a listing has carried at least 50 calls from at least two buyers; route checks, test calls, the seller's own traffic and calls refused before dialling are not counted, and a call that failed over counts once on each route it tried. Rows also carry routeChecks (the last 7 days of route checks, or null). The seller-stated expectedAsr, expectedAcd and expectedPdd are unchanged. New sorts: measured_asr_desc, measured_asr_asc, measured_acd_desc, measured_acd_asc, ner_desc, ner_asc and quality_desc. The Exchange Score uses measured figures when a listing has them for the last 7 or 30 days. Signed-out callers get the call count as a band and no buyer count.

    GET/routesGET/routes/{id}GET/routes/price-number

Send your first message today

Open an account, add credit from $5 and create a key. Wholesale rates from the first request, with no contract and no monthly fee.