Skip to main content

Overview

The Agent onboarding API needs one browser visit: the owner opens a link, signs up, and approves the request. Headless onboarding removes that visit entirely. If your agent can approve a payment through its own agent wallet, it can sign up, pay for the first month of the Agent Phone Plan, and receive its API key and phone number, all in the same conversation. The owner’s only manual step is relaying a 6-digit code sent to their phone by text. Two calls, no API key required to start:
  1. POST /v1/agent/onboarding/headless/start: send the owner’s phone and email, and get back a session handle. A text with a verification code goes out to the phone immediately.
  2. POST /v1/agent/onboarding/headless/complete: send the code back along with a payment approval, and get back the API key, org ID, phone number, and plan.
Nothing is created until the code is verified and the payment settles. A declined payment creates nothing, and the response tells your agent how to fall back to the link-based flow instead.
This is a different path to the same result as the Agent onboarding API, not a replacement for it. Use headless onboarding when your agent can present a payment token from an agent wallet. Use the link-based flow when it can’t, or when the payment is declined.
A Link virtual card is not accepted. /complete takes two payment credentials: a shared payment token (spt_) from the Link CLI in payment.shared_payment_token, or the Link CLI answering the WWW-Authenticate: Payment challenge that /complete returns. A virtual card, such as the one a request_virtual_card tool mints, is refused. If your agent can only get a virtual card, it can’t finish headless: show the owner the fallback link from the response and let them open it. Don’t open that link from your own browser; the page is for the human owner and has a bot check.

Which flow to use

Prerequisites

  • An agent wallet that can approve a single-use shared payment token (spt_) scoped to a Stripe business profile and an exact amount, or answer a Machine Payments Protocol challenge. The Link CLI does both; a Link virtual card does not work here. See Paying with an agent wallet.
  • The owner’s phone number, to send the verification code to
  • The owner present in the conversation to relay that code back

The flow

1

Start the flow

Call POST /v1/agent/onboarding/headless/start with the owner’s phone, email, and an optional label for your agent. No API key is required, this is how an agent gets one.
Response
client_name is optional (up to 64 characters, letters, numbers, spaces, and ._/-). Send the name of the platform you run on (grok, openclaw, poke, meta, or your product’s name): it never reaches the owner and lets Bland see which assistants complete setup.payment_intent is optional: "shared_payment_token" if you will pay with an agent wallet, "none" if you won’t. With "none", and only when free signup is off, /start answers 402 PLAN_REQUIRED with the browser fallback before any text is sent, so the owner isn’t asked for a code the flow can’t use. Today free signup is on, so "none" proceeds like any other start. owner_phone must be E.164 (for example +14155551234). owner_email must be a valid email address.This call sends a 6-digit verification code to owner_phone by text and creates nothing else: no account, no organization, no charge. headless_session is valid for expires_in seconds (600, or 10 minutes) and is single-use.
2

Get the code from your owner

Ask the owner for the 6-digit code that was just texted to their phone. This is their only manual step in the entire flow.
3

Complete the flow

Call POST /v1/agent/onboarding/headless/complete with the session, the code, and a payment. Two payment credentials are accepted: a shared payment token in payment.shared_payment_token, shown here, or a Machine Payments Protocol credential answering the challenge /complete returns. If you don’t yet know the amount or the seller, send payment: { "request_challenge": true } first. That verifies the code, keeps the session alive, and returns a 402 whose WWW-Authenticate: Payment header carries the amount, the currency, and the seller’s network profile id. See Or let the 402 drive the payment.
Response
payment.shared_payment_token is the single-use token your agent wallet issued for this charge. The other accepted credential is an Authorization: Payment header built from the challenge (see Or let the 402 drive the payment). Card details, including a Link virtual card, are refused. Either credential settles the first month of the Agent Phone Plan ($14.99 first month, then $29.99/month).The session lasts 10 minutes from /start. The first successful code check, whether from a request_challenge call or a paying call, restarts that window once. A re-issued challenge doesn’t restart it again, so the wallet approval has to complete inside it. If the session expires, start over with a new /start call and a new code.next_steps is a short list of things your agent should know before its first call. It’s optional on the wire: treat a missing field the same as an empty list.
4

Store the key

api_key is returned exactly once. Store it immediately; a repeated /complete call with a spent session returns INVALID_SESSION rather than the key again.

Paying with an agent wallet

The Agent Phone Plan is $14.99 for your first month (50% off), then $29.99/month. The token you present must be scoped to the seller and the amount named in the payment challenge (see Or let the 402 drive the payment). Read them from the challenge rather than from this page: the price comes from the plan catalog and can change. At the time of writing the challenge names: A token is spent by one settled charge. If the payment fails, request a new token rather than retrying the same one. Prefer link-cli mpp pay, which reads the challenge and retries /complete for you (see Or let the 402 drive the payment). Mint the token yourself when you need to control the spend request. With the Link CLI (link-cli auth login once, approved by the owner in the Link app), decode the challenge to read the seller and the amount:
Then create a spend request with those values and wait for the owner to approve it in the Link app:
--context must be at least 100 characters; the owner reads it when approving. The approved request carries the spt_ token. Send it as payment.shared_payment_token in /complete, as shown above.

Or let the 402 drive the payment

/complete also speaks the Machine Payments Protocol. Send payment: {"request_challenge": true} with the session and the code, and the response is 402 PLAN_REQUIRED with a challenge instead of a free account:
request is base64url JSON with the amount, the currency, and the seller profile under methodDetails.networkId. A wallet that speaks the protocol reads the challenge, mints the token, and repeats the same request with Authorization: Payment <credential>; the credential wins over request_challenge on the retry. The Link CLI does the whole round trip, after link-cli auth login once:
The first call verifies the code, so the retry with the credential skips it. The 200 carries a Payment-Receipt header naming the settled payment. A credential that doesn’t verify (expired, or not issued by this server) answers 402 PAYMENT_CREDENTIAL_INVALID with a fresh challenge; repeat the request with request_challenge and no credential to get a new one. A body shared_payment_token wins over a credential; sending shared_payment_token and request_challenge together is a 400.

If the bank asks for extra verification

A token whose card requires 3D Secure can’t complete headlessly. /complete answers 402 CARD_DECLINED, cancels the payment attempt, and creates nothing. Continue through the bundled fallback link, where the owner can complete the verification in a browser.

Renewals

The token settles the first month only. The plan renews one month later against the card on file. If there is none, the plan goes past due and degrades to pay-as-you-go: the number is kept, and the owner adds a card at Billing & Plans in the dashboard, which their verified phone lets them sign in to.

Existing accounts

Headless onboarding creates new accounts only. If the phone or the email already belongs to a Bland account, /start and /complete answer 409 ACCOUNT_EXISTS. Connect that account through the Agent onboarding API instead, or add the plan from the dashboard.

Connecting without the plan

If your agent omits payment, /complete still verifies the code and answers 200 with phone_number: null, plan.status: "none", and provisioning: "ready". The account starts with free credits, calls from a shared Bland number, can’t text, and can’t call internationally until the owner completes a purchase. next_steps says how to change each of those. If free signup is ever switched off, the same request answers 402 PLAN_REQUIRED with the browser fallback bundled and a payment challenge (see Or let the 402 drive the payment). The session stays verified, so a follow-up /complete with a payment finishes without a second code.

Adding the plan later

Card details can’t pass through your agent, so adding the Agent Phone Plan to an account that started free takes one browser visit by the owner. Two ways, both with a card:
  1. The link flow, from your agent. Call POST /v1/agent/onboarding/start, show the owner the link and code, and poll. The owner signs in with their phone, adds a card, and picks the plan; the poll result carries the plan and the new phone number, and your existing key keeps working.
  2. The dashboard, by the owner. Billing & Plans. Ask “what’s my Bland phone number?” afterwards and your agent reads it from the account.
Both act on the organization the owner has selected in the dashboard. An owner who belongs to more than one should have this account’s organization selected (its org_id came back from /complete), and your agent should check that the poll result’s org_id matches before treating the plan as this account’s. International calling unlocks after any completed purchase: buying credits on that same billing page does it, and so does the plan for US and Canada calling. next_steps on the connect response names whichever path is available.

If the number isn’t ready yet

provisioning is "ready" when everything is in place, or "pending" when the payment settled but a phone number hasn’t been handed over yet. On "pending", phone_number is null and next_steps includes a line telling your agent to call POST /billing/subscribe_agent_phone with the new API key in a few minutes. That call retries provisioning without charging again, since the plan is already active.

If the payment is declined

A declined payment, a payment that needs extra verification from the owner’s bank, or a payment token that’s already used or rejected all answer the same way: 402 CARD_DECLINED. Nothing is created. The response bundles a device-flow fallback so your agent can continue without starting over:
402 CARD_DECLINED
fallback carries everything POST /v1/agent/onboarding/start returns except verification_url. Show verification_url_complete (or user_code) to the owner exactly as you would from that flow, then poll POST /v1/agent/onboarding/poll with device_code until the owner approves. The page behind that link is for the human owner and has a bot check: show the link, don’t open it from your own browser. fallback also rides along on 402 PLAN_REQUIRED and 409 ACCOUNT_EXISTS.

Error codes

Both endpoints: /headless/start only: /headless/complete only: A code isn’t only ever “wrong”: if the owner takes too long or guesses incorrectly too many times, the session is burned and /complete answers INVALID_SESSION even with the right code. Start over with a fresh /start call.

Buying credits

An agent can also buy prepaid credits directly, using a payment token from the owner’s agent wallet, no browser involved. This is how an organization without the Agent Phone Plan unlocks international calling: the plan itself is US and Canada only, and buying credits doesn’t change that, but a completed credit purchase clears the same bar international calling requires everywhere else on Bland. Buying credits requires an existing Bland API key. If your agent hasn’t onboarded yet, do that first.

POST /v1/agent/credits

Response
  • amount_usd: from $5 to $100, at most two decimal places.
  • shared_payment_token: the single-use spt_ token your agent wallet issued for this purchase.
  • idempotency_key (optional): a UUID. Send the same one to retry the exact same purchase without paying twice.
  • The body is strict: no other fields are accepted.
The balance rises within seconds, once the payment is confirmed; that’s why the response says balance_update: "pending" rather than reporting a new balance directly. international_unlocked is true only once the unlock has actually taken effect. It’s false, with a note explaining why, in two cases: your organization is on an active Agent Phone Plan (which stays US and Canada only regardless of balance), or the unlock is still settling (retry in a few minutes).

The buy_credits MCP tool

The same purchase is available as a tool on Bland’s hosted MCP server, scoped to your organization: Ask the owner to approve the amount in their agent wallet first, then pass the token it gives you. If the tool doesn’t answer within its own timeout, the purchase may still be going through: check the balance before retrying, and if you do retry, send the same amount_usd, shared_payment_token, and idempotency_key so the same purchase can’t be charged twice.

Who can buy credits

Both surfaces share one policy: the caller must be acting as an organization, as an owner, admin, or operator of it. A personal (non-org) API key, or a member without one of those roles, is refused.

Error codes

Both POST /v1/agent/credits and buy_credits share one policy entry point and refuse for the same reasons with the same messages. The MCP tool has no HTTP status: it surfaces the message text directly, or a generic message for anything unexpected.

Security notes

  • The verification code expires in 10 minutes and can only be checked a handful of times before the session is burned. Start over with a fresh /start call if it expires.
  • A session is single-use. Once /complete succeeds (or the session is spent by a decline), a repeated call returns INVALID_SESSION.
  • The API key is scoped to a new organization and can be revoked at any time from Settings > API Keys in the dashboard.
  • A declined payment creates nothing: no account, no organization, no charge left behind.
  • Payment challenges are signed and expire with the session’s 10-minute window. A credential built against a changed or expired challenge is refused.
  • Treat the returned api_key and any payment token like credentials: keep them out of logs and chat transcripts.

Next steps

Agent onboarding API

The link-based flow this one falls back to when payment isn’t available or is declined.

Agent Phone Plan

What’s included, limits, and how to cancel.

Docs for agents: llms.txt