curl --request POST \
--url https://api.sentfrom.ai/v1/agent-signups \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"name": "My agent"
}
'import requests
url = "https://api.sentfrom.ai/v1/agent-signups"
payload = { "name": "My agent" }
headers = {
"Idempotency-Key": "<idempotency-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Idempotency-Key': '<idempotency-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({name: 'My agent'})
};
fetch('https://api.sentfrom.ai/v1/agent-signups', 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.sentfrom.ai/v1/agent-signups",
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([
'name' => 'My agent'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$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.sentfrom.ai/v1/agent-signups"
payload := strings.NewReader("{\n \"name\": \"My agent\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
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.sentfrom.ai/v1/agent-signups")
.header("Idempotency-Key", "<idempotency-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"My agent\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sentfrom.ai/v1/agent-signups")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"My agent\"\n}"
response = http.request(request)
puts response.read_body{
"tenant_id": "<string>",
"inbox": {
"id": "<string>",
"address": "jsmith@example.com"
},
"api_key": "<string>",
"onboarding_state": "unclaimed",
"capabilities": {
"receive": true,
"read": true,
"send": true,
"manage": true
},
"limits": {
"inboxes": 2,
"received_messages": 1,
"received_bytes": 1
},
"unclaimed_expires_at": "2023-11-07T05:31:56Z",
"claim_url": "<string>",
"claim_expires_at": "2023-11-07T05:31:56Z",
"instructions": [
"<string>"
]
}{
"tenant_id": "<string>",
"inbox": {
"id": "<string>",
"address": "jsmith@example.com"
},
"api_key": "<string>",
"onboarding_state": "unclaimed",
"capabilities": {
"receive": true,
"read": true,
"send": true,
"manage": true
},
"limits": {
"inboxes": 2,
"received_messages": 1,
"received_bytes": 1
},
"unclaimed_expires_at": "2023-11-07T05:31:56Z",
"claim_url": "<string>",
"claim_expires_at": "2023-11-07T05:31:56Z",
"instructions": [
"<string>"
]
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}Create an agent account
Create a receive-only inbox and credentials before the human claims the account.
curl --request POST \
--url https://api.sentfrom.ai/v1/agent-signups \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"name": "My agent"
}
'import requests
url = "https://api.sentfrom.ai/v1/agent-signups"
payload = { "name": "My agent" }
headers = {
"Idempotency-Key": "<idempotency-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Idempotency-Key': '<idempotency-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({name: 'My agent'})
};
fetch('https://api.sentfrom.ai/v1/agent-signups', 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.sentfrom.ai/v1/agent-signups",
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([
'name' => 'My agent'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$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.sentfrom.ai/v1/agent-signups"
payload := strings.NewReader("{\n \"name\": \"My agent\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
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.sentfrom.ai/v1/agent-signups")
.header("Idempotency-Key", "<idempotency-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"My agent\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sentfrom.ai/v1/agent-signups")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"My agent\"\n}"
response = http.request(request)
puts response.read_body{
"tenant_id": "<string>",
"inbox": {
"id": "<string>",
"address": "jsmith@example.com"
},
"api_key": "<string>",
"onboarding_state": "unclaimed",
"capabilities": {
"receive": true,
"read": true,
"send": true,
"manage": true
},
"limits": {
"inboxes": 2,
"received_messages": 1,
"received_bytes": 1
},
"unclaimed_expires_at": "2023-11-07T05:31:56Z",
"claim_url": "<string>",
"claim_expires_at": "2023-11-07T05:31:56Z",
"instructions": [
"<string>"
]
}{
"tenant_id": "<string>",
"inbox": {
"id": "<string>",
"address": "jsmith@example.com"
},
"api_key": "<string>",
"onboarding_state": "unclaimed",
"capabilities": {
"receive": true,
"read": true,
"send": true,
"manage": true
},
"limits": {
"inboxes": 2,
"received_messages": 1,
"received_bytes": 1
},
"unclaimed_expires_at": "2023-11-07T05:31:56Z",
"claim_url": "<string>",
"claim_expires_at": "2023-11-07T05:31:56Z",
"instructions": [
"<string>"
]
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}Headers
Credential-like high-entropy secret. Generate at least 32 random bytes encoded as URL-safe text, save privately before sending, and reuse with the exact saved body for retries. Never log this header.
32 - 128^[A-Za-z0-9_-]{32,128}$Body
Workspace display name. Trimmed; control characters are rejected. Defaults to Agent workspace.
1 - 100Optional inbox local part. Trimmed and lowercased; letters, digits, dots, underscores and hyphens, with a letter or digit at each end and no consecutive dots. Reserved or occupied names are rejected. Omit to allocate a name.
1 - 64Response
Original signup response replayed; the inbox and API key are unchanged.
Show child attributes
Show child attributes
Save privately before proceeding. Bearer credential for this tenant; unchanged across signup replays and claiming.
"unclaimed"Show child attributes
Show child attributes
Show child attributes
Show child attributes
Account expiry unless claimed, seven days by default.
Private console claim URL, with a separate bearer secret in the #token fragment. Share only with the operator in an existing trusted channel; never log or email it.
Link expiry, default 30 minutes, bounded by account expiry. A new link does not extend account lifetime.

