
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.
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.
Open an account
An email and a password, or continue with Google. No contract, no monthly fee and no sales call.
Open an accountAdd 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.
BillingCreate 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.
API keysMake the request
Run the sample. The response states what the message cost, and the dashboard logs every request by key.
Send an SMS quickstart
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": "…"
}
}PACKETEXCHANGE_API_KEY.PHP, Go, Java, C# and Ruby - Try itAPI referenceEvery endpoint, with a console that sends the request with your key.
- ImportPostman and InsomniaThe whole API as a collection, with live and test environments.
- GenerateOpenAPI documentBuild a typed client in any language, or load it into your tools.
- WatchStatusLive checks of the API, messaging and calling, every minute.
- FollowChangelogEvery API change, dated, with the endpoints it touches.
- AskSupportA global team across time zones, reached from your dashboard.
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.
Verify API · SMS and voice OTP
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.
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.0200/minUK mobile call, cheapest live routeNo per-verification fee and checks are free. You pay for the text or the call that carries the code, plus the platform fee.
- Key scope
- verify:write
- Also in this job
- POST/verify/checkPOST/comms/voice-otp
Also on the API
- Number lookupLine type, network and cheapest price. Free.
- WebhooksSigned events for sends, calls and inbound texts, with resend.
- Do-not-call listNumbers on your list are suppressed from calls and SMS.
- x402 top-upsAn agent funds its own balance in USDC on Base.
- Switch APIRun a hosted Class-4 switch from code.
Verify API · SMS and voice OTP
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.
{
"to": "+447700900123",
"channel": "voice",
"language": "en",
"brand": "Acme"
}{
"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.0200/minUK mobile call, cheapest live routeNo per-verification fee and checks are free. You pay for the text or the call that carries the code, plus the platform fee.
- Key scope
- verify:write
- Also in this job
- POST/verify/checkPOST/comms/voice-otp
Pick a job, pick a language
Ten guides from key to working request, each with complete code in cURL, Node, Python, PHP, Go, Java, C# and Ruby, the response it returns and what it costs.
- MessagingSend an SMS
- VerificationVerify a phone number by SMS
- VerificationVerify a phone number by voice call
- VoiceMake a phone call
- VoiceBuild an AI voice agent
- Numbers and routingBuy a phone number
- Numbers and routingPrice a number (least-cost routing)
- Numbers and routingTest a caller ID on a route
- Numbers and routingCheck routes before you buy
- Webhooks and agentsReceive webhooks and verify signatures
- Webhooks and agentsConnect an AI agent over MCP
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.

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 in the open
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.
Pricing in one line
The carrier's rate, plus 2% capped at $0.001. Prepaid from $5.
No monthly fee and no per-verification fee. Card, crypto or wire; agents can top up with x402.
What changed in the API
Dated, with the endpoints each change touches and what keeps working.
Full changelog- 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
- 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
- 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
- Added
Route checks: check up to three routes before you buy
POST /routes/check places one short real call over each of 1 to 3 routes, in your order (the first is your primary, the rest backups), and returns a checkId; GET /routes/check/{id} gives each route's verdict (working, no capacity, not delivered, false answer, or not confirmed) with a plain sentence to show. A call answered faster than a real line can answer (under 1.5 seconds after our INVITE, or under 2.5 seconds with no ringing) is reported as a false answer, never as working, and is not charged. By default the call goes to a public line in the destination that answers by itself and is ended after about two seconds; where we have no such line yet, a lighter check confirms only that the route accepts calls and places no call to anyone. With mode ring_me the route calls your own phone instead. Each connected call is charged at the route's rate for the connected seconds plus the normal platform fee, from your test credit first and then your balance, and a call that does not connect costs nothing; GET /routes/check/coverage says whether we have a test line for a route, and when we do not, ring_me with a number of your own is the check to use; test keys return a simulated result with no call and no charge. POST /routes/check/{id}/purchase buys the routes that passed and puts them at the top of your routing order, primary first.
POST/routes/checkGET/routes/check/{id}GET/routes/checksGET/routes/check/coveragePOST/routes/check/{id}/purchase