Poll Agent Onboarding
curl --request POST \
--url https://api.bland.ai/v1/agent/onboarding/poll \
--header 'Content-Type: application/json' \
--data '
{
"device_code": "<string>"
}
'import requests
url = "https://api.bland.ai/v1/agent/onboarding/poll"
payload = { "device_code": "<string>" }
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({device_code: '<string>'})
};
fetch('https://api.bland.ai/v1/agent/onboarding/poll', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.bland.ai/v1/agent/onboarding/poll",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'device_code' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.bland.ai/v1/agent/onboarding/poll"
payload := strings.NewReader("{\n \"device_code\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.bland.ai/v1/agent/onboarding/poll")
.header("Content-Type", "application/json")
.body("{\n \"device_code\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.bland.ai/v1/agent/onboarding/poll")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"device_code\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"status": "pending",
"interval": 5,
"expires_in": 823
},
"errors": null
}
{
"data": {
"status": "approved",
"api_key": "org_...",
"org_id": "...",
"phone_number": "+14155550123",
"plan": {
"name": "agent_phone_basic",
"display_name": "Agent Phone Plan",
"status": "active",
"phone_number": "+14155550123",
"concurrency": 1,
"max_call_duration_minutes": 60,
"allowed_countries": ["US", "CA"],
"current_period_end": "2026-10-07T00:00:00.000Z"
},
"client_name": "my-bot"
},
"errors": null
}
{
"data": {
"status": "expired"
},
"errors": null
}
{
"data": null,
"errors": [
{
"error": "SLOW_DOWN",
"message": "Poll more slowly.",
"interval": 10
}
]
}
{
"data": null,
"errors": [
{
"error": "TOO_MANY_REQUESTS",
"message": "Too many requests. Try again later."
}
]
}
Agent Onboarding
Poll Agent Onboarding
Poll for the result of a device-authorization flow started with /v1/agent/onboarding/start. No API key required.
POST
/
v1
/
agent
/
onboarding
/
poll
Poll Agent Onboarding
curl --request POST \
--url https://api.bland.ai/v1/agent/onboarding/poll \
--header 'Content-Type: application/json' \
--data '
{
"device_code": "<string>"
}
'import requests
url = "https://api.bland.ai/v1/agent/onboarding/poll"
payload = { "device_code": "<string>" }
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({device_code: '<string>'})
};
fetch('https://api.bland.ai/v1/agent/onboarding/poll', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.bland.ai/v1/agent/onboarding/poll",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'device_code' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.bland.ai/v1/agent/onboarding/poll"
payload := strings.NewReader("{\n \"device_code\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.bland.ai/v1/agent/onboarding/poll")
.header("Content-Type", "application/json")
.body("{\n \"device_code\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.bland.ai/v1/agent/onboarding/poll")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"device_code\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"status": "pending",
"interval": 5,
"expires_in": 823
},
"errors": null
}
{
"data": {
"status": "approved",
"api_key": "org_...",
"org_id": "...",
"phone_number": "+14155550123",
"plan": {
"name": "agent_phone_basic",
"display_name": "Agent Phone Plan",
"status": "active",
"phone_number": "+14155550123",
"concurrency": 1,
"max_call_duration_minutes": 60,
"allowed_countries": ["US", "CA"],
"current_period_end": "2026-10-07T00:00:00.000Z"
},
"client_name": "my-bot"
},
"errors": null
}
{
"data": {
"status": "expired"
},
"errors": null
}
{
"data": null,
"errors": [
{
"error": "SLOW_DOWN",
"message": "Poll more slowly.",
"interval": 10
}
]
}
{
"data": null,
"errors": [
{
"error": "TOO_MANY_REQUESTS",
"message": "Too many requests. Try again later."
}
]
}
Overview
No authentication is required for this endpoint. Call it with thedevice_code from /v1/agent/onboarding/start, waiting at least the returned interval seconds between calls. See Connect your AI agent for the full flow.
This endpoint has two independent
429 responses: SLOW_DOWN when you poll faster than the per-device interval, and TOO_MANY_REQUESTS from the per-IP rate limit (600 requests per minute per IP, since a hosting platform’s shared egress address can carry many bots), which carries a Retry-After header instead of interval.Body Parameters
string
required
The
device_code returned by /v1/agent/onboarding/start.Response
object
Current state of the flow.
string
One of
pending, approved, expired.number
Present when
status is pending. Minimum seconds to wait before polling again.number
Present when
status is pending. Seconds remaining before the codes expire.string
Present only when
status is approved. A dedicated API key for the org, returned exactly once.string
Present when
status is approved. The org the key belongs to.string
Present when
status is approved. The number provisioned for this org.object
Present when
status is approved. The org’s Agent Phone Plan subscription. The same object is returned by GET /billing/agent_phone (as data) and by GET /v1/me (as plan).string
Internal plan identifier,
agent_phone_basic.string
Human-readable plan name,
Agent Phone Plan.string
Subscription status,
active.string
The number provisioned for this org’s Agent Phone Plan.
number
Maximum concurrent calls,
1.number
Maximum call length in minutes,
60.array
Country codes calls, transfers, and SMS are allowed to,
["US", "CA"].string
ISO 8601 timestamp for the end of the current billing period.
string
Present when
status is approved, if a client_name was given to /start.null | array
null unless polling too fast.{
"data": {
"status": "pending",
"interval": 5,
"expires_in": 823
},
"errors": null
}
{
"data": {
"status": "approved",
"api_key": "org_...",
"org_id": "...",
"phone_number": "+14155550123",
"plan": {
"name": "agent_phone_basic",
"display_name": "Agent Phone Plan",
"status": "active",
"phone_number": "+14155550123",
"concurrency": 1,
"max_call_duration_minutes": 60,
"allowed_countries": ["US", "CA"],
"current_period_end": "2026-10-07T00:00:00.000Z"
},
"client_name": "my-bot"
},
"errors": null
}
{
"data": {
"status": "expired"
},
"errors": null
}
{
"data": null,
"errors": [
{
"error": "SLOW_DOWN",
"message": "Poll more slowly.",
"interval": 10
}
]
}
{
"data": null,
"errors": [
{
"error": "TOO_MANY_REQUESTS",
"message": "Too many requests. Try again later."
}
]
}
An
expired status covers both an expired code and a device_code that was never valid. The two aren’t distinguished, so don’t rely on this response to debug a mistyped code, start over with a new /start call instead.Docs for agents: llms.txt
Was this page helpful?