Skip to main content

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.

HeaderValueDescription
X-Api-Keyws_...Your Workspace API key
X-Sdk-TimestampUnix epoch (seconds)Must be within 30 seconds of server time
X-Sdk-SignatureBase64 Ed25519 signatureCovers 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.

Using the SDK?

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)
Timestamp window

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.



Error responses

All errors follow:

{
"message": "Human-readable description",
"statusCode": 400,
"error": "Bad Request"
}
StatusMeaning
400Validation error
401Missing or invalid API key
402Insufficient credits
403Missing permission
404Resource not found
429Rate limit exceeded — check Retry-After header
502Upstream service unavailable