Skip to content

Authentication

Builder endpoints are protected by an API key, and state-changing endpoints additionally require an HMAC-SHA256 request signature.

Headers

Header Required on Description
X-Api-Key All builder endpoints Your builder API key (bld_...)
X-Timestamp /v1/submit, /v1/trades Current Unix timestamp (seconds)
X-Signature /v1/submit, /v1/trades HMAC-SHA256 signature (hex)

Endpoints that only require X-Api-Key: /v1/keys, /v1/sign, /v1/deposit/address. See the API Reference for each endpoint's exact requirements.

Signing

The signature is computed over: timestamp_string + request_body

import hmac, hashlib, time, json, requests

API_KEY = "bld_a1b2c3..."
API_SECRET = "deadbeef1234..."  # hex-encoded 32 bytes
SIGNER_URL = "https://signer.parti-oracle.pbcapps.dev"

def signed_request(method, path, body=None):
    timestamp = str(int(time.time()))
    body_str = json.dumps(body) if body else ""

    # HMAC over: timestamp + body
    message = timestamp + body_str
    signature = hmac.new(
        bytes.fromhex(API_SECRET),
        message.encode(),
        hashlib.sha256
    ).hexdigest()

    headers = {
        "X-Api-Key": API_KEY,
        "X-Timestamp": timestamp,
        "X-Signature": signature,
        "Content-Type": "application/json",
    }

    return requests.request(method, SIGNER_URL + path, 
                          headers=headers, json=body)
const crypto = require('crypto');

function signedFetch(path, body) {
  const timestamp = Math.floor(Date.now() / 1000).toString();
  const bodyStr = JSON.stringify(body);
  const message = timestamp + bodyStr;

  const signature = crypto
    .createHmac('sha256', Buffer.from(API_SECRET, 'hex'))
    .update(message)
    .digest('hex');

  return fetch(SIGNER_URL + path, {
    method: 'POST',
    headers: {
      'X-Api-Key': API_KEY,
      'X-Timestamp': timestamp,
      'X-Signature': signature,
      'Content-Type': 'application/json',
    },
    body: bodyStr,
  });
}

Replay Protection

Requests are rejected if the timestamp is more than 5 seconds old (or 5 seconds in the future). Keep your server clock synchronized — NTP is strongly recommended.

Rate Limiting

Builder signing endpoints are rate-limited with a per-key token bucket.

  • Keying: X-Api-Key when present, falling back to the client IP.
  • Default: 10 requests/second per key, with a burst capacity of 10.
  • Tunable: operators can change the limit via the RATE_LIMIT_RPS environment variable on the signer.
  • Response: HTTP 429 Too Many Requests with body {"error": "rate limit exceeded"} when the bucket is empty.
  • Admin endpoints (/v1/admin/*) and /health bypass the limiter.

If you need a higher limit for production traffic, contact the operator.

Security Notes

  • Never expose your API_SECRET in client-side code
  • All signing should happen on your backend
  • The HMAC prevents request tampering — any change to the body invalidates the signature
  • Use HTTPS for all requests