Quickstart
Key to code in five requests.
Quote, buy, wait, read, finish. Everything you need to receive your first verification code through the API, with copy-paste examples in curl, JavaScript and Python.
Invite-only for now
not_available for now. Demo inventory — fictional numbers and simulated codes, marked demo: true — works end to end, so you can build against it today.Signed-in accounts create keys under Dashboard → API keys. New sign-ups are on a waitlist for now.
Terminal export PASSCODE_API_KEY="pc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # Check it works: returns your account and balance curl https://passcode.sh/api/v1/me -H "Authorization: Bearer $PASSCODE_API_KEY"Ask what a WhatsApp number in the US costs right now. Quotes come ranked; the first in-stock one is flagged
recommended. Skip this step if you don’t care about price — creating an order picks the recommended quote for you.GET/v1/quotecurl -G https://passcode.sh/api/v1/quote \ -H "Authorization: Bearer $PASSCODE_API_KEY" \ -d service=whatsapp \ -d country=USdata[0] { "offer_id": "ofr_3Lk8XpN2vQ7rT4mZ9cBw", "service": { "slug": "whatsapp", "name": "WhatsApp" }, "country": { "iso2": "US", "name": "United States", "dial_code": "+1" }, "price": "0.895", "price_micros": 895000, "list_price": "0.895", "list_price_micros": 895000, "stock": 318, "success_rate": 0.95, "avg_delivery_seconds": 6, "recommended": true, "demo": true }Buy the number. Your balance is charged now and you get the order back in
waitingwith aphone_number. Enter that number in the app you’re verifying. The Idempotency-Key makes the request safe to retry.POST/v1/orderscurl https://passcode.sh/api/v1/orders \ -H "Authorization: Bearer $PASSCODE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "service": "whatsapp", "country": "US", "max_price": "1.00" }'Response · 201 { "id": "ord_7Hq2LmX9vB3kR8tN4cYp", "status": "waiting", "service": { "slug": "whatsapp", "name": "WhatsApp" }, "country": { "iso2": "US", "name": "United States", "dial_code": "+1" }, "phone_number": "+12025550147", "price": "0.895", "price_micros": 895000, "code": null, "messages": [], "strategy": "best", "source": "api", "created_at": "2026-10-06T14:02:03.000Z", "expires_at": "2026-10-06T14:22:03.000Z", "received_at": null, "completed_at": null, "cancelled_at": null, "refunded_at": null, "can_cancel": true, "can_finish": false, "demo": true }Most codes arrive within seconds. Poll the order every few seconds until it leaves
waiting— or configure a webhook and we’ll POSTorder.code_receivedto you the moment it lands. If nothing arrives within 20 minutes the order becomesexpiredand is refunded.Poll an orderasync function waitForCode(orderId) { for (;;) { const res = await fetch(`https://passcode.sh/api/v1/orders/${orderId}`, { headers: { Authorization: `Bearer ${process.env.PASSCODE_API_KEY}` }, }); const order = await res.json(); if (order.status !== "pending" && order.status !== "waiting") return order; // received, expired… await new Promise((resolve) => setTimeout(resolve, 3000)); } }Got the code? Finish the order to release the number. Changed your mind before any SMS arrived? Cancel it for an immediate, full refund. Do neither and it settles itself at
expires_at.POST/v1/orders/{id}/finishcurl -X POST https://passcode.sh/api/v1/orders/ord_7Hq2LmX9vB3kR8tN4cYp/finish \ -H "Authorization: Bearer $PASSCODE_API_KEY"POST/v1/orders/{id}/cancelcurl -X POST https://passcode.sh/api/v1/orders/ord_7Hq2LmX9vB3kR8tN4cYp/cancel \ -H "Authorization: Bearer $PASSCODE_API_KEY"
All together
The whole flow as one script. Run it, type the number into the app, and watch the code print.
// quickstart.mjs — Node 18+: PASSCODE_API_KEY=pc_live_… node quickstart.mjs
const API = "https://passcode.sh/api/v1";
async function api(method, path, { body, headers = {} } = {}) {
const res = await fetch(`${API}${path}`, {
method,
headers: {
Authorization: `Bearer ${process.env.PASSCODE_API_KEY}`,
...(body ? { "Content-Type": "application/json" } : {}),
...headers,
},
body: body ? JSON.stringify(body) : undefined,
});
const json = await res.json();
if (!res.ok) throw new Error(`${json.error.code}: ${json.error.message}`);
return json;
}
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// 1. Quote: the best WhatsApp number in the US right now.
const { data: quotes } = await api("GET", "/quote?service=whatsapp&country=US");
const best = quotes.find((q) => q.recommended);
if (!best) throw new Error("Nothing in stock right now. Try another country.");
console.log(`Best offer: $${best.price}, ${Math.round(best.success_rate * 100)}% expected success`);
// 2. Buy exactly that offer. The Idempotency-Key makes a retry safe.
let order = await api("POST", "/orders", {
body: { service: "whatsapp", offer_id: best.offer_id },
headers: { "Idempotency-Key": crypto.randomUUID() },
});
console.log(`Enter this number in WhatsApp: ${order.phone_number}`);
// 3. Wait for the code (or use the order.code_received webhook instead).
while (order.status === "pending" || order.status === "waiting") {
await sleep(3000);
order = await api("GET", `/orders/${order.id}`);
}
// 4. Use it, then finish. No code? The order is already refunded.
if (order.code) {
console.log(`Your code: ${order.code}`);
await api("POST", `/orders/${order.id}/finish`);
} else {
console.log(`No SMS arrived (${order.status}); refunded at ${order.refunded_at}.`);
}Next: handle errors properly, and switch from polling to webhooks once you’re in production.