API Reference
Base URL: https://api.whiterabbit.app
API version: v1
All endpoints in this reference require only an API key — no JWT or user session. Use these from your backend, scripts, or any HTTP client.
Authentication
Every request requires three headers: the API key, a fresh timestamp, and an Ed25519 request signature.
| Header | Value | Description |
|---|---|---|
X-Api-Key | ws_... | Your Workspace API key |
X-Sdk-Timestamp | Unix epoch (seconds) | Must be within 30 seconds of server time |
X-Sdk-Signature | Base64 Ed25519 signature | Covers method, path, timestamp, and body |
Get your API key and API secret from the White Rabbit Dashboard under Settings → API Keys. Both are shown once at key creation time.
The caller-sdk handles signing automatically — you only need the API key. Manual signing is only required for raw HTTP clients.
Request signing
The signature is computed over a pipe-delimited message:
MESSAGE = METHOD + "|" + PATH + "|" + TIMESTAMP + "|" + JSON.stringify(body)
Then signed with your API secret (Ed25519 private key, shown once at key creation) and base64-encoded.
Node.js example
import { createPrivateKey, sign } from 'crypto';
import { readFileSync } from 'fs';
// Load your API secret (Ed25519 private key, DER format, base64-encoded — shown once at key creation)
const secretDer = Buffer.from(process.env.WR_API_SECRET!, 'base64');
const signingKey = createPrivateKey({ key: secretDer, format: 'der', type: 'pkcs8' });
function signRequest(
method: string,
path: string,
body: object = {},
): { timestamp: number; signature: string } {
const timestamp = Math.floor(Date.now() / 1000);
const message = [method.toUpperCase(), path, timestamp, JSON.stringify(body)]
.filter(Boolean)
.join('|');
const sig = sign(null, Buffer.from(message, 'utf-8'), signingKey);
return { timestamp, signature: sig.toString('base64') };
}
// Usage
const { timestamp, signature } = signRequest('POST', '/v1/sdk/components', body);
fetch('https://api.whiterabbit.app/v1/sdk/components', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': process.env.WR_API_KEY!,
'X-Sdk-Timestamp': String(timestamp),
'X-Sdk-Signature': signature,
},
body: JSON.stringify(body),
});
Python example
import base64, json, os, time
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
# Load API secret (Ed25519 private key, DER format, base64-encoded)
der_bytes = base64.b64decode(os.environ["WR_API_SECRET"])
signing_key = Ed25519PrivateKey.from_private_bytes(der_bytes[-32:]) # last 32 bytes = seed
def sign_request(method: str, path: str, body: dict = {}) -> dict:
timestamp = int(time.time())
message = "|".join([method.upper(), path, str(timestamp), json.dumps(body, separators=(',', ':'))])
sig = signing_key.sign(message.encode("utf-8"))
return {"timestamp": timestamp, "signature": base64.b64encode(sig).decode()}
{ timestamp, signature } = sign_request("POST", "/v1/sdk/components", body)
The server rejects requests where X-Sdk-Timestamp is more than 30 seconds in the past or set in the future. Sync your system clock with NTP.
Quick links
Error responses
All errors follow:
{
"message": "Human-readable description",
"statusCode": 400,
"error": "Bad Request"
}
| Status | Meaning |
|---|---|
400 | Validation error |
401 | Missing or invalid API key |
402 | Insufficient credits |
403 | Missing permission |
404 | Resource not found |
429 | Rate limit exceeded — check Retry-After header |
502 | Upstream service unavailable |