Skip to main content

Buy phone lines

POST /v1/phone-lines buys 1 to 10 numbers taken from GET /v1/phone-lines/available. Each number becomes a line of your workspace, ACTIVE and paid for its first month.
Requires a tenant-scoped key. With an OAuth / MCP token, only the workspace Owner may buy (phone_lines:purchase) — 403 PERMISSION_DENIED otherwise. The account holder must be verified first, in the dashboard — see identity verification.
Real side effect: this charges money. Each number costs the full monthly price (R$ 33,90 or US$ 33.90), taken from your wallet credits first and then from your saved card.

Endpoint

POST https://pilotstatus.com.br/v1/phone-lines

Headers

string
required
Any string up to 255 characters with no control characters — a UUID per purchase is the usual choice. Missing, empty or whitespace-only → 400 IDEMPOTENCY_KEY_REQUIRED; too long or with a control character → 400 IDEMPOTENCY_KEY_INVALID. See Idempotency.

Request body

string[]
required
1 to 10 distinct numbers, each exactly as GET /v1/phone-lines/available returned it in number: E.164 digits without + — 55, a two-digit area code starting 1–9, then 8 digits (551148637200). Numbers from different area codes can go in the same request.
numbers is the only accepted field. Anything else is refused with 400 UNKNOWN_FIELDS, naming the fields — in particular, the idempotency key is not a body field (the dashboard’s requestId does not exist here).

Example

Response: 200 with one result per number

The numbers are independent. Each one is charged and acquired on its own, in the order you sent them, and one that fails does not undo the others. So no single status describes the request: it answers 200 when it was processed, and the outcome of each number is in results[i].ok.
A 200 does not mean you bought anything. Every item can have failed. Always read results.
object[]
One entry per number, in the order sent.
string
The number, as you sent it.
boolean
true when the line was bought by this request.
string
Only when ok: true. The new line’s id, for GET /v1/phone-lines/{id} and the activation-code endpoints.
string
Only when ok: false. Why this number failed — see the table below.
string
Only when ok: false. Bilingual message (English | Portuguese) for that code.

Order of operations, per number

  1. Reserve the number under your Idempotency-Key (see below). Already reserved → REQUEST_ALREADY_PROCESSED.
  2. Check that no line holds it — in any workspace, yours included — and that no other purchase of it is in flight → otherwise NUMBER_UNAVAILABLE, nothing charged.
  3. Charge the full monthly price: wallet credits first, the remainder on the saved card. If the card step fails, the credits already taken are put back → PAYMENT_FAILED.
  4. Acquire the number at the carrier. If that fails, the full price is refunded to your wallet — including any part that was paid by card — → NUMBER_UNAVAILABLE or SUPPLIER_UNAVAILABLE.
  5. Create the line: status: "ACTIVE", currentPeriodEnd one month ahead, and the phone_line.purchased webhook event.
The charge happens before the acquisition on purpose: if the carrier sells us the number, it cannot be undone, and a refund to you is instant. There is no checkout link here (unlike extra numbers): with no credits and no saved card, the item fails with PAYMENT_FAILED. Fund the wallet first — in the dashboard (card or PIX), or with POST /v1/billing/checkout (wallet_topup, card only) — or save a card (add_card).

Whole-request errors

Anything other than 200 means no number was attempted by this request, with one exception — 500, see below. Checks run in this order:
A 500 or a timeout does not prove that nothing happened. The numbers are processed one after another, and a failure midway can come after earlier numbers were already charged and bought. Retry the same request with the same Idempotency-Key, then list your lines with GET /v1/phone-lines to see which numbers are yours.

Idempotency

The Idempotency-Key header is mandatory because a client that times out on this request has no other way to know whether money moved. What it guarantees, exactly:
  • The key is tracked per number, for one hour. Before anything else, each number is recorded under (your workspace, the key, the number). For the next hour, sending the same key again with that number charges nothing and buys nothing: the item answers ok: false, REQUEST_ALREADY_PROCESSED.
  • A replay does not return the original result. REQUEST_ALREADY_PROCESSED comes back whether the first attempt bought the number or failed. To know which, call GET /v1/phone-lines: a number that was bought is in your list.
  • A number that failed is locked under that key for the hour. After a PAYMENT_FAILED you top up and retry — with a new key, or the retry answers REQUEST_ALREADY_PROCESSED.
  • After the hour the key is forgotten. A number you bought then answers NUMBER_UNAVAILABLE (it is yours — there is no second charge); a number that had failed is attempted again. To retry a failed number, always use a new key.
  • Only the numbers are protected, not the request. Sending the same key with a different number buys that number.
  • A request refused as a whole records nothing. After any 400 or 403 above, fix the request and resend it with the same key.
  • Concurrent duplicates. If two deliveries of the same request are in flight together, each number proceeds in one of them; the other gets REQUEST_ALREADY_PROCESSED for it.
  • Scoped to your workspace. The same key sent by another workspace never collides with yours.
The record is kept in a cache. If that cache is unavailable, the protection is skipped rather than blocking purchases — two deliveries of the same request that land during such an outage could both charge. Send each purchase once and retry only on a timeout, a 5xx or a network error.
1

One key per purchase

Generate a UUID for each purchase the user makes and send it as Idempotency-Key. Use a generous client timeout: numbers are processed one after another.
2

On timeout, 5xx or network error

Resend the same body with the same key. Numbers already handled come back REQUEST_ALREADY_PROCESSED; numbers the first attempt never reached are processed now.
3

Reconcile

Call GET /v1/phone-lines and match by number to learn which lines you now hold.
4

Retry failures with a new key

For numbers that failed (PAYMENT_FAILED, SUPPLIER_UNAVAILABLE), fix the cause and send them with a new key.

After the purchase