# Set a unique key once per new action; persist it and reuse it for every retry.
: "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
: "${REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY before running this example}"
curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/sessions' \
-H "Authorization: Bearer $REFLECTIONS_KEY" \
-H "Reflections-Version: 2026-10-15" \
-H "Idempotency-Key: $REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY" \
-H "Content-Type: application/json" \
--data-raw '{
"talent": [
"tal_9t0wxyhk5zba2q8v1m3n7p4r6s"
],
"facet": "fct_v1m3n7p4r6s9t0wxyhk5zba2q8",
"use": {
"modality": "speech",
"kind": "impersonation",
"purpose": "personal",
"commercial": false,
"channels": [
"in_app"
],
"territories": [
"US"
]
},
"inputs": [
{
"role": "system",
"text": "You are a fan voice chat. Speak as Maya Okafor in a friendly tone."
}
],
"end_user": {
"id": "usr_48213"
},
"execution": {
"provider": "example-voice-provider",
"model": "realtime-voice-2"
}
}'import { env, exit } from "node:process";
// Set a unique key once per new action; persist it and reuse it for every retry.
const apiKey = env.REFLECTIONS_KEY;
if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
const idempotencyKey = env.REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY;
if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY before running this example");
const response = await fetch("https://app.reflections.ai/v1/sessions", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Reflections-Version": "2026-10-15",
"Idempotency-Key": idempotencyKey,
"Content-Type": "application/json",
},
body: JSON.stringify({
"talent": [
"tal_9t0wxyhk5zba2q8v1m3n7p4r6s"
],
"facet": "fct_v1m3n7p4r6s9t0wxyhk5zba2q8",
"use": {
"modality": "speech",
"kind": "impersonation",
"purpose": "personal",
"commercial": false,
"channels": [
"in_app"
],
"territories": [
"US"
]
},
"inputs": [
{
"role": "system",
"text": "You are a fan voice chat. Speak as Maya Okafor in a friendly tone."
}
],
"end_user": {
"id": "usr_48213"
},
"execution": {
"provider": "example-voice-provider",
"model": "realtime-voice-2"
}
}),
signal: AbortSignal.timeout(30_000),
});
const responseBody = await response.text();
if (!response.ok) {
console.error(`HTTP ${response.status}: ${responseBody}`);
exit(1);
}
console.log(responseBody);
import json
import os
from urllib.error import HTTPError
from urllib.request import Request, urlopen
# Set a unique key once per new action; persist it and reuse it for every retry.
apiKey = os.environ["REFLECTIONS_KEY"]
if not apiKey:
raise ValueError("Set REFLECTIONS_KEY before running this example")
idempotencyKey = os.environ["REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY"]
if not idempotencyKey:
raise ValueError("Set REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY before running this example")
headers = {
"Authorization": f"Bearer {apiKey}",
"Reflections-Version": "2026-10-15",
"Idempotency-Key": idempotencyKey,
"Content-Type": "application/json",
}
data = json.dumps({
"talent": ["tal_9t0wxyhk5zba2q8v1m3n7p4r6s"],
"facet": "fct_v1m3n7p4r6s9t0wxyhk5zba2q8",
"use": {
"modality": "speech",
"kind": "impersonation",
"purpose": "personal",
"commercial": False,
"channels": ["in_app"],
"territories": ["US"],
},
"inputs": [
{
"role": "system",
"text": "You are a fan voice chat. Speak as Maya Okafor in a friendly tone.",
},
],
"end_user": {"id": "usr_48213"},
"execution": {"provider": "example-voice-provider", "model": "realtime-voice-2"},
}).encode("utf-8")
request = Request("https://app.reflections.ai/v1/sessions",
method="POST", headers=headers, data=data)
try:
with urlopen(request, timeout=30) as response:
print(response.read().decode("utf-8"))
except HTTPError as error:
error_body = error.read().decode("utf-8")
raise RuntimeError(f"HTTP {error.code}: {error_body}") from error
package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
"time"
)
func main() {
// Set a unique key once per new action; persist it and reuse it for every retry.
apiKey := os.Getenv("REFLECTIONS_KEY")
if apiKey == "" {
panic("Set REFLECTIONS_KEY before running this example")
}
idempotencyKey := os.Getenv("REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY")
if idempotencyKey == "" {
panic("Set REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY before running this example")
}
body := strings.NewReader(`{
"talent": [
"tal_9t0wxyhk5zba2q8v1m3n7p4r6s"
],
"facet": "fct_v1m3n7p4r6s9t0wxyhk5zba2q8",
"use": {
"modality": "speech",
"kind": "impersonation",
"purpose": "personal",
"commercial": false,
"channels": [
"in_app"
],
"territories": [
"US"
]
},
"inputs": [
{
"role": "system",
"text": "You are a fan voice chat. Speak as Maya Okafor in a friendly tone."
}
],
"end_user": {
"id": "usr_48213"
},
"execution": {
"provider": "example-voice-provider",
"model": "realtime-voice-2"
}
}`)
request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/sessions", body)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", "Bearer " + apiKey)
request.Header.Set("Reflections-Version", "2026-10-15")
request.Header.Set("Idempotency-Key", idempotencyKey)
request.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 30 * time.Second}
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
responseBody, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode < 200 || response.StatusCode >= 300 {
panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, responseBody))
}
fmt.Print(string(responseBody))
}
{
"id": "ses_q8v1m3n7p4r6s9t0wxyhk5zba2",
"object": "session",
"livemode": true,
"status": "active",
"check": "chk_n7p4r6s9t0wxyhk5zba2q8v1m3",
"license": "lic_ba2q8v1m3n7p4r6s9t0wxyhk5z",
"talent": [
"tal_9t0wxyhk5zba2q8v1m3n7p4r6s"
],
"token": "eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXNlc3Npb24rand0In0.eyJhdWQiOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwiZXhwIjoxNzkyMjYwMzAwLCJpYXQiOjE3OTIyNjAwMDAsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoic2VzX3E4djFtM243cDRyNnM5dDB3eHloazV6YmEyIiwic3ViIjoiYWNjdF83cDRyNnM5dDB3eHloazV6YmEycTh2MW0zbiIsInRscCI6eyJjaGVjayI6ImNoa19uN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtMyIsImV1IjoiM2Y5YzFhN2U1YjJkOGY0MDYxYzNlOWE3YjVkMmY4MDE2ZTRjOWEzYjdkMWY1ZTJjOGE2YjRkMGY5ZTNjN2ExNSIsImZhY2V0cyI6WyJmY3RfdjFtM243cDRyNnM5dDB3eHloazV6YmEycTgiXSwibGljZW5zZXMiOlt7ImxpY2Vuc2UiOiJsaWNfYmEycTh2MW0zbjdwNHI2czl0MHd4eWhrNXoiLCJyZXZpc2lvbiI6Imxydl83cDRyNnM5dDB3eHloazV6YmEycTh2MW0zbiIsInRhbGVudCI6InRhbF85dDB3eHloazV6YmEycTh2MW0zbjdwNHI2cyIsInRlcm1zX2RpZ2VzdCI6InNoYTI1Njo4ZTBhMmM0ZTZiOGQwZjJhNGM2ZThiMGQyZjRhNmM4ZTBiMmQ0ZjZhOGMwZTJiNGQ2ZjhhMGMyZTRiNmQ4ZjBhIn1dLCJzYW1wbGluZyI6eyJhdWRpb193aW5kb3dfbWF4IjoiUFQxNVMiLCJ0cmFuc2NyaXB0IjoiZXZlcnlfdHVybiJ9LCJzZXNzaW9uIjoic2VzX3E4djFtM243cDRyNnM5dDB3eHloazV6YmEyIiwidGFsZW50IjpbInRhbF85dDB3eHloazV6YmEycTh2MW0zbjdwNHI2cyJdLCJ1c2UiOnsiY2hhbm5lbHMiOlsiaW5fYXBwIl0sImNvbW1lcmNpYWwiOmZhbHNlLCJraW5kIjoiaW1wZXJzb25hdGlvbiIsIm1vZGFsaXR5Ijoic3BlZWNoIiwicHVycG9zZSI6InBlcnNvbmFsIiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fQ.RD_dRcXCqGHhYvg-PV3b1JIAoAX-WzVp02x6j-eSzmhYFxuZvniuJVrhJuHmzlFq_FYr6smqYXHQzb5p8DI0gA",
"expires_at": "2026-10-17T18:05:00Z",
"renew_every": "PT60S",
"sampling": {
"audio_window_max": "PT15S",
"transcript": "every_turn"
},
"obligations": [
{
"type": "disclosure",
"level": "licensed",
"placement": "visible",
"text": "AI voice of Maya Okafor, licensed."
},
{
"type": "generation_instructions",
"instructions": [
"Do not discuss politics or religion.",
"Do not make promises on her behalf."
],
"term": "license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never"
},
{
"type": "usage_report",
"units": "seconds",
"within": "P1D"
}
],
"reasons": [],
"stream_url": "wss://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/stream",
"termination": null,
"ended_at": null,
"metadata": {},
"created_at": "2026-10-17T18:00:00Z"
}{
"type": "https://docs.reflections.ai/errors/parameter_invalid",
"title": "A parameter is invalid",
"status": 400,
"code": "parameter_invalid",
"param": "use.territories[1]",
"detail": "\"UK\" is not an ISO 3166-1 alpha-2 code. Use \"GB\".",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "https://docs.reflections.ai/errors/invalid_api_key",
"title": "The API key is not valid",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "https://docs.reflections.ai/errors/account_not_connected",
"title": "The licensee has not connected your platform",
"status": 403,
"code": "account_not_connected",
"detail": "acct_2q8v1m3n7p4r6s9t0wxyhk5zba has no active connection with your account.",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "https://docs.reflections.ai/errors/idempotency_key_in_use",
"title": "A request with this key is still running",
"status": 409,
"code": "idempotency_key_in_use",
"detail": "Retry with the same key after a short wait.",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "https://docs.reflections.ai/errors/idempotency_key_reused",
"title": "This key was used for a different request",
"status": 422,
"code": "idempotency_key_reused",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "https://docs.reflections.ai/errors/rate_limited",
"title": "Too many requests",
"status": 429,
"code": "rate_limited",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "invalid_request",
"request_id": "<string>",
"detail": "<string>",
"param": "<string>",
"doc_url": "<string>"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "invalid_request",
"request_id": "<string>",
"detail": "<string>",
"param": "<string>",
"doc_url": "<string>"
}Create a session
Planned contract — unavailable in test and live modes. This operation is a protocol reference, not a callable endpoint. Start with the working sandbox quickstart.
Starts a live voice or video session. Reflections runs a check on the session’s inputs and,
if it allows, returns a session token that expires in 5 minutes. Renew it every
renew_every, submit samples at the sampling rate, and stay connected to stream_url to
receive session.terminated.
Sessions never escalate: anything that would escalate is deny. A license that holds every
output for release cannot start a session (session_not_permitted).
Restricted keys need sessions:write.
# Set a unique key once per new action; persist it and reuse it for every retry.
: "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
: "${REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY before running this example}"
curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/sessions' \
-H "Authorization: Bearer $REFLECTIONS_KEY" \
-H "Reflections-Version: 2026-10-15" \
-H "Idempotency-Key: $REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY" \
-H "Content-Type: application/json" \
--data-raw '{
"talent": [
"tal_9t0wxyhk5zba2q8v1m3n7p4r6s"
],
"facet": "fct_v1m3n7p4r6s9t0wxyhk5zba2q8",
"use": {
"modality": "speech",
"kind": "impersonation",
"purpose": "personal",
"commercial": false,
"channels": [
"in_app"
],
"territories": [
"US"
]
},
"inputs": [
{
"role": "system",
"text": "You are a fan voice chat. Speak as Maya Okafor in a friendly tone."
}
],
"end_user": {
"id": "usr_48213"
},
"execution": {
"provider": "example-voice-provider",
"model": "realtime-voice-2"
}
}'import { env, exit } from "node:process";
// Set a unique key once per new action; persist it and reuse it for every retry.
const apiKey = env.REFLECTIONS_KEY;
if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
const idempotencyKey = env.REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY;
if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY before running this example");
const response = await fetch("https://app.reflections.ai/v1/sessions", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Reflections-Version": "2026-10-15",
"Idempotency-Key": idempotencyKey,
"Content-Type": "application/json",
},
body: JSON.stringify({
"talent": [
"tal_9t0wxyhk5zba2q8v1m3n7p4r6s"
],
"facet": "fct_v1m3n7p4r6s9t0wxyhk5zba2q8",
"use": {
"modality": "speech",
"kind": "impersonation",
"purpose": "personal",
"commercial": false,
"channels": [
"in_app"
],
"territories": [
"US"
]
},
"inputs": [
{
"role": "system",
"text": "You are a fan voice chat. Speak as Maya Okafor in a friendly tone."
}
],
"end_user": {
"id": "usr_48213"
},
"execution": {
"provider": "example-voice-provider",
"model": "realtime-voice-2"
}
}),
signal: AbortSignal.timeout(30_000),
});
const responseBody = await response.text();
if (!response.ok) {
console.error(`HTTP ${response.status}: ${responseBody}`);
exit(1);
}
console.log(responseBody);
import json
import os
from urllib.error import HTTPError
from urllib.request import Request, urlopen
# Set a unique key once per new action; persist it and reuse it for every retry.
apiKey = os.environ["REFLECTIONS_KEY"]
if not apiKey:
raise ValueError("Set REFLECTIONS_KEY before running this example")
idempotencyKey = os.environ["REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY"]
if not idempotencyKey:
raise ValueError("Set REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY before running this example")
headers = {
"Authorization": f"Bearer {apiKey}",
"Reflections-Version": "2026-10-15",
"Idempotency-Key": idempotencyKey,
"Content-Type": "application/json",
}
data = json.dumps({
"talent": ["tal_9t0wxyhk5zba2q8v1m3n7p4r6s"],
"facet": "fct_v1m3n7p4r6s9t0wxyhk5zba2q8",
"use": {
"modality": "speech",
"kind": "impersonation",
"purpose": "personal",
"commercial": False,
"channels": ["in_app"],
"territories": ["US"],
},
"inputs": [
{
"role": "system",
"text": "You are a fan voice chat. Speak as Maya Okafor in a friendly tone.",
},
],
"end_user": {"id": "usr_48213"},
"execution": {"provider": "example-voice-provider", "model": "realtime-voice-2"},
}).encode("utf-8")
request = Request("https://app.reflections.ai/v1/sessions",
method="POST", headers=headers, data=data)
try:
with urlopen(request, timeout=30) as response:
print(response.read().decode("utf-8"))
except HTTPError as error:
error_body = error.read().decode("utf-8")
raise RuntimeError(f"HTTP {error.code}: {error_body}") from error
package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
"time"
)
func main() {
// Set a unique key once per new action; persist it and reuse it for every retry.
apiKey := os.Getenv("REFLECTIONS_KEY")
if apiKey == "" {
panic("Set REFLECTIONS_KEY before running this example")
}
idempotencyKey := os.Getenv("REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY")
if idempotencyKey == "" {
panic("Set REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY before running this example")
}
body := strings.NewReader(`{
"talent": [
"tal_9t0wxyhk5zba2q8v1m3n7p4r6s"
],
"facet": "fct_v1m3n7p4r6s9t0wxyhk5zba2q8",
"use": {
"modality": "speech",
"kind": "impersonation",
"purpose": "personal",
"commercial": false,
"channels": [
"in_app"
],
"territories": [
"US"
]
},
"inputs": [
{
"role": "system",
"text": "You are a fan voice chat. Speak as Maya Okafor in a friendly tone."
}
],
"end_user": {
"id": "usr_48213"
},
"execution": {
"provider": "example-voice-provider",
"model": "realtime-voice-2"
}
}`)
request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/sessions", body)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", "Bearer " + apiKey)
request.Header.Set("Reflections-Version", "2026-10-15")
request.Header.Set("Idempotency-Key", idempotencyKey)
request.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 30 * time.Second}
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
responseBody, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode < 200 || response.StatusCode >= 300 {
panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, responseBody))
}
fmt.Print(string(responseBody))
}
{
"id": "ses_q8v1m3n7p4r6s9t0wxyhk5zba2",
"object": "session",
"livemode": true,
"status": "active",
"check": "chk_n7p4r6s9t0wxyhk5zba2q8v1m3",
"license": "lic_ba2q8v1m3n7p4r6s9t0wxyhk5z",
"talent": [
"tal_9t0wxyhk5zba2q8v1m3n7p4r6s"
],
"token": "eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXNlc3Npb24rand0In0.eyJhdWQiOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwiZXhwIjoxNzkyMjYwMzAwLCJpYXQiOjE3OTIyNjAwMDAsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoic2VzX3E4djFtM243cDRyNnM5dDB3eHloazV6YmEyIiwic3ViIjoiYWNjdF83cDRyNnM5dDB3eHloazV6YmEycTh2MW0zbiIsInRscCI6eyJjaGVjayI6ImNoa19uN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtMyIsImV1IjoiM2Y5YzFhN2U1YjJkOGY0MDYxYzNlOWE3YjVkMmY4MDE2ZTRjOWEzYjdkMWY1ZTJjOGE2YjRkMGY5ZTNjN2ExNSIsImZhY2V0cyI6WyJmY3RfdjFtM243cDRyNnM5dDB3eHloazV6YmEycTgiXSwibGljZW5zZXMiOlt7ImxpY2Vuc2UiOiJsaWNfYmEycTh2MW0zbjdwNHI2czl0MHd4eWhrNXoiLCJyZXZpc2lvbiI6Imxydl83cDRyNnM5dDB3eHloazV6YmEycTh2MW0zbiIsInRhbGVudCI6InRhbF85dDB3eHloazV6YmEycTh2MW0zbjdwNHI2cyIsInRlcm1zX2RpZ2VzdCI6InNoYTI1Njo4ZTBhMmM0ZTZiOGQwZjJhNGM2ZThiMGQyZjRhNmM4ZTBiMmQ0ZjZhOGMwZTJiNGQ2ZjhhMGMyZTRiNmQ4ZjBhIn1dLCJzYW1wbGluZyI6eyJhdWRpb193aW5kb3dfbWF4IjoiUFQxNVMiLCJ0cmFuc2NyaXB0IjoiZXZlcnlfdHVybiJ9LCJzZXNzaW9uIjoic2VzX3E4djFtM243cDRyNnM5dDB3eHloazV6YmEyIiwidGFsZW50IjpbInRhbF85dDB3eHloazV6YmEycTh2MW0zbjdwNHI2cyJdLCJ1c2UiOnsiY2hhbm5lbHMiOlsiaW5fYXBwIl0sImNvbW1lcmNpYWwiOmZhbHNlLCJraW5kIjoiaW1wZXJzb25hdGlvbiIsIm1vZGFsaXR5Ijoic3BlZWNoIiwicHVycG9zZSI6InBlcnNvbmFsIiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fQ.RD_dRcXCqGHhYvg-PV3b1JIAoAX-WzVp02x6j-eSzmhYFxuZvniuJVrhJuHmzlFq_FYr6smqYXHQzb5p8DI0gA",
"expires_at": "2026-10-17T18:05:00Z",
"renew_every": "PT60S",
"sampling": {
"audio_window_max": "PT15S",
"transcript": "every_turn"
},
"obligations": [
{
"type": "disclosure",
"level": "licensed",
"placement": "visible",
"text": "AI voice of Maya Okafor, licensed."
},
{
"type": "generation_instructions",
"instructions": [
"Do not discuss politics or religion.",
"Do not make promises on her behalf."
],
"term": "license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never"
},
{
"type": "usage_report",
"units": "seconds",
"within": "P1D"
}
],
"reasons": [],
"stream_url": "wss://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/stream",
"termination": null,
"ended_at": null,
"metadata": {},
"created_at": "2026-10-17T18:00:00Z"
}{
"type": "https://docs.reflections.ai/errors/parameter_invalid",
"title": "A parameter is invalid",
"status": 400,
"code": "parameter_invalid",
"param": "use.territories[1]",
"detail": "\"UK\" is not an ISO 3166-1 alpha-2 code. Use \"GB\".",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "https://docs.reflections.ai/errors/invalid_api_key",
"title": "The API key is not valid",
"status": 401,
"code": "invalid_api_key",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "https://docs.reflections.ai/errors/account_not_connected",
"title": "The licensee has not connected your platform",
"status": 403,
"code": "account_not_connected",
"detail": "acct_2q8v1m3n7p4r6s9t0wxyhk5zba has no active connection with your account.",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "https://docs.reflections.ai/errors/idempotency_key_in_use",
"title": "A request with this key is still running",
"status": 409,
"code": "idempotency_key_in_use",
"detail": "Retry with the same key after a short wait.",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "https://docs.reflections.ai/errors/idempotency_key_reused",
"title": "This key was used for a different request",
"status": 422,
"code": "idempotency_key_reused",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "https://docs.reflections.ai/errors/rate_limited",
"title": "Too many requests",
"status": 429,
"code": "rate_limited",
"request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "invalid_request",
"request_id": "<string>",
"detail": "<string>",
"param": "<string>",
"doc_url": "<string>"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "invalid_request",
"request_id": "<string>",
"detail": "<string>",
"param": "<string>",
"doc_url": "<string>"
}Authorizations
Your secret key, rk_test_… or rk_live_…, sent as Authorization: Bearer <key>. Keep it
on your server. Restricted keys carry only the scopes you give them.
Headers
The dated API version. Defaults to the version your account is pinned to.
"2026-10-15"
Act for a connected licensee. The value is the licensee's account ID. Requires an active connection between that account and yours.
^acct_[0-9a-hjkmnp-tv-z]{26}$A unique key for this operation, up to 255 characters. In test mode, POST keys are scoped to your account and mode and bind the endpoint and body for 24 hours. A different endpoint or body with the same key is refused.
Initial live check and generation creation require a nonempty key. Each operation has a
separate account-scoped namespace; retain the same API key, body and idempotency key for
retries within 24 hours of creation. A pending check returns 202 with status: "checking".
Completed checks replay their sealed response; successful generation POSTs replay the
original accepted 202, so use GET for current state. Live verification is a read-only
query that returns a fresh verification ID on each call, without exact response caching.
The broader delegated-account contract also scopes keys to Reflections-Account;
delegated requests and the other planned live POST operations remain unsupported.
255Body
What the model receives when the session starts, such as your system text, in order.
1Show child attributes
Show child attributes
How the session's output will be used.
Show child attributes
Show child attributes
Talent your user picked, up to 4. The inputs are still resolved for anyone else.
4^tal_[0-9a-hjkmnp-tv-z]{26}$A specific facet, such as one of several voices.
^fct_[0-9a-hjkmnp-tv-z]{26}$Use this license. By default the narrowest license that allows the use is chosen.
^lic_[0-9a-hjkmnp-tv-z]{26}$The person the session is for.
Show child attributes
Show child attributes
The model that runs the session.
Show child attributes
Show child attributes
The longest the session may run, such as PT30M. The stream sends a max_duration
warning before it is reached.
"P30D"
Your own keys, returned on the session.
Show child attributes
Show child attributes
Response
The session. If status is denied, the check's reasons explain why and no token is issued.
The session's ID, ses_ followed by 26 characters.
^ses_[0-9a-hjkmnp-tv-z]{26}$Always session.
"session"true in live mode, false in test mode.
active: renew and submit samples. denied: the check did not allow it; reasons say
why. ended: you ended it. terminated: Reflections ended it; termination says why.
active, denied, ended, terminated The check Reflections ran on the session's inputs when it started.
^chk_[0-9a-hjkmnp-tv-z]{26}$When the session started.
The license the session runs under. Null when none applies.
^lic_[0-9a-hjkmnp-tv-z]{26}$The talent the session covers.
^tal_[0-9a-hjkmnp-tv-z]{26}$A JWS with typ tlp-session+jwt. Null when the session is not active.
When the current token expires, 5 minutes after it was issued. Null when the session is not active.
How often to renew the token: PT60S.
"P30D"
Which samples to submit, and how often.
Show child attributes
Show child attributes
What you must do for the whole session, such as show the disclosure.
Show child attributes
Show child attributes
Why the session was denied. Empty otherwise.
Show child attributes
Show child attributes
The session stream's WebSocket URL. Stay connected to receive session.terminated. Null
when the session is denied.
Why and when Reflections ended the session. Null unless status is terminated. The
session stream's session.terminated message carries the same fields.
Show child attributes
Show child attributes
When you ended the session with POST /v1/sessions/{session_id}/end. Null until then.
Your metadata from the request.
Show child attributes
Show child attributes