curl --request POST \
--url https://api.brilo.ai/v1/agent/onboarding/start \
--header 'Content-Type: application/json' \
--data '
{
"client_name": "Grok",
"prefill": {
"email": "maya@example.com",
"first_name": "Maya",
"last_name": "Chen",
"name": "Maya Chen",
"phone": "+14155550123"
}
}
'import requests
url = "https://api.brilo.ai/v1/agent/onboarding/start"
payload = {
"client_name": "Grok",
"prefill": {
"email": "maya@example.com",
"first_name": "Maya",
"last_name": "Chen",
"name": "Maya Chen",
"phone": "+14155550123"
}
}
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({
client_name: 'Grok',
prefill: {
email: 'maya@example.com',
first_name: 'Maya',
last_name: 'Chen',
name: 'Maya Chen',
phone: '+14155550123'
}
})
};
fetch('https://api.brilo.ai/v1/agent/onboarding/start', 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.brilo.ai/v1/agent/onboarding/start",
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([
'client_name' => 'Grok',
'prefill' => [
'email' => 'maya@example.com',
'first_name' => 'Maya',
'last_name' => 'Chen',
'name' => 'Maya Chen',
'phone' => '+14155550123'
]
]),
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.brilo.ai/v1/agent/onboarding/start"
payload := strings.NewReader("{\n \"client_name\": \"Grok\",\n \"prefill\": {\n \"email\": \"maya@example.com\",\n \"first_name\": \"Maya\",\n \"last_name\": \"Chen\",\n \"name\": \"Maya Chen\",\n \"phone\": \"+14155550123\"\n }\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.brilo.ai/v1/agent/onboarding/start")
.header("Content-Type", "application/json")
.body("{\n \"client_name\": \"Grok\",\n \"prefill\": {\n \"email\": \"maya@example.com\",\n \"first_name\": \"Maya\",\n \"last_name\": \"Chen\",\n \"name\": \"Maya Chen\",\n \"phone\": \"+14155550123\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.brilo.ai/v1/agent/onboarding/start")
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 \"client_name\": \"Grok\",\n \"prefill\": {\n \"email\": \"maya@example.com\",\n \"first_name\": \"Maya\",\n \"last_name\": \"Chen\",\n \"name\": \"Maya Chen\",\n \"phone\": \"+14155550123\"\n }\n}"
response = http.request(request)
puts response.read_body{
"device_code": "<string>",
"expires_in": 900,
"interval": 5,
"user_code": "7FK9-BHDQ",
"verification_url": "<string>",
"verification_url_complete": "<string>"
}Start pairing this assistant with a Brilo phone number
Returns a short code to show the user and a link they can open. They sign up, pay and approve on that page; you call /poll until it says completed, and that response carries your API key.
Read the user the user_code, or open verification_url_complete if you can open a link — and show the code either way. Codes last 15 minutes. Nothing is charged until the user approves it themselves.
Pass prefill with your owner’s name, email and phone if you know them, so their sign-up form arrives filled in.
curl --request POST \
--url https://api.brilo.ai/v1/agent/onboarding/start \
--header 'Content-Type: application/json' \
--data '
{
"client_name": "Grok",
"prefill": {
"email": "maya@example.com",
"first_name": "Maya",
"last_name": "Chen",
"name": "Maya Chen",
"phone": "+14155550123"
}
}
'import requests
url = "https://api.brilo.ai/v1/agent/onboarding/start"
payload = {
"client_name": "Grok",
"prefill": {
"email": "maya@example.com",
"first_name": "Maya",
"last_name": "Chen",
"name": "Maya Chen",
"phone": "+14155550123"
}
}
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({
client_name: 'Grok',
prefill: {
email: 'maya@example.com',
first_name: 'Maya',
last_name: 'Chen',
name: 'Maya Chen',
phone: '+14155550123'
}
})
};
fetch('https://api.brilo.ai/v1/agent/onboarding/start', 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.brilo.ai/v1/agent/onboarding/start",
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([
'client_name' => 'Grok',
'prefill' => [
'email' => 'maya@example.com',
'first_name' => 'Maya',
'last_name' => 'Chen',
'name' => 'Maya Chen',
'phone' => '+14155550123'
]
]),
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.brilo.ai/v1/agent/onboarding/start"
payload := strings.NewReader("{\n \"client_name\": \"Grok\",\n \"prefill\": {\n \"email\": \"maya@example.com\",\n \"first_name\": \"Maya\",\n \"last_name\": \"Chen\",\n \"name\": \"Maya Chen\",\n \"phone\": \"+14155550123\"\n }\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.brilo.ai/v1/agent/onboarding/start")
.header("Content-Type", "application/json")
.body("{\n \"client_name\": \"Grok\",\n \"prefill\": {\n \"email\": \"maya@example.com\",\n \"first_name\": \"Maya\",\n \"last_name\": \"Chen\",\n \"name\": \"Maya Chen\",\n \"phone\": \"+14155550123\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.brilo.ai/v1/agent/onboarding/start")
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 \"client_name\": \"Grok\",\n \"prefill\": {\n \"email\": \"maya@example.com\",\n \"first_name\": \"Maya\",\n \"last_name\": \"Chen\",\n \"name\": \"Maya Chen\",\n \"phone\": \"+14155550123\"\n }\n}"
response = http.request(request)
puts response.read_body{
"device_code": "<string>",
"expires_in": 900,
"interval": 5,
"user_code": "7FK9-BHDQ",
"verification_url": "<string>",
"verification_url_complete": "<string>"
}Body
What to call your assistant on the approval screen, e.g. "Grok". Shown to the owner as an UNVERIFIED claim, because anyone can send anything here — it helps a person recognise the request they just made, and it is not a credential. Omit it and the screen says "your assistant" instead, which is the honest fallback.
64"Grok"
Your owner's details, if you know them, so the sign-up form arrives filled in. Every field is optional; invalid values are dropped silently and never fail the request. Brilo does not store or log these: they travel only in the #fragment of verification_url_complete, which the owner's browser keeps to itself.
Show child attributes
Show child attributes
Response
Your half of the pairing. Returned ONCE and never again — only its hash is stored — so keep it until the pairing finishes or fails.
Seconds until the code stops working.
900
Seconds to wait between polls. Polling faster is throttled.
5
The short code to read out or show the user. They type it at verification_url. Drawn from an alphabet with no confusable characters, so it never contains O, I, L, U, 0 or 1.
"7FK9-BHDQ"
Where the user goes to type the code themselves.
The same page with the code already filled in. Use this when you can open a link for the user; use verification_url when you can only speak. Show the code either way — matching it against what you displayed is the check that stops someone being walked through this flow by an attacker.
