Skip to main content
Protocol reference. Reuse and idempotency can be tested against fictional fixtures. The name index, revocation feed, license events and production availability targets below are not implemented by the current sandbox. Start with the runnable quickstart and sandbox support matrix.
This page covers what you may cache, how to retry, and what to do when a call fails. Two rules decide everything on it: only an allow lets you generate a named talent, and nothing you cache outlives a revocation.

What you may cache

Platforms that cache any decision read the revocation feed at least every 60 seconds, in addition to webhooks. A suspension is not a revocation and is not in the feed: there is no revocation object and nothing to acknowledge. When you receive license.suspended, drop every cached decision under that license. Until license.resumed, checks deny with license_suspended, open sessions end, and renewals fail with 409 session_not_active. Held outputs stay held, and outputs already released are unaffected.

Reuse windows

Some products make many generations for one user in a few minutes: a text-to-speech app reading lines, an image tool producing variations. Ask for a reuse window so one decision covers them:
The window covers later generations of the same use, for the same talent, model and end_user, until authorization.expires_at or until authorization.generations_used reaches max_generations. Every output in the window is still submitted as a generation, where its words or pixels are checked against the license. A new user, a new use or a new model needs a new check.

Never turn a non-allow into an allow

Caching goes wrong when something that is not an allow is treated as one.
  • An error, a timeout or a 503 is not a decision. Generate nothing for a named talent.
  • A cached deny stays a deny for that request. When it ages out of your cache, check again; do not assume the answer changed.
  • escalate is not an allow. Wait for check.resolved.
  • A resolution with status: none, or no local match in the name index, is not permission. Only a check resolves indirect references, such as “the runner from Ridgeline’s spring campaign”.
  • An allow covers its own request. A cached authorization never covers a different prompt, reference, model or use, unless it carries a reuse window for that use.

Retry safely

Every POST takes an Idempotency-Key, kept for 24 hours. Generate one key per logical request, store it with the request, and reuse it on every retry.
A deny or escalate is a 200 with a decision, not an error. Never retry a decision to get a different one.

When Reflections is unavailable

Named talent: fail closed. If a check cannot complete for a request that names a talent in talent, matches the name index, or carries a reference or voice sample, do not generate. The one exception is an authorization you already hold: while it has not expired and has generations left, you may use it for the request it covers. Tell your user the request cannot run right now; do not fall back to generating without a decision. Requests that name and match no one: you may proceed. A request that names no talent, matches no entry in your current name index, and carries no reference or voice sample may be generated and delivered while the check cannot complete. Nothing is sent later. With no index, or one past its expires_at, every request fails closed. Live sessions may continue until the current session token expires, at most 5 minutes, never past it. See Real-time sessions. Revocations wait for you. When calls succeed again, read the feed from your stored cursor, and any license.suspended events you missed with GET /v1/events, before you serve any cached decision. The acknowledgement deadlines do not move: acknowledge every action but withdraw_outputs by acknowledge_by, and withdraw_outputs by post_revocation.withdraw_by. The proposed production availability target for checks is 99.95% per month. It is not a confirmed service commitment or a measured sandbox result. Current status and incidents are on status.reflections.ai.

When evaluation is unavailable

Sometimes Reflections is up but cannot finish evaluating a rule. The check then returns escalate with escalation.reason: "evaluation_unavailable", or deny with review_required if you sent on_escalate: "deny". At the generation, a rule the talent wrote that could not be read is recorded in unchecked_terms and the output is delivered; a protected attribute that could not be read denies the output. In test mode, rfl_test_unavailable in a check’s text forces the evaluation_unavailable path.

Failure modes

Fail-closed and fail-open rules in one place.

Idempotency

Keys, replay, and the three outcomes.

Rate limits

Limits, headers and raising them.

Handle revocations

The feed that invalidates your caches.