Developer API · Reference

Phone numbers & SMS, one REST call away.

Everything bills pay-as-you-go from your CrowPhone credit balance. All endpoints accept and return JSON. Get a key on the Developers page, or start at the overview.

Authentication

Pass your key as a Bearer token on every request (except GET /countries). Keys start with cp_live_, are shown once at creation, and can be rotated anytime from the Developers page.

Authorization: Bearer cp_live_your_key_here

Endpoints

GET/api/v1/countriesno auth

Available countries with monthly number pricing, per-SMS rates and capabilities.

Parameters

None.

Sample request

curl https://www.crowphone.com/api/v1/countries

Sample response · 200

{
  "countries": [
    {
      "code": "SE",
      "name": "Sweden",
      "monthly_price": 4.60,
      "sms_receive_price": 0.03,
      "sms_send_price": 0.04,
      "capabilities": { "receive_sms": true, "send_sms": true, "voice": true }
    }
  ]
}

POST/api/v1/numbers

Buy a number, charged from your balance. PH/SE are mobile-class — best for receiving verification codes, and the only ones that can send SMS (US/CA are receive-only).

Parameters

NameInTypeRequiredDescription
countrybodystringoptionalISO country code (see GET /countries). Defaults to US — or SE when must_send_sms is true.
monthsbodyintegeroptionalRental length in months, 1–12. Default 1.
must_send_smsbodybooleanoptionalSet true if you need outbound SMS: receive-only countries are rejected up front, and with no country given we pick SE for you.

Sample request

curl -X POST https://www.crowphone.com/api/v1/numbers \
  -H "Authorization: Bearer cp_live_..." \
  -H "Content-Type: application/json" \
  -d '{"must_send_sms": true, "months": 1}'

Sample response · 200

{
  "id": "0f6f4a4e-…",
  "number": "+46700900123",
  "country": "SE",
  "months": 1,
  "price": 3.22,
  "expires_at": "2026-10-07T12:00:00.000Z",
  "balance": 46.78,
  "capabilities": { "receive_sms": true, "send_sms": true, "voice": true },
  "notes": [
    "Deliverability is strongest for same-region traffic (e.g. SE → EU). Note: US/CA destinations only accept registered US/CA senders — international numbers cannot text them, and such sends are rejected up front without charge."
  ]
}

GET/api/v1/numbers

List your app's active numbers.

Parameters

None.

Sample request

curl https://www.crowphone.com/api/v1/numbers \
  -H "Authorization: Bearer cp_live_..."

Sample response · 200

{
  "numbers": [
    {
      "id": "0f6f4a4e-…",
      "number": "+46700900123",
      "country": "SE",
      "expires_at": "2026-10-07T12:00:00.000Z",
      "created_at": "2026-09-07T12:00:00.000Z",
      "capabilities": { "receive_sms": true, "send_sms": true, "voice": true }
    }
  ]
}

DELETE/api/v1/numbers/:id

Release a number immediately. No refund for unused time — release when you're done with it.

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)requiredThe number's id from POST /numbers or GET /numbers.

Sample request

curl -X DELETE https://www.crowphone.com/api/v1/numbers/0f6f4a4e-… \
  -H "Authorization: Bearer cp_live_..."

Sample response · 200

{
  "released": true,
  "number": "+46700900123"
}

POST/api/v1/messages

Send an SMS from one of your numbers. Priced per 160-character segment (70 for emoji/unicode) at the destination country's rate; carrier-reported failures are refunded automatically.

Parameters

NameInTypeRequiredDescription
frombodystringrequiredOne of your app's active numbers, E.164 (e.g. +46700900123). Must be send-capable — US/CA numbers are rejected.
tobodystringrequiredDestination number, E.164.
bodybodystringrequiredMessage text, up to 1,600 characters. Long messages bill as multiple segments.

Sample request

curl -X POST https://www.crowphone.com/api/v1/messages \
  -H "Authorization: Bearer cp_live_..." \
  -H "Content-Type: application/json" \
  -d '{"from": "+46700900123", "to": "+46701234567",
       "body": "Your order shipped"}'

Sample response · 200

{
  "id": "b3e2c1d0-…",
  "sid": "SM8f3…",
  "from": "+46700900123",
  "to": "+46701234567",
  "segments": 1,
  "price": 0.04,
  "balance": 46.74,
  "status": "queued"
}

// Sends to US/CA destinations return 400: those carriers only accept
// registered US/CA senders, so no international number can text them.

GET/api/v1/messages

List messages across your numbers, newest first. Use this for polling if you don't set a webhook.

Parameters

NameInTypeRequiredDescription
numberquerystringoptionalFilter to one of your numbers, E.164.
directionquerystringoptional"inbound" or "outbound". Omit for both.
limitqueryintegeroptionalMax results, 1–100. Default 50.

Sample request

curl "https://www.crowphone.com/api/v1/messages?direction=inbound&limit=20" \
  -H "Authorization: Bearer cp_live_..."

Sample response · 200

{
  "messages": [
    {
      "id": "a1f9e8d7-…",
      "number": "+46700900123",
      "from": "+46701234567",
      "to": "+46700900123",
      "body": "Thanks!",
      "direction": "inbound",
      "price": 0.03,
      "created_at": "2026-09-07T12:05:00.000Z"
    }
  ]
}

GET/api/v1/balance

Your current credit balance.

Parameters

None.

Sample request

curl https://www.crowphone.com/api/v1/balance \
  -H "Authorization: Bearer cp_live_..."

Sample response · 200

{
  "balance": 46.74,
  "currency": "USD"
}

Errors

Errors are JSON with a human-readable message. Anything refundable is refunded before the error is returned.

400Invalid parameters — the message field says exactly what to fix.
401Missing, malformed, revoked, or unknown API key.
402Insufficient balance. The message includes the exact cost. Top up at /topup.
403Account not eligible (e.g. API unlocks at $50 in lifetime top-ups).
404Resource not found, or not owned by this app.
429Daily send cap reached for this app (default 500/day — open a support ticket to raise it).
502Carrier rejected the action. Any charge is already refunded — the message says "You have not been charged."

Inbound message webhooks

Set a webhook URL on your app and every text received by your numbers is POSTed to it within seconds. Verify the X-Crowphone-Signature header: it's sha256=HMAC-SHA256(raw_body, webhook_secret) using the secret shown when you created the app. No webhook? Poll GET /api/v1/messages instead.

POST https://yourapp.com/webhooks/crowphone
X-Crowphone-Signature: sha256=3f1a…

{
  "type": "message.received",
  "data": {
    "number": "+46700900123",
    "from": "+14155550123",
    "body": "Your code is 123456",
    "received_at": "2026-09-07T04:20:00.000Z"
  }
}

Good to know

  • Receiving verification codes: strict apps (WhatsApp, Google, Discord) often refuse virtual numbers. Mobile-class numbers (PH, SE) have the best acceptance odds; US/CA numbers are VoIP-class and get refused more.
  • Sending: US/CA numbers can't send SMS (carrier registration rules) — send from PH/SE numbers, or pass "must_send_sms": true when buying and we'll pick one for you.
  • Deliverability: European and most open-market destinations deliver reliably (e.g. SE → EU). Some destinations require carrier-registered senders — US & Canada (rejected up front, no charge) and the Philippines (rejected by the carrier, refunded automatically) are the known ones. Receiving works on every line from anywhere.
  • Fair billing: failed sends and undelivered messages are refunded automatically. Unanswered inbound calls cost nothing.
  • Limits: 500 outbound SMS per app per day by default — open a ticket to raise it.
  • Access: creating an API app requires $50 in lifetime top-ups. It's spendable credit, not a fee — it keeps the API spam-free.
  • Voice calling via API is coming soon; calls work today in the browser dialer.
Get your API key

API access unlocks at $50 in lifetime top-ups — all of it spendable credit for numbers and messages (and $50+ earns +12% bonus credits).