Skip to main content

Idempotency

All blockchain write operations accept an idempotency_key parameter to prevent duplicate submissions (e.g., double-minting on network retries). This is critical for financial operations where a retry could produce unintended results.

How It Works

  1. Include an idempotency_key (any unique string, max 255 characters) in your request body
  2. If the same key is sent again within the retention window, the API returns the original result without re-executing
  3. Keys are scoped per tenant — different tenants can use the same key independently
POST /v1/tokens/tok_abc/mint
{ "to": "0x...", "amount": "1000", "idempotency_key": "mint-user42-2024-03-06" }
→ 201 Created: { "id": "tx_abc123", "status": "pending" }

POST /v1/tokens/tok_abc/mint (same key)
{ "to": "0x...", "amount": "1000", "idempotency_key": "mint-user42-2024-03-06" }
→ 200 OK: { "id": "tx_abc123", "status": "pending" } ← same tx returned

Key Retention

Idempotency keys are retained for 24 hours from the first request. After this window, the same key can be reused for a new operation.

AspectDetail
Retention window24 hours
ScopePer tenant
Max length255 characters
StorageRedis (fast lookups)

Which Endpoints Require It

EndpointRequired?
POST /v1/tokens/:id/mintYes
POST /v1/tokens/:id/transferYes
POST /v1/tokens/:id/burnYes
POST /v1/tokens/:id/approveYes
POST /v1/batchYes
POST /v1/vestingOptional
POST /v1/vaults/:id/depositOptional
POST /v1/tokens (deploy)Optional

SDK Example

// The SDK can auto-generate idempotency keys
const tx = await urblock.tokens.mint("tok_abc123", {
to: "0x1234567890abcdef1234567890abcdef12345678",
amount: "1000000000000000000",
idempotency_key: "mint-user42-2024-03-06",
});

// Retry with the same key — safe, returns original tx
const retry = await urblock.tokens.mint("tok_abc123", {
to: "0x1234567890abcdef1234567890abcdef12345678",
amount: "1000000000000000000",
idempotency_key: "mint-user42-2024-03-06",
});

console.log(tx.id === retry.id); // true — no duplicate mint

curl Example

curl -X POST https://api.urblock.io/v1/tokens/tok_abc123/mint \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"to": "0x1234567890abcdef1234567890abcdef12345678",
"amount": "1000000000000000000",
"idempotency_key": "mint-user42-2024-03-06"
}'

Error Response

If you send the same key with different parameters, the API returns 409 Conflict:

{
"error": {
"type": "invalid_request_error",
"code": "idempotency_key_reuse",
"message": "Idempotency key already used with different parameters.",
"status": 409
}
}

Best Practices

PracticeExample
Use deterministic keys{action}-{userId}-{timestamp}
Include operation contextmint-user42-2024-03-06-reward
Use UUIDs for one-off ops550e8400-e29b-41d4-a716-446655440000
Never reuse keys for different opsEach operation gets a unique key
Retry safelySame key + same params = safe retry

Key Generation Patterns

// Pattern 1: Action + entity + date
const key = `mint-${userId}-${new Date().toISOString().slice(0, 10)}`;

// Pattern 2: Action + unique reference
const key = `transfer-invoice-${invoiceId}`;

// Pattern 3: UUID for one-off operations
const key = crypto.randomUUID();

How It's Implemented

Under the hood, Urblock stores idempotency keys in Redis with a 24-hour TTL:

1. Request arrives with idempotency_key
2. Check Redis: key exists?
→ Yes: compare params hash
→ Same: return stored response (200 OK)
→ Different: return 409 Conflict
→ No: proceed with operation, store result in Redis
3. Return response

Next Steps