Skip to content
Docs navigation: Decision model / Idempotency

Idempotency

RightNow AIDecision modelIdempotency Updated

On this page

Use an Idempotency-Key to replay the same decision while its stored answer is available.

decide.ts
import { SystemZeroClient } from '@rightnowai/system-zero';

const client = new SystemZeroClient({
  apiKey: process.env.SYSTEM_ZERO_API_KEY,
  baseURL: "https://api.rightnowai.co/v1",
});
const reply = await client.decide({
  "model": "rightnow-decision",
  "state": "The blender I ordered arrived with a cracked jar.",
  "questions": {
    "damaged": {
      "type": "boolean",
      "instructions": "Did the item arrive damaged?"
    }
  }
});
console.log(JSON.stringify(reply, null, 2));
const models = await client.models.list();
console.log(models);

// Set SYSTEM_ZERO_API_KEY to your API key before running this example.
// Run this example on your server.
// SDK defaults: The default is 5 retries, also the maximum, with 150 seconds
// per attempt and a 60-second total retry budget. A single wait longer than 60
// seconds raises the last error.
// Use Retry-After-Ms, or Retry-After when milliseconds are absent. The wait is
// never shorter than a random backoff floor: a random fraction of 0.5 seconds
// doubled for each attempt, capped at 8 seconds.

Keep the key and body

Generate a fresh key for a new decision. Keep that key and the same JSON body for retries, using the same workspace and API key.

The API compares the canonical JSON body with the method and route. Changing the body while keeping the key returns 400 idempotency_key_reuse.

A request policy is part of that comparison, so a changed policy under the same key returns the same refusal.

The header is optional. Without it, repeating a call cannot retrieve an answer lost in transit.

Read a replay

Successful keys have a 24-hour answer window and retain an identity tombstone without request or answer content for 30 days after that window; after answer expiry, the same body returns 409 idempotency_replay_unavailable and a changed body returns 400 idempotency_key_reuse.

The same key and body can return the completed answer with X-RightNow-Idempotent-Replay: true. The replay has a new request trace and current rate-limit headers.

Replay availability is not guaranteed. If the settled answer cannot be read, the response uses X-RightNow-Idempotent-Replay: unavailable and 409 idempotency_replay_unavailable.

If a stored answer cannot be read temporarily, the same key and body may replay it after the store recovers and before the answer expires or is evicted. Recovery is not guaranteed. This refusal has error.retryable: false; stop automatic retries. A new key starts new work and may produce a different answer.

Handle a replay refusal

CodeWhat to do
idempotency_conflictThe same work is still running. Wait for Retry-After, then retry with the same Idempotency-Key and body.
idempotency_key_reuseUse the original body with this Idempotency-Key, or a new key for changed work.
idempotency_replay_unavailableInspect error.details.original_status. A new key starts new work rather than recovering the old answer.
invalid_idempotency_keyCorrect the blank or malformed key.
idempotency_unavailableWait for Retry-After, then retry with the same Idempotency-Key.
same request
Text
Illustration of a keyed retry.

Changed parameters fail; running work waits. Stored replies replay; missing replies stop automatic retries.

Use error.retryable and x-should-retry to decide whether to retry. Follow the wait in the response; see Errors.