QUICKSTART

DOCS

Five minutes to your first signed receipt.

// 01

Install & seed

npm install
npm run setup        # prisma generate + db push + seed default Atlas-01
npm run dev

The seed prints a demo API key to your terminal. Save it — it is hashed and discarded.

// 02

Create an agent

curl -X POST http://localhost:3000/api/agents \
  -H "content-type: application/json" \
  -d '{ "name": "Atlas-02", "role": "Research agent" }'

The response contains apiKey — shown once, never again.

// 03

Create / update a mandate

curl -X POST http://localhost:3000/api/mandates \
  -H "content-type: application/json" \
  -d '{
    "agentId": "agent_xxx",
    "name": "research-budget-v1",
    "dailyBudgetUsd": 25,
    "maxCostPerActionUsd": 2,
    "approvalThresholdUsd": 5,
    "allowedTools": ["paid_api_call","web_search"],
    "blockedTools": ["wallet_transfer","shell_exec"],
    "blockedActions": ["transfer_usdc","delete_files"],
    "approvalRequiredActions": ["send_email"],
    "allowedDomains": ["api.openai.com"],
    "blockedDomains": ["unknown-wallet.site"]
  }'
// 04

Preflight check (the wire contract)

curl -X POST http://localhost:3000/api/check \
  -H "Authorization: Bearer msk_xxx" \
  -H "content-type: application/json" \
  -d '{
    "agentId": "agent_xxx",
    "actionType": "paid_api_call",
    "tool": "paid_api_call",
    "target": "https://api.openai.com/v1/responses",
    "costUsd": 0.02
  }'

Returns decision (APPROVED · BLOCKED · NEEDS_APPROVAL), reason, matchedRule, riskLevel, and the full signed receipt.

// 05

Verify a receipt

curl -X POST http://localhost:3000/api/verify \
  -H "content-type: application/json" \
  -d '{ "id": "rct_xxxxxx" }'

Or POST the full receipt JSON. Returns { "valid": true | false, "reasons": [...] }.

// 06

TypeScript SDK

import { MandateSeal } from "@/sdk/mandateseal";

const seal = new MandateSeal({
  apiKey: process.env.MANDATESEAL_API_KEY!,
  baseUrl: "http://localhost:3000",
});

const result = await seal.check({
  agentId: "agent_atlas_01",
  actionType: "paid_api_call",
  tool: "paid_api_call",
  target: "https://api.openai.com/v1/responses",
  costUsd: 0.02,
});

if (result.decision !== "APPROVED") {
  throw new Error(result.reason);
}

// run your action…

const proof = await seal.verifyReceipt(result.receipt);
if (!proof.valid) throw new Error("receipt tampered with");
// 07

Policy engine — rules in order

  1. If mandate is disabled → APPROVED.
  2. Tool in blockedTools → BLOCKED.
  3. actionType in blockedActions → BLOCKED.
  4. Target domain in blockedDomains → BLOCKED.
  5. cost > maxCostPerActionUsd → BLOCKED.
  6. cost > approvalThresholdUsd → NEEDS_APPROVAL.
  7. actionType in approvalRequiredActions → NEEDS_APPROVAL.
  8. If allowedTools is non-empty and tool not in it → BLOCKED.
  9. If allowedDomains is non-empty and target not in it → BLOCKED.
  10. Otherwise → APPROVED.