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

# Idempotency

> Use client-generated UUIDs to make create requests safe to retry.

You generate the UUIDs for the resources you create — `orderId`, `customerId`, and `bankAccountId`. Because you supply the ID, it doubles as an **idempotency key**: the API enforces uniqueness on it, so a retried create can't silently produce a duplicate.

## How it works

When you create an order with an `orderId` you've already used, the API rejects the second request with **`409 Conflict`** rather than creating a duplicate:

```
409 Conflict
An order with this transaction ID already exists
```

This means a network blip or timeout is safe to recover from: **reuse the same `orderId`** on retry. One of two things happens —

* the original request never landed → the retry creates the order, or
* the original request *did* land → the retry returns `409`, telling you the order already exists.

Either way you end up with exactly one order.

## Recommended retry pattern

1. Generate the resource UUID **once** and persist it before the first attempt.
2. Reuse that same UUID on every retry.
3. Treat `409 Conflict` as success — the resource already exists.
4. If you need the resource's current state, `GET` it by ID.

```js theme={null}
import { randomUUID } from "node:crypto";

// Generate and persist BEFORE the first attempt, so retries reuse it.
const orderId = randomUUID();

async function createOrder() {
  const res = await fetch("https://api.sand.etherfuse.com/ramp/order", {
    method: "POST",
    headers: { Authorization: apiKey, "Content-Type": "application/json" },
    body: JSON.stringify({ orderId, quoteId, /* ... */ }),
  });

  if (res.status === 409) {
    // Already created on a previous attempt — fetch it instead.
    return fetch(`https://api.sand.etherfuse.com/ramp/order/${orderId}`, {
      headers: { Authorization: apiKey },
    }).then((r) => r.json());
  }
  if (!res.ok) throw new Error(`Create failed: ${res.status}`);
  return res.json();
}
```

## A second safety net for onramps

Beyond the per-ID check, onramps are also guarded against accidental duplicates by **amount**: only one *pending* onramp order can exist for a given `(bank account, amount)` pair. A second attempt returns:

```
409 Conflict
A pending onramp order already exists for this bank account and amount
```

If this is intentional (e.g. two genuinely separate orders of the same amount), wait for the first to move past the pending state, or vary the amount.

<Tip>
  Generate UUIDs with a standard v4 generator (`crypto.randomUUID()` in Node, `uuid` libraries elsewhere). The same pattern applies to `customerId` and `bankAccountId` during [onboarding](/guides/onboarding).
</Tip>
