: "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba' \
-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/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba", {
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/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba",
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/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba", 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": "gen_2q8v1m3n7p4r6s9t0wxyhk5zba",
"object": "generation",
"livemode": true,
"check": "chk_m3n7p4r6s9t0wxyhk5zba2q8v1",
"session": null,
"candidate_index": 0,
"status": "allowed",
"decision": "allow",
"artifact": {
"file": "file_8q0r2s4t6v8w0x2y4z6a8b0c2d",
"sha256": "3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d",
"media_type": "audio/wav",
"duration_ms": 3400
},
"execution": {
"provider": "example-voice-provider",
"model": "tts-2",
"job_id": "job_90417"
},
"findings": [
{
"term": "license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.requiredAttributes",
"attribute": "identity.samePerson",
"result": "preserved"
},
{
"term": "license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never",
"rule": "Do not discuss politics or religion.",
"result": "preserved"
}
],
"unchecked_terms": [],
"reasons": [],
"obligations": [
{
"type": "disclosure",
"level": "licensed",
"placement": "metadata",
"text": "AI voice of Maya Okafor, licensed."
},
{
"type": "c2pa_manifest"
},
{
"type": "usage_report",
"units": "seconds",
"within": "P1D"
}
],
"escalation": null,
"assurance": "observed",
"receipt": "rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy",
"c2pa": {
"label": "ai.reflections.license",
"data": {
"receipt": "eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXJlY2VpcHQrand0In0.eyJpYXQiOjE3OTIyNjAzNjMsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoicmNwdF9oazV6YmEycTh2MW0zbjdwNHI2czl0MHd4eSIsInN1YiI6Imdlbl8ycTh2MW0zbjdwNHI2czl0MHd4eWhrNXpiYSIsInRscCI6eyJhcnRpZmFjdF9zaGEyNTYiOiIzYjVkN2Y5YTFjM2U1YjdkOWYxYTNjNWU3YjlkMWYzYTVjN2U5YjFkM2Y1YTdjOWUxYjNkNWY3YTljMWUzYjVkIiwiYXNzdXJhbmNlIjoib2JzZXJ2ZWQiLCJkZWNpc2lvbiI6ImFsbG93Iiwia2luZCI6ImdlbmVyYXRpb24iLCJsaWNlbnNlZSI6ImFjY3RfN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtM24iLCJsaWNlbnNlcyI6W3sibGljZW5zZSI6ImxpY19iYTJxOHYxbTNuN3A0cjZzOXQwd3h5aGs1eiIsInJldmlzaW9uIjoibHJ2XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwidGFsZW50IjoidGFsXzl0MHd4eWhrNXpiYTJxOHYxbTNuN3A0cjZzIiwidGVybXNfZGlnZXN0Ijoic2hhMjU2OjhlMGEyYzRlNmI4ZDBmMmE0YzZlOGIwZDJmNGE2YzhlMGIyZDRmNmE4YzBlMmI0ZDZmOGEwYzJlNGI2ZDhmMGEifV0sIm9ibGlnYXRpb25zIjpbeyJsZXZlbCI6ImxpY2Vuc2VkIiwicGxhY2VtZW50IjoibWV0YWRhdGEiLCJ0ZXh0IjoiQUkgdm9pY2Ugb2YgTWF5YSBPa2Fmb3IsIGxpY2Vuc2VkLiIsInR5cGUiOiJkaXNjbG9zdXJlIn0seyJ0eXBlIjoiYzJwYV9tYW5pZmVzdCJ9LHsidHlwZSI6InVzYWdlX3JlcG9ydCIsInVuaXRzIjoic2Vjb25kcyIsIndpdGhpbiI6IlAxRCJ9XSwicGxhdGZvcm0iOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwicmVxdWVzdF9kaWdlc3QiOiJzaGEyNTY6ZDRmNmI4YTBjMmU0ZDZmOGIwYTJjNGU2ZDhmMGIyYTRjNmU4ZDBmMmI0YTZjOGUwZDJmNGI2YThjMGUyZDRmNiIsInRhbGVudCI6WyJ0YWxfOXQwd3h5aGs1emJhMnE4djFtM243cDRyNnMiXSwidXNlIjp7ImNoYW5uZWxzIjpbImF1ZGlvIiwid2ViIl0sImNvbW1lcmNpYWwiOnRydWUsImtpbmQiOiJpbXBlcnNvbmF0aW9uIiwibW9kYWxpdHkiOiJzcGVlY2giLCJwdXJwb3NlIjoiYnJhbmRlZF9jb250ZW50IiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fQ.K7AXwiCTQv-GS_xfIdystUTVdNl6u7p0FQ9XSkoh5amUnEehLLLpriZk7OA38gBo5UZHItmJm0rHf_8Eebj2rg",
"verify_url": "https://app.reflections.ai/r/rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy"
}
},
"watermark": null,
"metadata": {},
"created_at": "2026-10-17T18:06:02Z",
"decided_at": "2026-10-17T18:06:03Z"
}{
"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/resource_not_found",
"title": "No such object",
"status": 404,
"code": "resource_not_found",
"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>"
}Retrieve a generation
Test mode available. Live mode available when configured. Source support does not
establish production activation. The initial live implementation returns the caller’s
generation as checking, held, released, denied or expired. Only the talent’s
committed release permits decision: "allow". Poll this operation for current state;
replaying the POST returns its original accepted 202 response.
Private details remain available while pending and for 24 hours after their terminal
retention boundary, then return 404. Signed receipts have a separate seven-year lifetime.
Returns a generation. Read it for the decision on an output that is checking or held, or
to read its c2pa assertion again.
Restricted keys need generations:write or generations:read.
: "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba' \
-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/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba", {
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/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba",
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/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba", 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": "gen_2q8v1m3n7p4r6s9t0wxyhk5zba",
"object": "generation",
"livemode": true,
"check": "chk_m3n7p4r6s9t0wxyhk5zba2q8v1",
"session": null,
"candidate_index": 0,
"status": "allowed",
"decision": "allow",
"artifact": {
"file": "file_8q0r2s4t6v8w0x2y4z6a8b0c2d",
"sha256": "3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d",
"media_type": "audio/wav",
"duration_ms": 3400
},
"execution": {
"provider": "example-voice-provider",
"model": "tts-2",
"job_id": "job_90417"
},
"findings": [
{
"term": "license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.requiredAttributes",
"attribute": "identity.samePerson",
"result": "preserved"
},
{
"term": "license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never",
"rule": "Do not discuss politics or religion.",
"result": "preserved"
}
],
"unchecked_terms": [],
"reasons": [],
"obligations": [
{
"type": "disclosure",
"level": "licensed",
"placement": "metadata",
"text": "AI voice of Maya Okafor, licensed."
},
{
"type": "c2pa_manifest"
},
{
"type": "usage_report",
"units": "seconds",
"within": "P1D"
}
],
"escalation": null,
"assurance": "observed",
"receipt": "rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy",
"c2pa": {
"label": "ai.reflections.license",
"data": {
"receipt": "eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXJlY2VpcHQrand0In0.eyJpYXQiOjE3OTIyNjAzNjMsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoicmNwdF9oazV6YmEycTh2MW0zbjdwNHI2czl0MHd4eSIsInN1YiI6Imdlbl8ycTh2MW0zbjdwNHI2czl0MHd4eWhrNXpiYSIsInRscCI6eyJhcnRpZmFjdF9zaGEyNTYiOiIzYjVkN2Y5YTFjM2U1YjdkOWYxYTNjNWU3YjlkMWYzYTVjN2U5YjFkM2Y1YTdjOWUxYjNkNWY3YTljMWUzYjVkIiwiYXNzdXJhbmNlIjoib2JzZXJ2ZWQiLCJkZWNpc2lvbiI6ImFsbG93Iiwia2luZCI6ImdlbmVyYXRpb24iLCJsaWNlbnNlZSI6ImFjY3RfN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtM24iLCJsaWNlbnNlcyI6W3sibGljZW5zZSI6ImxpY19iYTJxOHYxbTNuN3A0cjZzOXQwd3h5aGs1eiIsInJldmlzaW9uIjoibHJ2XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwidGFsZW50IjoidGFsXzl0MHd4eWhrNXpiYTJxOHYxbTNuN3A0cjZzIiwidGVybXNfZGlnZXN0Ijoic2hhMjU2OjhlMGEyYzRlNmI4ZDBmMmE0YzZlOGIwZDJmNGE2YzhlMGIyZDRmNmE4YzBlMmI0ZDZmOGEwYzJlNGI2ZDhmMGEifV0sIm9ibGlnYXRpb25zIjpbeyJsZXZlbCI6ImxpY2Vuc2VkIiwicGxhY2VtZW50IjoibWV0YWRhdGEiLCJ0ZXh0IjoiQUkgdm9pY2Ugb2YgTWF5YSBPa2Fmb3IsIGxpY2Vuc2VkLiIsInR5cGUiOiJkaXNjbG9zdXJlIn0seyJ0eXBlIjoiYzJwYV9tYW5pZmVzdCJ9LHsidHlwZSI6InVzYWdlX3JlcG9ydCIsInVuaXRzIjoic2Vjb25kcyIsIndpdGhpbiI6IlAxRCJ9XSwicGxhdGZvcm0iOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwicmVxdWVzdF9kaWdlc3QiOiJzaGEyNTY6ZDRmNmI4YTBjMmU0ZDZmOGIwYTJjNGU2ZDhmMGIyYTRjNmU4ZDBmMmI0YTZjOGUwZDJmNGI2YThjMGUyZDRmNiIsInRhbGVudCI6WyJ0YWxfOXQwd3h5aGs1emJhMnE4djFtM243cDRyNnMiXSwidXNlIjp7ImNoYW5uZWxzIjpbImF1ZGlvIiwid2ViIl0sImNvbW1lcmNpYWwiOnRydWUsImtpbmQiOiJpbXBlcnNvbmF0aW9uIiwibW9kYWxpdHkiOiJzcGVlY2giLCJwdXJwb3NlIjoiYnJhbmRlZF9jb250ZW50IiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fQ.K7AXwiCTQv-GS_xfIdystUTVdNl6u7p0FQ9XSkoh5amUnEehLLLpriZk7OA38gBo5UZHItmJm0rHf_8Eebj2rg",
"verify_url": "https://app.reflections.ai/r/rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy"
}
},
"watermark": null,
"metadata": {},
"created_at": "2026-10-17T18:06:02Z",
"decided_at": "2026-10-17T18:06:03Z"
}{
"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/resource_not_found",
"title": "No such object",
"status": 404,
"code": "resource_not_found",
"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}$Path Parameters
The generation's ID.
^gen_[0-9a-hjkmnp-tv-z]{26}$Response
The generation.
The generation's ID, gen_ followed by 26 characters.
^gen_[0-9a-hjkmnp-tv-z]{26}$Always generation.
"generation"true in live mode, false in test mode.
Where the output is. Deliver only on allowed or released.
checking, allowed, denied, held, released, expired, withdrawn observed: Reflections checked these bytes. attested: Reflections recorded what you stated without checking it.
observed, attested When the output was submitted.
The check the output was made under. Null for an output made in a session.
^chk_[0-9a-hjkmnp-tv-z]{26}$The session the output was made in. Null for an output made under a check.
^ses_[0-9a-hjkmnp-tv-z]{26}$Which of the check's candidates this is, from 0. Null under reuse and for an output
made in a session.
allow, deny, or escalate while a reviewer must release the output. Null while
status is checking.
allow, deny, escalate The output that was checked.
Show child attributes
Show child attributes
The run that made the output, as you stated it.
Show child attributes
Show child attributes
Each rule checked on the bytes, with its result.
Show child attributes
Show child attributes
Addresses of rules the talent wrote that could not be checked on these bytes. They do not withhold the output.
Where a reason or finding rests, written as an address: license:<id>/terms.<key> for a
term, talent:<id> for a talent's standing boundary.
Why the output was denied or expired. Empty otherwise.
Show child attributes
Show child attributes
What you must do with this output, such as embed c2pa and show the disclosure, or keep
it private while held.
Show child attributes
Show child attributes
The release review, when a person must release the output. Null otherwise.
Show child attributes
Show child attributes
The receipt that records the decision. Null while the output is checking or held,
and after a withdrawal from review.
^rcpt_[0-9a-hjkmnp-tv-z]{26}$The assertion to embed in the output's C2PA manifest before you deliver it. Null unless
decision is allow.
Show child attributes
Show child attributes
The watermark you registered on the generation. Null if none.
Show child attributes
Show child attributes
Your metadata from the request.
Show child attributes
Show child attributes
When the output was allowed, released, denied or expired. Null otherwise.