{
  "markdown": "# Sanction\n\n**The independent authorization plane for AI agents.**\n\nBefore an agent spends money, invokes a tool, touches a credential, or\nprovisions a resource, it asks Sanction. Sanction approves, escalates to a\nhuman, or denies. Every decision is logged and auditable. Sanction belongs to\nno platform: one policy engine answers across model providers, payment rails,\nidentities, and agent ecosystems.\n\n## Who runs Sanction\n\n- **Organizations governing their own AI** — the primary case. Teams and\n  departments become wallets in a tree; budgets, tool rules, and approval\n  bands are enforced — not dashboarded — with chargeback-ready reporting\n  underneath. Alerts tell you what happened; a decision happens first.\n- **Platforms and agencies embedding governance** — agents you ship or run\n  for clients carry a wallet wherever they execute: MCP hosts, Bedrock,\n  your own stack via SDK or REST.\n- **Individuals** — free, no card, personal and production use.\n\n---\n\n## What it does\n\nOne policy decision engine governs every kind of agent action:\n\n| Governed action | What Sanction enforces |\n|---|---|\n| **Spend** (`/authorize`) | Auto-approve floor, human-escalation band, per-transaction hard cap, daily and monthly budgets — checked and debited atomically. |\n| **Tools** (`/authorize/tool`) | Block/allow/escalate lists for any MCP tool or external action. Escalations reach the approval inbox like spend does. |\n| **Credentials** (`/exec` + `/mandate/verify` + `/credentials/inject`) | AES-256-GCM envelope-encrypted vault (KMS-wrapped, rotating keys). Injection requires a scoped 15-minute mandate JWT and clearance ≥ the credential's bar. Counterparties verify the mandate with no API key. Every access audit-logged. |\n| **Provisioning** (`/authorize/provision`) | Seats, licenses, infrastructure — resource, line item, quantity, and dollars authorized in one call. |\n| **Capability** (`/authorize/capability`) | Skills, plugins, new APIs — acquiring capability is governed like spending money. One ordered rule list (block / allow / escalate, prefix-glob patterns) gates new power before it lands in an agent. |\n\nWhat a decision looks like in practice — one `POST /authorize` with an\namount, three possible outcomes, all of them terminal or resumable:\n\n- **Approved** → `{ \"status\": \"approved\" }`; budget counters debit in the\n  same transaction the decision persists (an advisory lock makes sibling\n  agents queue, not race).\n- **Escalated** → `{ \"status\": \"escalated\", \"request_id\": \"…\" }`; a human\n  sees it in the approval inbox, and approving mints a one-use grant the\n  agent redeems by retrying with `grant_id`. Policy decides what a timeout\n  means (approve or deny) — nothing hangs forever.\n- **Denied** → `{ \"status\": \"denied\", \"decision_code\": \"PER_TXN_LIMIT\",\n  \"remediation\": \"Amount exceeds the per-transaction limit. Split into\n  smaller charges or ask the owner to raise the limit.\" }`. Codes are\n  stable machine strings (`DAILY_BUDGET_EXCEEDED`,\n  `CATEGORY_BLOCKED`, `WALLET_FROZEN`, …) so agents branch and replan\n  instead of parsing prose. Replays of the same request return the same code.\n\nAround the engine:\n\n- **Human approvals → one-use grants.** Escalations land in an approval inbox\n  (dashboard PWA, email, Slack). Approving mints a single-use, expiring grant\n  the agent redeems on retry. Policy timeouts guarantee a terminal outcome.\n- **Seats.** An agent is a seat you can hand to whoever holds it: named\n  holders, contractor auto-expiry (the key fails closed past the date), key\n  rotation that keeps history, and batch creation from one template.\n- **Budgets that cascade.** Wallets nest into trees; subtree caps are enforced\n  atomically so sibling agents can't race past a parent's limit. The console's\n  spend view draws the month's runway — cumulative burn against the cap, pace,\n  and the projected exhaust date — from wallet down to seat.\n- **Notifications that find you.** Email by default; signed JSON webhooks for\n  machines; and Slack two ways — a pasted incoming-webhook URL that deep-links\n  to the decision, or **Add to Slack**, which installs per workspace over OAuth\n  and posts interactive **Approve / Deny** buttons that run the same\n  `resolveApproval` path as the dashboard, actor recorded. Each route subscribes\n  to its own events. [Guide](docs/NOTIFICATIONS.md)\n- **Evidence you can replay.** Every policy edit becomes an immutable\n  revision; every decision stores the revision in force and the exact context\n  the engine evaluated. `GET /authorize/{id}/evidence` re-runs the pure rules\n  over the stored context and proves the outcome reproduces.\n- **What-if over real history.** `POST /policy/simulate` replays stored\n  decisions under a candidate policy — which calls flip, what spend wouldn't\n  clear — before you change anything.\n- **The audit plane.** `GET /audit-events` merges every decision, token log,\n  and secret access into one feed (CSV export included);\n  `GET /reporting/summary` spans any period with day buckets and per-seat\n  rollups; wallet stats project burn pace and exhaustion ETAs; a weekly\n  digest lands in Slack every Monday.\n- **Tamper-evident exports.** `GET /audit/export` hands you a signed,\n  hash-chained snapshot of your governed decisions: altering, dropping, or\n  reordering any row breaks the chain, and the head is HMAC-signed by Sanction.\n  A regulator or the governed customer runs `POST /audit/verify` — self-contained,\n  no database — to prove nothing changed after signing, down to the first broken link.\n- **A console that opens on the roster.** The dashboard home is the wallet tree\n  as groups with agents as cards, each carrying a mandate stamp (live / paused /\n  blocked). A wallet holds people, not just keys: team membership with roles\n  (`owner` / `admin` / `viewer`), a switcher across every membership, and a\n  viewer who can read everything and change nothing.\n- **Adopt without enforcing.** Observe mode runs the real engine on a live fleet\n  and records what it *would* have done — blocking nothing, moving no counters —\n  so you can watch a week of would-be denials and the dollars behind them, then\n  flip each pool to enforce in one confirm-gated click.\n- **Spend answerable to outcomes.** Report outcomes (`POST /outcomes`) and a\n  wallet over its cost-per-outcome ceiling throttles to human-gated spend.\n  Wallets can be frozen outright, and budget reallocated across the tree.\n- **LLM gateway.** Point your model SDK's base URL at\n  `https://getsanction.com/api/gateway/<provider>` with `x-sanction-key` —\n  usage is metered and budget-capped with zero per-call instrumentation.\n\nEvery security claim above maps to enforcing code and a regression test in\n[docs/TRACEABILITY.md](docs/TRACEABILITY.md) — 1,100+ tests behind a coverage\ngate of 90% statements/lines, 94% functions, and 83% branches, including\nconcurrency and Postgres row-level-security suites.\n\n### Start from a pack, not a blank policy\n\nEleven installable policy packs cover the common shapes — **Startup defaults**,\n**Coding agent seat**, **MCP tool governance**, **Compliance baseline**,\n**Client-safe launch**, and **No-egress** (Sanction Local) among them. `GET /policy/packs` lists them;\n`POST /policy/packs/{id}/preview` simulates one against your last 30 days of\nreal decisions before anything changes; `apply` writes it as a policy revision.\n\n### Changing policy in production\n\nPolicy edits are never a leap of faith:\n\n1. Draft the change (or pick a pack).\n2. `POST /policy/simulate` replays your stored decision history under the\n   candidate — see exactly which calls flip and what spend wouldn't clear.\n3. Apply. The edit becomes an immutable revision; every subsequent decision\n   records the revision in force.\n4. If a decision is ever questioned, `GET /authorize/{id}/evidence` re-runs\n   the rules over the stored context and proves the outcome reproduces.\n\n### When to use the credential vault\n\nUse Sanction's vault when credentials should flow through the same\npolicy, approval, and audit trail as spend and tools — one clearance model,\nno separate secrets cluster. Keep your existing Vault or Secrets Manager\nwhen you need fleet-scale secret lifecycle management independent of agent\ngovernance; Sanction consumes upstream identity and secrets rather than\nreplacing them. Threat model: [docs/SECURITY.md](docs/SECURITY.md).\n\n---\n\n## Distribution\n\nPlatform vendors govern agents inside their own walls. Sanction authorizes\nagents wherever they run. Pick the shortest path to your stack:\n\n| You want to… | Use | First step |\n|---|---|---|\n| Govern any MCP host (Claude Desktop, Cursor, …) | MCP wallet | Paste `https://getsanction.com/mcp` or `npx sanction-mcp` |\n| Intercept tools/call to an MCP server | MCP broker | Register the upstream, point the host at `/mcp/broker/<name>` |\n| Meter model spend with zero code changes | LLM gateway | Point the SDK base URL at `/api/gateway/<provider>` |\n| Govern agents in a TypeScript app | SDK | `npm install sanction-sdk` |\n| Call the engine from anything else | REST API | `POST /v1/authorize` with an `x-api-key` |\n| Plug into an AuthZEN enforcement point | PDP | Point it at `/api/access/v1/evaluation` |\n| Orchestrate on AWS Bedrock | Action Group | [docs/BEDROCK.md](docs/BEDROCK.md) |\n\nThe full menu:\n\n- **MCP (agent wallet)** — paste `https://getsanction.com/mcp` (Streamable HTTP, `x-api-key`) or `npx sanction-mcp` in any MCP host. The agent carries the wallet. [Wallet Card](https://getsanction.com/.well-known/wallet-card.json) · [guide](docs/AGENT-WALLET.md)\n- **AuthZEN PDP** — any [OpenID AuthZEN 1.0](https://openid.net/specs/authorization-api-1_0.html) enforcement point can use Sanction as its decision point, zero custom code ([guide](docs/AUTHZEN.md))\n- **TypeScript SDK** — `npm install sanction-sdk` ([source](sdk/)): `SanctionClient` (agent plane) and `SanctionAdminClient` (management plane), plus framework adapters (`SanctionMiddleware`, `sanctionTool`)\n- **REST API** — direct integration, OpenAPI 3.0 spec at `/api/openapi.json` (Bedrock-compatible)\n- **AWS Bedrock Action Group** — enterprise agent orchestration ([setup guide](docs/BEDROCK.md))\n- **LLM gateway** — cross-provider metering with no code changes\n\nFastest first decision: `bash examples/setup.sh` — wallet, agent, and a demo\npolicy in one command, printing the env exports your agent needs\n([examples/](examples/) has runnable clients to point at it).\n\n[Agent wallet](docs/AGENT-WALLET.md) ·\n[Quickstart](docs/QUICKSTART.md) ·\n[Starter kit](docs/STARTER-KIT.md) ·\n[LangChain](docs/LANGCHAIN.md) · [CrewAI](docs/CREWAI.md) ·\n[Vercel AI SDK](docs/VERCEL-AI-SDK.md) ·\n[Bedrock Agents](docs/BEDROCK.md) ·\n[Agent fleets](docs/AGENT-FLEETS.md) ·\n[AuthZEN PDP](docs/AUTHZEN.md) ·\n[Multi-tenant runbook](docs/INTEGRATION.md) ·\n[Notifications](docs/NOTIFICATIONS.md)\n\n---\n\n## API\n\nBase URL: `https://getsanction.com/api/v1` — grouped by workflow. Agent\nendpoints take `x-api-key pxy_…`; management endpoints take the owner's\n`x-mgmt-key sk_…`.\n\n**Ask permission** — the data plane an agent calls:\n\n```\nPOST  /authorize                — Authorize a spend action (grant_id redeems an approval)\nPOST  /authorize/quote          — Authorize an x402 payment challenge before the wallet signs\nPOST  /authorize/tool           — Authorize a tool invocation\nPOST  /authorize/provision      — Authorize provisioning (resource + line item + $)\nPOST  /authorize/capability     — Authorize acquiring capability (skill/plugin/API)\nGET   /authorize/{id}           — Poll an escalated decision (grant receipt included)\nPOST  /tokens                   — Log LLM token consumption against the daily budget\nPOST  /outcomes                 — Report an outcome; spend becomes answerable to results\n```\n\n**Escalate to a human** — over the line, someone decides:\n\n```\nGET/POST /approvals             — The approval inbox; approving mints a one-use grant\n```\n\n**Carry credentials** — scoped mandates instead of raw secrets:\n\n```\nPOST  /exec                     — Mint a scoped mandate JWT (15-min TTL)\nPOST  /mandate/verify           — Counterparty checks a presented mandate (no API key)\nPOST  /credentials/inject       — Inject a decrypted credential (Bearer JWT)\nPOST  /credentials/vault        — Store an encrypted credential (owner)\nPOST  /exec/revoke              — Kill a live execution token (owner)\n```\n\n**Prove what happened** — audit, evidence, reporting:\n\n```\nGET   /authorize/{id}/evidence  — Audit proof: re-run the pure rules over the stored\n                                  context and confirm the recorded outcome reproduces\nGET   /audit-events             — Unified audit feed (decisions, tokens, secret access; ?format=csv)\nGET   /reporting/summary        — Any range ≤92 days: totals, day buckets, per-agent\nGET   /reporting/daily-summary  — One-day rollup\nGET   /audit/export             — Signed, hash-chained decision export (owner; ?download=1)\nPOST  /audit/verify             — Verify a tamper-evident export (recompute chain + signature)\n```\n\n**Shape policy** — edit safely, prove impact first (owner):\n\n```\nGET/PATCH /wallets/policy       — Read / update budgets, thresholds, lists, capability rules\nPOST  /policy/simulate          — Replay real history under a candidate policy (what-if)\nGET   /policy/packs             — List installable policy packs (public)\nPOST  /policy/packs/{id}/preview — Simulate a pack against your last 30 days\nPOST  /policy/packs/{id}/apply  — Install a pack as the wallet policy (writes a revision)\n```\n\n**Run the fleet** — wallets, seats, keys (owner):\n\n```\nPOST  /wallets                  — Create a wallet + policy (management key shown once)\nGET   /wallets/stats            — Today + month-to-date stats + burn projections\nGET   /wallets/tree             — Subtree spend rollup\nPOST  /wallets/keys/rotate      — Rotate the wallet's data-encryption key\nPOST  /agents                   — Register a seat (holder, expiry; key shown once)\nPOST  /agents/batch             — Stamp one template across up to 50 seats\nGET/PATCH /agents               — List / per-seat budgets, clearance, holder, expiry\nPOST  /agents/rotate            — Rotate a seat's key (optionally pass to a new holder)\nPOST  /webhooks                 — Register a notification route (per-event subscriptions)\nPOST/GET/DELETE /broker/upstreams — Register the MCP servers the broker may front (BROKER-1)\nPOST  /wallets/freeze           — Pause every agent action in this wallet and its subtree\nPOST  /wallets/unfreeze         — Resume exactly where the fleet stopped\nPOST  /wallets/reallocate       — Move budget across the wallet tree\nPOST  /wallets/bootstrap-key    — Mint a management key for a legacy wallet\nGET   /outcomes                 — Reported outcomes + cost-per-outcome state\nGET   /activity                 — Recent decision activity for the console\n```\n\n**Speak the standard** — AuthZEN PDP + AARP (agent key; base\n`https://getsanction.com/api` — spec-canonical paths):\n\n```\nPOST  /access/v1/evaluation     — OpenID AuthZEN 1.0 evaluation (decision-only)\nPOST  /access/v1/evaluations    — AuthZEN batch, all three evaluation semantics\nPOST  /access/v1/access-request — AARP: open an escalation from a signed binding token\nGET   /access/v1/access-request/{id} — AARP task status (maps to the profile's states)\n```\n\nFull schemas: [`/api/openapi.json`](https://getsanction.com/api/openapi.json).\n\n---\n\n## MCP setup\n\nThe agent carries a Sanction wallet. Discovery: `GET /.well-known/wallet-card.json`.\nstdio MCP is cooperative — the host must ask before acting.\nCursor plugin (MCP + skills): [`cursor-plugin/`](cursor-plugin/).\n\n```json\n{\n  \"mcpServers\": {\n    \"sanction\": {\n      \"command\": \"npx\",\n      \"args\": [\"sanction-mcp\"],\n      \"env\": {\n        \"SANCTION_API_URL\": \"https://getsanction.com/api/v1\",\n        \"SANCTION_API_KEY\": \"pxy_...\"\n      }\n    }\n  }\n}\n```\n\n---\n\n## Stack\n\nNext.js 16 (App Router) + TypeScript · Prisma 7 on Neon Postgres (row-level\nsecurity enforced at the database) · Vercel · jose (HS256, alg-pinned) ·\nAES-256-GCM envelope encryption with AWS KMS root of trust in production.\n\n## Contributing & security\n\n[CONTRIBUTING.md](CONTRIBUTING.md) gets you from clone to green PR\n(`npm install && npm run check` — no database needed for unit tests).\nSecurity model and disclosure: [docs/SECURITY.md](docs/SECURITY.md).\nVocabulary: [docs/DOMAIN.md](docs/DOMAIN.md).\n\n## Pricing\n\nIt's free, or it's an agreement. **Free** for individuals — no card, personal\nand production use. Beyond that, an enterprise agreement shaped to your\ndeployment: SSO, policy administration, audit export, SLA.\n[Talk to us](https://getsanction.com/#pricing).\n\n## License\n\n- **`packages/sanction-mcp`** (the MCP client) — [MIT](packages/sanction-mcp/LICENSE). Embed it anywhere.\n- **Everything else** (server, dashboard, API) — [Functional Source License 1.1](LICENSE) (FSL-1.1-MIT). Source-available: use and self-host for any purpose except offering a competing service. Converts to MIT two years after release.\n- **Commercial use beyond the FSL** — [Commercial License guide](docs/COMMERCIAL-LICENSE.md) ([on-site](https://getsanction.com/docs/commercial-license)).\n",
  "bytes": 17118,
  "sha": "2be8a360ecaaf684d571f3c5ea5f8b0f757396d0f6513799c5aa043367baac74",
  "repo_slug": "ericlovold/sanction",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_ericlovold_sanction_35183ca5/readme"
}