> ## Documentation Index
> Fetch the complete documentation index at: https://docs.velobase.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Idempotency

> Safely retry API requests without duplicate processing.

Network issues can cause an API request to drop the response, even if Velobase successfully processed it. To prevent duplicate processing when you retry, Velobase's billing primitives require an idempotency identifier.

<Note>
  Idempotency applies to the billing primitives you call directly (deposit, freeze, consume, deduct, unfreeze) for work you price yourself. Model gateway calls (`POST /v1/chat/completions`, `POST /v1/messages`) are billed automatically per request against the end-customer wallet named in the `X-Velobase-Customer` header, so they do not take these identifier fields.
</Note>

## How it works

When Velobase receives a request, it checks if the provided identifier has already been processed for that specific customer:

1. **First request**: The operation is processed, the customer's wallet is updated, and the result is returned with `"is_idempotent_replay": false`.
2. **Duplicate request**: Velobase recognizes the identifier, skips the operation, and immediately returns the exact same result as the original request, but marked with `"is_idempotent_replay": true`.

## Identifiers by Endpoint

Velobase uses different identifier fields depending on the operation type. These fields must be passed in the JSON request body.

| Endpoint                                                                                                      | Field             | Purpose                                                                           |
| ------------------------------------------------------------------------------------------------------------- | ----------------- | --------------------------------------------------------------------------------- |
| `POST /v1/customers/deposit`                                                                                  | `idempotency_key` | A unique string (like a UUID) generated by your system for this specific deposit. |
| `POST /v1/billing/deduct`, `POST /v1/billing/freeze`, `POST /v1/billing/consume`, `POST /v1/billing/unfreeze` | `transaction_id`  | The unique ID of the task or job in your system that caused the billing event.    |

Customer deposits use `amount` as integer credits. Other billing requests may use explicit unit fields such as `amount_usd`, `amount_cents`, or `amount_credits`, where 1 USD = 100 cents = 1,000,000 credits.

## Error: Transaction Conflict

Identifiers are scoped to the customer (`customer_id`). If you attempt to reuse the exact same `transaction_id` or `idempotency_key` for a *different* customer, Velobase will reject the request with a `409 Conflict` error (`transaction_conflict`):

```json theme={null}
{
  "error": {
    "message": "transactionId already belongs to another customer",
    "type": "conflict",
    "code": "transaction_conflict"
  }
}
```

Always ensure your identifiers are globally unique across your entire system, such as using a UUIDv4 or a composite key (`user-123-task-456`).
