Skip to content

Idempotency

Mises API implements idempotency to ensure that critical operations (such as withdrawals) are not accidentally duplicated.

What is Idempotency?

Idempotency is the property that ensures an operation can be executed multiple times without changing the result beyond the first execution.

Practical example:

  • You send a withdrawal request for R$ 100.00
  • The request fails due to network timeout
  • You resend the same request with the same key
  • The API recognizes that it has already processed this operation and returns the original result
  • Result: Only 1 withdrawal is created, not 2

Idempotency-Key Header

For idempotent operations, you must include the Idempotency-Key header:

http
POST /v1/withdrawals HTTP/1.1
Host: api.misespay.com
Authorization: Bearer {token}
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

Accepted Format

  • UUID v4 (recommended): 550e8400-e29b-41d4-a716-446655440000
  • Alphanumeric with hyphens/underscores: my-unique-key-123
  • Size: 1 to 255 characters
  • Allowed characters: Letters, numbers, hyphens (-) and underscores (_)

IMPORTANT

Each unique operation attempt must have a different Idempotency-Key. Use the same key only for retry of the same operation.

Endpoints that Require Idempotency

EndpointRequires Idempotency-KeyDescription
POST /v1/withdrawals✅ Yes (required)Create withdrawal
POST /v1/sales❌ NoCreate sale
GET /v1/balance❌ NoQuery balance

How It Works

First Request (201 Created)

bash
curl -X POST https://api.misespay.com/v1/withdrawals \
  -H "Authorization: Bearer {token}" \
  -H "Idempotency-Key: abc-123-xyz" \
  -H "Content-Type: application/json" \
  -d '{"amount": 10.00, "authorize": true}'

Response:

json
{
  "success": true,
  "message": "Withdrawal requested successfully",
  "data": {
    "withdrawal_id": "881c686a-9e53-4809-a63c-c2730b924ea7",
    "amount": "R$ 10,00",
    "status": "processing"
  }
}

Duplicate Request (200 OK)

bash
# Same Idempotency-Key
curl -X POST https://api.misespay.com/v1/withdrawals \
  -H "Authorization: Bearer {token}" \
  -H "Idempotency-Key: abc-123-xyz" \
  -H "Content-Type: application/json" \
  -d '{"amount": 10.00, "authorize": true}'

Response:

json
{
  "success": true,
  "message": "Withdrawal already processed previously",
  "data": {
    "withdrawal_id": "881c686a-9e53-4809-a63c-c2730b924ea7",
    "amount": "R$ 10,00",
    "status": "processing"
  },
  "idempotent": true
}

Differences:

  • HTTP Status: 200 OK (instead of 201 Created)
  • Additional field: "idempotent": true
  • Same data from original withdrawal

Best Practices

✅ Do

  • Generate a unique key for each new operation
  • Reuse the same key only for retry of the same operation
  • Use UUID v4 to ensure global uniqueness
  • Store the key along with the request for possible retries
  • Implement automatic retry in case of timeout/network error

❌ Don't

  • Don't reuse keys between different operations
  • Don't use sequential values (1, 2, 3...)
  • Don't use timestamps as unique key
  • Don't omit the header in endpoints that require it

400 - Missing Idempotency-Key

json
{
  "success": false,
  "message": "Idempotency-Key header is required"
}

Solution: Add the Idempotency-Key header to the request.

400 - Invalid Idempotency-Key

json
{
  "success": false,
  "message": "Invalid Idempotency-Key. Use only letters, numbers, hyphens and underscores (maximum 255 characters)"
}

Solution: Use only allowed characters (a-z, A-Z, 0-9, -, _).

409 - Idempotency Conflict

If you send the same Idempotency-Key with different data, the API may return an error:

json
{
  "success": false,
  "message": "Conflict: Idempotency-Key already used with different data"
}

Solution: Generate a new Idempotency-Key for the new operation.

Use Cases

1. Network Timeout

javascript
// First attempt - timeout
try {
  await createWithdrawal(idempotencyKey, 100);
} catch (error) {
  // Retry with the SAME key
  await createWithdrawal(idempotencyKey, 100); // ✅ Safe
}

2. Server Error 500

javascript
// First attempt - error 500
const response = await createWithdrawal(idempotencyKey, 100);

if (response.status === 500) {
  // Retry with the SAME key
  await createWithdrawal(idempotencyKey, 100); // ✅ Safe
}

3. Multiple Operations

javascript
// Operation 1
const key1 = uuidv4();
await createWithdrawal(key1, 100);

// Operation 2 - NEW key
const key2 = uuidv4();
await createWithdrawal(key2, 50); // ✅ Correct

Next Steps

Mises API - Simplified PIX Payments