Valqio Docs
Guides

Errors and retries

Handle denies, timeouts, retries, and partial failures without double-counting usage.

Retry behavior should protect one product attempt, not create a new one.

Use stable keys

Every billable attempt needs a stable idempotency key.

const requestId = "req_123"
const idempotencyKey = `generate-report:${requestId}`

Reuse that key when the same request is retried. Create a new key only when the customer starts a new product attempt.

What to retry

SituationApp behavior
Network timeout before response.Retry with the same idempotency key.
RATE_LIMITED response.Back off and retry only if the product experience allows waiting.
HARD_CAP or INSUFFICIENT_CREDITS.Do not retry automatically; show an upgrade, top-up, or usage-limit message.
METER_NOT_FOUND or INVALID_REQUEST.Treat as integration configuration work, not a customer retry.
Reservation commit fails after work succeeds.Retry commit with the same commit key.
Worker fails after reserve.Release with the same release key.

Minimal handler

const decision = await runtime.enforce({
  requestId,
  meterKey: "generation-runs",
  quantity: 1,
  subject: { type: "customer", key: "workspace_acme" },
  idempotencyKey,
})

if (!decision.allowed) {
  return {
    status: decision.reasonCode === "RATE_LIMITED" ? 429 : 402,
    body: {
      reasonCode: decision.reasonCode,
      retriable: decision.retriable,
      requestId,
    },
  }
}

Use Console evidence to debug unexpected denies. Search by request ID, subject, meter, reason code, or idempotency key.

On this page