Concepts
Idempotency
An Idempotency-Key makes a POST safe to retry: if the first attempt went through, a retry with the same key returns its result instead of trading twice.
Why it matters
Networks fail at the worst moment. If POST /v1/trades times out, you can't tell whether the trade happened. Retrying without protection could buy twice; not retrying could miss the trade. With an Idempotency-Key, the retry is safe either way.
The header
| Endpoint | Idempotency-Key |
|---|---|
POST/v1/trades | Required |
POST/v1/giftcards | Required |
POST/v1/quotes | Optional |
A key is 1 to 64 characters of A-Z, a-z, 0-9, _ and -. A UUID v4 is a good choice.
How it behaves
Myntkaup keeps each key for 24 hours, per account:
- Same key, same body: the stored status and response are returned again. Nothing runs twice.
- Same key, different body:
409 idempotency_conflict. Use a new key for a new request. - Same key while the first request is still running:
409 idempotency_in_progress. Wait a moment and retry with the same key.
Using it well
- Make one key per operation, not per attempt. Every retry of that operation reuses it, with the same body.
- Store the key before you send the request, together with what you meant to do. If your program crashes and restarts, it can retry with the stored key instead of starting over.
- Sign every attempt again. Each attempt needs a new timestamp and nonce; only the
Idempotency-Keyand the body stay the same. - After a
502,504or a dropped connection, retry with the same key until you get a definite answer. A504 gateway_timeouton aPOSTmeans it may still complete.
# Signed by sign-headers.sh: see Authentication
body='{"quote_id":"qt_01JB8X2Q4M7Z3V9K5T1N6R0P2W"}'
idempotency_key=$(uuidgen) # reuse it to retry safely
curl https://public-api.myntkaup.is/v1/trades \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $idempotency_key" \
$(./sign-headers.sh POST /v1/trades "$body" | sed 's/^/-H /') \
--data "$body"import { Myntkaup } from "@myntkaup/api";
const client = new Myntkaup(); // reads the key from the environment
// Sends a random Idempotency-Key unless you pass idempotencyKey.
const trade = await client.trades.create({ quoteId: "qt_01JB8X2Q4M7Z3V9K5T1N6R0P2W" });
console.log(trade.status, trade.base_amount);from myntkaup import Myntkaup
client = Myntkaup() # reads the key from the environment
# Sends a random Idempotency-Key unless you pass idempotency_key.
trade = client.trades.create(quote_id="qt_01JB8X2Q4M7Z3V9K5T1N6R0P2W")
print(trade["status"], trade["base_amount"])In the SDKs
trades.create and giftcards.create send a random UUID v4 when you don't pass one, and their automatic retries reuse it. quotes.create sends a key only if you give one. To survive a crash of your own program, pass a key you've stored:
import { randomUUID } from "node:crypto";
const idempotencyKey = randomUUID();
await saveIntent({ quoteId: quote.id, idempotencyKey }); // your own storage
const trade = await client.trades.create({ quoteId: quote.id, idempotencyKey });import uuid
idempotency_key = str(uuid.uuid4())
save_intent(quote_id=quote["id"], idempotency_key=idempotency_key) # your own storage
trade = client.trades.create(quote_id=quote["id"], idempotency_key=idempotency_key)