curl --request GET \
--url https://api.aurous-labs.com/v1/characters \
--header 'X-Api-Key: <api-key>'import requests
url = "https://api.aurous-labs.com/v1/characters"
headers = {"X-Api-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-Api-Key': '<api-key>'}};
fetch('https://api.aurous-labs.com/v1/characters', 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.aurous-labs.com/v1/characters",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-Api-Key: <api-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"
"net/http"
"io"
)
func main() {
url := "https://api.aurous-labs.com/v1/characters"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Api-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.aurous-labs.com/v1/characters")
.header("X-Api-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.aurous-labs.com/v1/characters")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Api-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"object": "list",
"data": [
{
"id": "char_01HXMQ7Z3K8Y2NABCDEFGHJKMR",
"object": "character",
"name": "Aurora the Adventurer",
"status": "ready",
"refs": [
{
"pose": "front",
"url": "https://api.aurous-labs.com/storage/.../front.bin?token=…"
}
],
"created_at": "2026-05-08T10:00:00Z",
"updated_at": "2026-05-08T10:00:00Z",
"client_reference_id": "bot_8472",
"attributes": {
"gender": "female",
"age": 28,
"ethnicity": "east-asian",
"hair_color": "black",
"hair_style": "shoulder-length straight",
"eye_color": "brown",
"body_type": "athletic",
"additional_details": "small scar above right eyebrow; warm smile"
},
"error_message": null,
"aurous_version": "2026-08-26"
}
],
"has_more": true,
"next_cursor": "img_01HXMQ7Z3K8Y2VNABCDEFGHJKM"
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt"
}
}List characters
Page through your team’s characters, newest first.
curl --request GET \
--url https://api.aurous-labs.com/v1/characters \
--header 'X-Api-Key: <api-key>'import requests
url = "https://api.aurous-labs.com/v1/characters"
headers = {"X-Api-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-Api-Key': '<api-key>'}};
fetch('https://api.aurous-labs.com/v1/characters', 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.aurous-labs.com/v1/characters",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-Api-Key: <api-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"
"net/http"
"io"
)
func main() {
url := "https://api.aurous-labs.com/v1/characters"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Api-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.aurous-labs.com/v1/characters")
.header("X-Api-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.aurous-labs.com/v1/characters")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Api-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"object": "list",
"data": [
{
"id": "char_01HXMQ7Z3K8Y2NABCDEFGHJKMR",
"object": "character",
"name": "Aurora the Adventurer",
"status": "ready",
"refs": [
{
"pose": "front",
"url": "https://api.aurous-labs.com/storage/.../front.bin?token=…"
}
],
"created_at": "2026-05-08T10:00:00Z",
"updated_at": "2026-05-08T10:00:00Z",
"client_reference_id": "bot_8472",
"attributes": {
"gender": "female",
"age": 28,
"ethnicity": "east-asian",
"hair_color": "black",
"hair_style": "shoulder-length straight",
"eye_color": "brown",
"body_type": "athletic",
"additional_details": "small scar above right eyebrow; warm smile"
},
"error_message": null,
"aurous_version": "2026-08-26"
}
],
"has_more": true,
"next_cursor": "img_01HXMQ7Z3K8Y2VNABCDEFGHJKM"
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt"
}
}{
"error": {
"type": "invalid_request",
"code": "balance_too_low",
"message": "Team available balance is 1.5 credits, generation requires 2.0.",
"doc_url": "https://docs.aurous-labs.com/errors#balance_too_low",
"request_id": "req_01HXMQ7Z3K8Y2VNABCDEFGHJKM",
"param": "prompt"
}
}GET /v1/characters returns a cursor-paginated list of your team’s characters, ordered by created_at descending. Soft-deleted characters are excluded.
When to use
- Powering a “pick a character” UI in your own product.
- Auditing which characters are still in
synthesizing/reviewingand need attention. - Bulk-syncing the catalog into your local database.
Pagination
Passlimit (1–100, default 20) and starting_after (the next_cursor value from the previous response, which is the id of the last character returned). Stop when next_cursor is null.
The cursor convention is consistent across every paginated V1 endpoint — starting_after to advance, next_cursor to receive the next anchor.
Examples
# First page
curl "https://api.aurous-labs.com/v1/characters?limit=20" \
-H "X-Api-Key: $AUROUS_API_KEY"
# Subsequent pages — `starting_after` is the `id` of the last character
# returned (also surfaced as `next_cursor` on the previous response).
curl "https://api.aurous-labs.com/v1/characters?limit=20&starting_after=char_01HXMQ7Z3K8Y2VNABCDEFGHJKM" \
-H "X-Api-Key: $AUROUS_API_KEY"
async function* paginate() {
let cursor: string | null = null;
do {
const url = new URL("https://api.aurous-labs.com/v1/characters");
url.searchParams.set("limit", "20");
if (cursor) url.searchParams.set("starting_after", cursor);
const page = await fetch(url, {
headers: { "X-Api-Key": process.env.AUROUS_API_KEY! },
}).then((r) => r.json());
for (const c of page.data) yield c;
cursor = page.next_cursor;
} while (cursor);
}
for await (const c of paginate()) console.log(c.id, c.name, c.status);
import os, requests
cursor = None
while True:
params = {"limit": 20}
if cursor:
params["starting_after"] = cursor
page = requests.get(
"https://api.aurous-labs.com/v1/characters",
headers={"X-Api-Key": os.environ["AUROUS_API_KEY"]},
params=params,
).json()
for c in page["data"]:
print(c["id"], c["name"], c["status"])
cursor = page["next_cursor"]
if not cursor:
break
Limits
- Rate limit: bucket
characters_get— 120 requests/min sustained, 240 burst per team.
Common pitfalls
- The list does not include
deletedcharacters. To enumerate everything for an audit, you need to track deletions out-of-band — deletes are soft and the character stays for IDs to remain valid forever, but the list endpoint hides them. next_cursoris the last returned character’sid(the opaquechar_<ulid>). Pass it back asstarting_afteron the next request — don’t synthesize cursors yourself.- The fields returned per character are the same as
GET /v1/characters/{id}(no shrunk “summary” shape); pages are bounded bylimit, not by payload size.
Authorizations
Your team API key (starts with al_live_).
Headers
Optional API version pin (YYYY-MM-DD). Omit the header to receive the platform default, currently 2026-08-26.
^\d{4}-\d{2}-\d{2}$"2026-08-26"
Query Parameters
Items per page (1-100, default 20)
20
Cursor — opaque char_<ulid> from a prior page
"char_01HXMQ7Z3K8Y2NABCDEFGHJKMR"
Filter to a single lifecycle state. Omit to list all (non-deleted) states. An unrecognized value returns 400 invalid_request. Note: cancelled is NOT a filterable status — a cancelled character is hard-deleted and never appears in list/get; it surfaces only as the character.cancelled webhook.
synthesizing, reviewing, ready, failed, deleted Response
Cursor-paginated list of characters
Discriminator
list "list"
Array of CharacterResponse items
Show child attributes
Show child attributes
True when the next page exists
true
Pass as ?starting_after= on the next request. null when has_more is false.
"img_01HXMQ7Z3K8Y2VNABCDEFGHJKM"

