Docs
Phone numbers

Buy a phone number

POSThttps://api.norreach.app/v1/phone-numbers

Asks to buy a number from GET /phone-numbers/available, under the owner's rules: the key needs the numbers:buy scope (in no preset — tick it on purpose) and an owner's or admin's role; the workspace's DAILY LIMIT for numbers bought through the API and its MONTHLY-COST CEILING are enforced by the database, so parallel requests can't race past them (429 number_cap_reached with reason and the caps — defaults 2 a day and 20.00 USD a month, changed by owners and admins in Settings › API & webhooks). The purchase WAITS IN APPROVALS (202, approval_key) until a person approves it — in the app, or with approvals:decide + numbers:buy — and is bought at that moment through the app's own purchase, every check run again (the number still on sale and its price, the caps, the country's rules and business verification, the role, the outreach pause). An owner can switch on "API may buy numbers without approval"; then it's bought at once (201, or 202 while the order settles). The same number asked for again while it waits answers the waiting request. 409 with reason number_taken / price_unconfirmed / verification_required / purchase_failed; nothing is ever charged on a refusal. Releasing a number is done in the app only. dry_run=true checks everything and buys nothing. Fires number.purchased.

⚠ numbers:buyRole must allow: numbers.buyIdempotency-Key requiredSupports dry_runOperation id: buy_phone_number
POST/phone-numbers
curl -X POST "https://api.norreach.app/v1/phone-numbers" \
  -H "Authorization: Bearer $NORREACH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "number": "+46812345679",
  "country": "SE",
  "type": "local",
  "label": "Stockholm sales"
}'
Buy a phone number
{
  "object": "number_purchase",
  "number": "+46812345679",
  "status": "awaiting_approval",
  "dry_run": false,
  "approval_key": "number_buy:2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
  "phone_number": null,
  "monthly_price": {
    "amount_minor": 300,
    "currency": "USD"
  },
  "caps": {
    "daily_limit": 2,
    "bought_today": 0,
    "monthly_ceiling": {
      "amount_minor": 2000,
      "currency": "USD"
    },
    "committed_this_month": {
      "amount_minor": 0,
      "currency": "USD"
    }
  },
  "note": "Waiting in Approvals — nothing is bought until an owner or admin approves it."
}

Authorizations

Authorizationstringheaderrequired

Bearer authentication: send Authorization: Bearer <key>, with an API key or an OAuth access token. The key needs the scope numbers:buy. API keys and scopes

Query parameters

dry_runbooleanquery

Run every check and return what would happen, changing nothing.

Headers

Idempotency-Keystringheaderrequired

Any unique string (≤ 255). The same key with the same request returns the first answer for 24 hours.

Body

application/json

numberstringrequired

E.164, from GET /phone-numbers/available.

countrystringrequired
typeenumrequired
One of:localmobiletollfree
labelstring

Response

202application/json— Buy a phone number

object"number_purchase"required
numberstringrequired
statusenumrequired

awaiting_approval = waiting in Approvals (approval_key); bought = yours now (phone_number); pending = the order is still settling; would_buy / would_wait = a dry run.

One of:awaiting_approvalboughtpendingwould_buywould_wait
dry_runbooleanrequired
approval_keystring | nullrequired
phone_numberobject | nullrequired
monthly_priceobject | nullrequired
capsobjectrequired
Show child attributes
caps.daily_limitintegerrequired
caps.bought_todayintegerrequired
caps.monthly_ceilingobjectrequired
Show child attributes
caps.monthly_ceiling.amount_minorintegerrequired
caps.monthly_ceiling.currencystringrequired
caps.committed_this_monthobjectrequired
Show child attributes
caps.committed_this_month.amount_minorintegerrequired
caps.committed_this_month.currencystringrequired
notestringrequired

Errors

Errors are application/problem+json with a stable code.

StatusCodeMeaning
400bad_requestThe request couldn't be read.
400unknown_fieldThe request has a field this operation doesn't know.
400idempotency_key_requiredThis operation needs an Idempotency-Key header.
401unauthorizedA valid API key is required.
403insufficient_scopeThis API key doesn't have the scope this operation needs.
403feature_not_enabledThe API isn't switched on for this workspace.
403role_forbiddenThe key's creator's role can't do this.
409idempotency_in_progressA request with this Idempotency-Key is still running.
409conflictThat conflicts with the current state.
409outreach_pausedOutreach is paused for this workspace.
413too_largeThe request body is too large.
422validation_failedThe request has invalid fields.
422idempotency_mismatchThis Idempotency-Key was used with a different request.
429rate_limitedToo many requests. Slow down and try again.
429number_cap_reachedThe workspace's limit for buying numbers through the API is reached.
500server_errorSomething went wrong on our side.
503unavailableThe API isn't available right now. Try again shortly.