Overview

Zafeguard public REST API reference — component execution, workflow triggers, and run management. All endpoints require an API key (no JWT needed).

Overview

Base URL: https://api.zafeguard.com
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 Zafeguard Dashboard under Settings → API Keys. Both are shown once at key creation time.

The @zafeguard/caller-sdk does not require manual signing — it sends X-Api-Key alone. This signing flow only applies to 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.ZAFEGUARD_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.zafeguard.com/v1/sdk/components', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': process.env.ZAFEGUARD_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["ZAFEGUARD_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.



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

On this page