Authentication
How to authenticate with the DUAL API using JWT tokens and API keys.
Authentication Methods
The DUAL API supports two authentication methods in v3.0.0+. Both are valid and can be used independently:
1. Bearer JWT Token (Recommended)
Obtain a JWT token using the OTP flow. First, request an OTP:
curl -X POST https://gateway-48587430648.europe-west6.run.app/auth/otp \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com"}'
Then authenticate with the OTP:
curl -X POST https://gateway-48587430648.europe-west6.run.app/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"otp": "123456"
}'
// Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 3600
}
Use the token in subsequent requests:
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
https://gateway-48587430648.europe-west6.run.app/wallets/me
2. API Key (Via x-api-key Header)
Create an API key via POST /api-keys and include it in the x-api-key header:
curl -X POST https://gateway-48587430648.europe-west6.run.app/api-keys \
-H "Authorization: Bearer $JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "My API Key" }'
// Response:
{
"id": "key_abc123xyz",
"key": "sk_live_1a2b3c4d5e6f7g8h",
"created_at": "2026-03-17T10:00:00Z"
}
Use the API key in subsequent requests:
curl -H "x-api-key: sk_live_1a2b3c4d5e6f7g8h" \
https://gateway-48587430648.europe-west6.run.app/wallets/me
Rate Limits
API requests are rate-limited per organization. Limits vary by operation type: 300 req/min for reads, 60 req/min for writes, and 2,000 actions/sec for Event Bus operations. See the Rate Limits page for the full breakdown.
Rate limit status is included in every response via these headers:
X-RateLimit-Limit— Maximum requests per minute for this endpoint groupX-RateLimit-Remaining— Requests remaining in current windowX-RateLimit-Reset— Unix timestamp when the window resets
When you exceed the limit, the API returns 429 Too Many Requests with a Retry-After header (in seconds):
curl https://gateway-48587430648.europe-west6.run.app/objects \
-H "x-api-key: $DUAL_API_KEY"
// Response (429):
{
"error": "rate_limit_exceeded",
"message": "Write rate limit of 60 req/min per org exceeded",
"retry_after": 30
}
// Headers:
Retry-After: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1710758430
Contact support to request higher rate limits.
Security Model
DUAL implements a 5-layer security architecture:
- Layer 1 — EIP-712 typed data signatures for all state-changing requests
- Layer 2 — Hash chain integrity for action ordering
- Layer 3 — Batch fingerprinting for on-chain anchoring
- Layer 4 — ZK proof verification for dispute resolution
- Layer 5 — Smart contract enforcement on Ethereum