: "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2' \
-H "Authorization: Bearer $REFLECTIONS_KEY" \
-H "Reflections-Version: 2026-10-15"import { env, exit } from "node:process";
const apiKey = env.REFLECTIONS_KEY;
if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
const response = await fetch("https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2", {
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`,
"Reflections-Version": "2026-10-15",
},
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 os
from urllib.error import HTTPError
from urllib.request import Request, urlopen
apiKey = os.environ["REFLECTIONS_KEY"]
if not apiKey:
raise ValueError("Set REFLECTIONS_KEY before running this example")
headers = {
"Authorization": f"Bearer {apiKey}",
"Reflections-Version": "2026-10-15",
}
request = Request("https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2",
method="GET", headers=headers)
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"
"time"
)
func main() {
apiKey := os.Getenv("REFLECTIONS_KEY")
if apiKey == "" {
panic("Set REFLECTIONS_KEY before running this example")
}
request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2", nil)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", "Bearer " + apiKey)
request.Header.Set("Reflections-Version", "2026-10-15")
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"
}Retrieve 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.
Returns a session. If the session stream drops, read the session before you reconnect: a
termination you missed shows as status: terminated with termination.
Restricted keys need sessions:write.
: "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2' \
-H "Authorization: Bearer $REFLECTIONS_KEY" \
-H "Reflections-Version: 2026-10-15"import { env, exit } from "node:process";
const apiKey = env.REFLECTIONS_KEY;
if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
const response = await fetch("https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2", {
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`,
"Reflections-Version": "2026-10-15",
},
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 os
from urllib.error import HTTPError
from urllib.request import Request, urlopen
apiKey = os.environ["REFLECTIONS_KEY"]
if not apiKey:
raise ValueError("Set REFLECTIONS_KEY before running this example")
headers = {
"Authorization": f"Bearer {apiKey}",
"Reflections-Version": "2026-10-15",
}
request = Request("https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2",
method="GET", headers=headers)
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"
"time"
)
func main() {
apiKey := os.Getenv("REFLECTIONS_KEY")
if apiKey == "" {
panic("Set REFLECTIONS_KEY before running this example")
}
request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2", nil)
if err != nil {
panic(err)
}
request.Header.Set("Authorization", "Bearer " + apiKey)
request.Header.Set("Reflections-Version", "2026-10-15")
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"
}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}$Path Parameters
The session's ID.
^ses_[0-9a-hjkmnp-tv-z]{26}$Response
The session.
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