# Errors and retries

Use the HTTP status and stable error code to decide what to do next. Preserve the correlation ID when reporting a failed request, and keep the original idempotency key when retrying an unchanged mutation after a transient failure.

## Response envelopes

Successful authenticated v2 operations normally return a `data` envelope. Collections may also return `meta` with pagination information. Read the operation's response schema for the complete shape.

```json
{
  "error": {
    "code": "LIQUIDITY_STUDIO_PRECONDITION_REQUIRED",
    "message": "If-Match is required for this versioned resource mutation",
    "correlationId": "example-request-id",
    "retryable": false
  }
}
```

The v2 error envelope includes `code`, `message`, `correlationId`, and `retryable`. Validation failures may include `fieldErrors`, an object mapping field names to arrays of validation messages. Authentication middleware may also include `remediation`. These optional fields are not present on every failure.

Each HTTP attempt has its own correlation ID, including an idempotency replay. Use `code` for programmatic decisions; human-readable messages can change as validation becomes more specific.

The OAuth token endpoint is an exception: an invalid client returns `401` with `{"error":"invalid_client"}` and a Basic `WWW-Authenticate` challenge. The email sign-in routes and public endpoints can also use their own response shapes. Do not assume the nested v2 envelope for every endpoint on the host.

## Status and recovery

| Status | Meaning | Next action |
| --- | --- | --- |
| `400` | Malformed input, missing organization header, or invalid request fields | Correct the request using its schema and any `fieldErrors` |
| `401` | Missing, invalid, or expired authentication; sometimes recent interactive authentication is required | Inspect the code; sign in again, obtain a new access token, or rotate the affected credential as appropriate |
| `403` | Missing scope, organization membership, or workspace role | Check the organization, exact required scope, creator membership, and route permissions |
| `404` | Resource unavailable in the permitted context | Check its identifier, organization, visibility, and current availability |
| `409` | Conflict, rejected lifecycle transition, idempotency mismatch, or secret already returned | Inspect the code and refresh the relevant resource; do not blindly resubmit a new mutation |
| `412` | The resource changed since the version you reviewed | Reload the resource, review the new evidence, and submit the renewed intent with its current version |
| `422` | Domain input fails the operation's semantic checks | Correct the domain input according to the returned code and message |
| `428` | A required strong `If-Match` precondition is missing or malformed | Load the resource and send its quoted current entity tag |
| `429` | Request budget exhausted | Honor `Retry-After`; service-scope exhaustion currently returns `900` seconds |
| `500`, `503` | Internal or dependency failure | Retry only when appropriate for the operation, preserving the original mutation key and request |

Authentication failures distinguish invalid credentials from an unavailable verifier: `LIQUIDITY_STUDIO_INVALID_SERVICE_CREDENTIAL` is `401`, while `LIQUIDITY_STUDIO_SERVICE_AUTH_UNAVAILABLE` is `503`. The service scope gate returns `LIQUIDITY_STUDIO_SERVICE_SCOPE_REQUIRED` for a missing scope or route that rejects service credentials.

## Idempotency

Mutations that declare `Idempotency-Key` require a trimmed key of 8–160 characters. Generate one key for one reviewed intent, and retain it until you know the result. GET requests do not require a mutation key.

```http
POST /api/liquidity-studio/v2/proposals
Authorization: Bearer <issued service credential>
x-klineo-organization-id: <organization ID>
Idempotency-Key: proposal-report-2026-09-30-001
Content-Type: application/json
```

This illustrates headers only; the proposal body must match the API reference and the credential needs `proposals:prepare` plus a role allowed by the route.

The v2 mutation wrapper scopes the key to the organization and actor. It binds the claim to the method, path, body, actor role, and `If-Match` value. An identical completed request ordinarily replays the stored response with `Idempotency-Replayed: true`. Reusing that key with a different request returns `409`.

Handled client failures in the ordinary v2 idempotency wrapper are stored and replayed, except that its `LIQUIDITY_STUDIO_REAUTHENTICATION_REQUIRED` guard is left unrecorded. Authentication or scope rejection before entering a mutation handler also does not create a completed mutation result. For an unchanged intent rejected at those boundaries, restoring access does not require a new key.

Credential creation and rotation use a separate one-time-secret mutation handler that stores their recent-authentication `401` as a completed client failure. Reauthentication alone does not change that stored result: the original key replays the `401`. After a definitive completed failure, resolve authentication, review the intended action and current evidence, and submit a renewed intent with a new key. The same review requirement applies to corrected input or a newly reviewed resource version. See [authentication failures and stored results](/developers/idempotency/#authentication-failures-and-stored-results).

A transient server failure is not stored as a completed client-error response. Retain the original key and exact request while recovering an uncertain or transient result; a new key must not be used merely to escape an unresolved attempt.

Do not create a fresh key simply because a connection timed out: the original request may have committed. Retry the same request with its same key first, then reconcile the returned result. Particular resource services can have additional documented idempotency rules; follow the operation's contract.

## Secrets are never replayed

Developer credential issuance, credential rotation, and webhook registration use one-time secret delivery. Their durable completion stores metadata rather than the secret. An identical request after successful delivery returns:

```json
{
  "error": {
    "code": "LIQUIDITY_OPERATING_SYSTEM_SECRET_ALREADY_RETURNED",
    "message": "This credential secret was returned only in the first successful response and cannot be replayed",
    "correlationId": "example-retry-id",
    "retryable": false
  },
  "metadata": {
    "resourceType": "DEVELOPER_CREDENTIAL",
    "resourceId": "<issued credential ID>",
    "resourceVersion": "<resource version hash>",
    "issuedAt": "<issuance timestamp>"
  }
}
```

The response is `409` with `Idempotency-Replayed: true`. Metadata may be omitted when an older stored completion has no compatible metadata. If the first response was lost, refresh the resource and follow its recovery workflow. For developer credentials, rotate or revoke; the original plaintext secret cannot be recovered. See [Authentication](/developers/authentication/).

## Resource versions and strong preconditions

Versioned resources expose `resourceVersion`; supported reads also expose its quoted value in `ETag`. When an operation requires `If-Match`, submit the exact current strong entity tag:

```http
If-Match: "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
```

This is an illustrative hash. Use the value returned for the actual resource, including the double quotes. A bare hash, a weak `W/` tag, or a wildcard does not satisfy this contract. Missing or malformed tags return `428`; stale versions return `412` where the operation enforces the precondition. Some creation operations require `If-Match` only when replacing an existing generation; consult that operation's parameters.

A precondition failure is a request to review changed evidence. Fetch the latest resource, check whether the original intent still makes sense, and submit its updated version with a new key. Avoid automatically substituting the new version into an old authority-sensitive request.

## Retry policy

Use bounded retries with exponential backoff and jitter for transient transport failures and retryable server responses. Honor a supplied `Retry-After` over your usual backoff. For a mutation, keep the method, path, body, organization, version, and idempotency key unchanged during those retries.

Do not automatically retry every `401`, `403`, `409`, `412`, or `428`. Resolve the underlying credential, scope, conflict, or version problem first. A successful preparatory API response or idempotency replay establishes the API operation's result; it does not itself establish a finalized onchain transaction or execution authority.
