v1.1.0
OAS 3.0.3
orda API
API for managing quotes, transactions and recipients in a cross-chain payment system.
Authentication
This API uses HMAC-SHA256 authentication to ensure request integrity and authenticity. All requests must include proper authentication headers.
Required Headers
Header | Description | Example |
---|---|---|
x-client-id |
Your project client ID from orda dashboard | prj_abc123... |
x-signature |
HMAC-SHA256 signature of the canonical request body | a1b2c3d4... |
x-timestamp |
Request timestamp in milliseconds (for replay protection - Optional) | 1704067200000 |
Signature Generation
The HMAC signature is generated using the following process:
1. Canonical JSON Serialization
The request body is canonicalized to ensure consistent signatures regardless of JSON key ordering:
- Object keys are sorted alphabetically
- No whitespace between elements
- Consistent string escaping
- Handles nested objects and arrays recursively
Example:
// Original JSON (key order may vary)
{"name": "John", "age": 30, "city": "New York"}
// Canonical JSON (always same output)
{"age":30,"city":"New York","name":"John"}
2. HMAC-SHA256 Calculation
signature = HMAC-SHA256(canonical_body, client_secret)
Where:
canonical_body
is the canonicalized JSON string (or empty string for no body)client_secret
is your API client secret- Output is hexadecimal string
Authentication Flow
- Canonicalize the request body JSON (if present)
- Generate HMAC-SHA256 signature using your client secret
- Add headers to your request:
x-client-id
: Your project client IDx-signature
: The generated signaturex-timestamp
: Current timestamp in milliseconds - Optional
- Send the request
Error Responses
Status Code | Error | Description |
---|---|---|
401 |
INVALID_SIGNATURE |
Signature verification failed |
401 |
MISSING_SIGNATURE |
Required x-signature header missing |
401 |
MISSING_CLIENT_ID |
Required x-client-id header missing |
401 |
TIMESTAMP_TOO_OLD |
Request timestamp is too old (replay protection) |
403 |
INVALID_CLIENT |
Client credentials are invalid |
Code Examples
JavaScript (Node.js)
const crypto = require('crypto');
function canonicalizeJSON(obj, seenObjects = new WeakSet()) {
if (obj === null) return 'null';
if (typeof obj === 'undefined') return 'undefined';
if (typeof obj === 'boolean' || typeof obj === 'number') return String(obj);
if (typeof obj === 'string') return JSON.stringify(obj);
if (obj instanceof Date) return JSON.stringify(obj.toISOString());
if (Array.isArray(obj)) {
if (seenObjects.has(obj)) return '[Circular]';
seenObjects.add(obj);
const items = obj.map(item => canonicalizeJSON(item, seenObjects));
seenObjects.delete(obj);
return `[${items.join(',')}]`;
}
if (typeof obj === 'object') {
if (seenObjects.has(obj)) return '{Circular}';
seenObjects.add(obj);
const sortedKeys = Object.keys(obj).sort();
const pairs = sortedKeys.map(key => {
const value = canonicalizeJSON(obj[key], seenObjects);
return `${JSON.stringify(key)}:${value}`;
});
seenObjects.delete(obj);
return `{${pairs.join(',')}}`;
}
return JSON.stringify(obj);
}
function generateSignature(body, clientSecret) {
const canonicalBody = body ? canonicalizeJSON(body) : '';
return crypto
.createHmac('sha256', clientSecret)
.update(canonicalBody)
.digest('hex');
}
// Add to request headers
const headers = {
'x-client-id': clientId,
'x-signature': generateSignature(requestBody, clientSecret),
'x-timestamp': Date.now().toString(),
'Content-Type': 'application/json'
};
Python
import hashlib
import hmac
import json
import time
from typing import Any, Set
def canonicalize_json(obj: Any, seen_objects: Set[int] = None) -> str:
if seen_objects is None:
seen_objects = set()
if obj is None:
return 'null'
elif isinstance(obj, bool):
return 'true' if obj else 'false'
elif isinstance(obj, (int, float)):
return str(obj)
elif isinstance(obj, str):
return json.dumps(obj)
elif isinstance(obj, list):
obj_id = id(obj)
if obj_id in seen_objects:
return '[Circular]'
seen_objects.add(obj_id)
items = [canonicalize_json(item, seen_objects) for item in obj]
seen_objects.remove(obj_id)
return f"[{','.join(items)}]"
elif isinstance(obj, dict):
obj_id = id(obj)
if obj_id in seen_objects:
return '{Circular}'
seen_objects.add(obj_id)
sorted_keys = sorted(obj.keys())
pairs = [f'"{key}":{canonicalize_json(obj[key], seen_objects)}' for key in sorted_keys]
seen_objects.remove(obj_id)
return f"{{{','.join(pairs)}}}"
else:
return json.dumps(obj)
def generate_signature(body: dict, client_secret: str) -> str:
canonical_body = canonicalize_json(body) if body else ''
signature = hmac.new(
client_secret.encode('utf-8'),
canonical_body.encode('utf-8'),
hashlib.sha256
).hexdigest()
return signature
# Add to request headers
headers = {
'x-client-id': client_id,
'x-signature': generate_signature(request_body, client_secret),
'x-timestamp': str(int(time.time() * 1000)),
'Content-Type': 'application/json'
}
cURL
# You'll need to implement canonical JSON serialization
# and HMAC generation in your preferred scripting language
SIGNATURE=$(echo -n "$CANONICAL_BODY" | openssl dgst -sha256 -hmac "$CLIENT_SECRET" -hex | cut -d' ' -f2)
TIMESTAMP=$(date +%s)000
curl -X POST "https://api.orda.network/v1/endpoint" \
-H "Content-Type: application/json" \
-H "x-client-id: $CLIENT_ID" \
-H "x-signature: $SIGNATURE" \
-H "x-timestamp: $TIMESTAMP" \
-d "$REQUEST_BODY"
Important Notes
- Empty bodies: For requests with no body, use an empty string
""
for signature generation - Key ordering: The canonical JSON ensures consistent signatures regardless of object key order
- Environment variables: When using Postman, environment variables in the format
{{variable_name}}
are automatically resolved - Replay protection: Timestamps prevent replay attacks; ensure your system clock is synchronized
- Secret security: Keep your client secret secure and never expose it in client-side code
Testing Your Implementation
To verify your HMAC implementation is working correctly:
- Test with the same JSON object but different key orders
- Ensure both generate identical signatures
- Verify empty body requests work correctly
- Test with nested objects and arrays
Client Libraries