Skip to main content
This page is optimized for AI agent consumption. For human-friendly guides, see the Documentation.

Quick Reference

KeyValue
Base URLhttps://app.mandate.md/api
Auth headerAuthorization: Bearer <MANDATE_RUNTIME_KEY>
Content-Typeapplication/json
Live key prefixmndt_live_... (mainnet)
Test key prefixmndt_test_... (testnet)
Credential file~/.mandate/credentials.json
Non-custodialPrivate keys never leave your machine

Mandatory Security Rules

These rules are non-negotiable. Violating any of them is a security breach, not a simplification.
  1. Call /validate before EVERY transaction. No exceptions.
  2. If allowed: false, do NOT execute. Display the blockReason to the user.
  3. If the API is unreachable, do NOT execute. Do NOT fall back to the wallet directly.
  4. Display validation results to the user BEFORE any wallet call.
  5. Even with custodial wallets, validate with Mandate BEFORE calling the wallet API.
  6. Skipping validation bypasses spend limits, allowlists, and approval workflows the owner configured.

Fail-Safe Behavior

When the Mandate API is unreachable:
  1. Do NOT execute the transaction.
  2. Do NOT fall back to calling the wallet API directly.
  3. Display: Mandate: policy server unreachable, transaction halted for safety
  4. Retry up to 3 times at 30-second intervals.
  5. If all retries fail: Cannot execute until policy server recovers. No funds were spent.

Primary Endpoint: POST /validate

Policy check before every transaction. Works with any wallet type (custodial or self-custodial).
curl -X POST https://app.mandate.md/api/validate \
  -H "Authorization: Bearer $MANDATE_RUNTIME_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action":"swap","reason":"Swap 0.1 ETH for USDC","amount":"50","to":"0xAlice"}'

Parameters

FieldRequiredDescription
actionYesWhat you are doing: transfer, swap, buy, bridge, stake, bet (free text)
reasonYesWhy you are doing it (max 1000 chars). Scanned for prompt injection.
amountNoUSD value (assumes stablecoins)
toNoRecipient address (checked against allowlist)
tokenNoToken address

Response

{ "allowed": true, "intentId": "...", "action": "swap", "requiresApproval": false }
All policy checks apply: circuit breaker, schedule, allowlist, spend limits, daily/monthly quotas, reason scanner. Every call is logged to the audit trail. For full endpoint documentation, see POST /validate.

Registration: POST /agents/register

No auth required. Creates an agent identity and returns credentials.
curl -X POST https://app.mandate.md/api/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name":"MyAgent","evmAddress":"0xYourAddress","chainId":84532}'

Response

{
  "runtimeKey": "mndt_test_...",
  "agentId": "...",
  "claimUrl": "https://app.mandate.md/claim/..."
}
Display the claimUrl to the human owner so they can link the agent to their dashboard. Store runtimeKey in ~/.mandate/credentials.json with chmod 600. Agents use POST /agents/register, not dashboard login. Dashboard login is for humans only. For details, see Register an Agent.

Activation: POST /activate

Set the EVM address for a registered agent. Call once after registration. Requires auth.
curl -X POST https://app.mandate.md/api/activate \
  -H "Authorization: Bearer $MANDATE_RUNTIME_KEY" \
  -H "Content-Type: application/json" \
  -d '{"evmAddress":"0xYourAddress"}'

Status Polling: GET /intents/{id}/status

Poll the state of a validated intent.
curl https://app.mandate.md/api/intents/{intentId}/status \
  -H "Authorization: Bearer $MANDATE_RUNTIME_KEY"
For approval flows, poll until approved, then proceed. See Handle Approvals.

Validation Flow

1. POST /validate with action + reason        (policy check)
2. Execute via your wallet (Bankr, Locus, etc.)  (only if allowed: true)
3. Done.

Error Handling

HTTP Status Codes

StatusMeaningCommon Cause
400Bad RequestMissing or invalid fields
401UnauthorizedMissing or invalid runtime key
403ForbiddenCircuit breaker active
404Not FoundIntent not found
409ConflictDuplicate intentHash or wrong status
410GoneApproval expired
422Policy BlockedValidation failed (see blockReason)
429Rate LimitedToo many requests, back off and retry
500Server ErrorTransient, retry later
All errors return JSON: { "error": "message" } or { "allowed": false, "blockReason": "..." } For error handling guidance, see Handle Errors and Common Errors.

SDK Error Types

import {
  PolicyBlockedError,      // err.blockReason, err.detail, err.declineMessage
  ApprovalRequiredError,   // err.intentId, err.approvalId
  CircuitBreakerError,     // Agent circuit-broken, reset via dashboard
  RiskBlockedError,        // err.blockReason -> "aegis_critical_risk"
} from '@mandate.md/sdk';

Block Reason Values

ValueMeaning
circuit_breaker_activeAgent is circuit-broken (dashboard to reset)
no_active_policyNo policy set (visit dashboard)
intent_hash_mismatchClient hash does not match server recompute (raw validate only)
gas_limit_exceededGas too high per policy
value_wei_exceededNative ETH value too high
outside_scheduleOutside allowed hours/days
address_not_allowedRecipient not in allowlist
selector_blockedFunction selector is blocked
per_tx_limit_exceededAmount exceeds per-tx USD limit
daily_quota_exceededDaily USD limit reached
monthly_quota_exceededMonthly USD limit reached
reason_blockedPrompt injection detected in reason field
aegis_critical_riskTransaction flagged as CRITICAL risk by security scanner
For the full reference, see Block Reasons.

Intent States

StateDescriptionExpiry
allowedValidated via /validate24 hours
reservedRaw validated, waiting for broadcast15 min
approval_pendingRequires owner approval via dashboard1 hour
approvedOwner approved, broadcast window open10 min
broadcastedTx sent, waiting for on-chain receiptnone
confirmedOn-chain confirmed, quota committednone
failedReverted, dropped, policy violation, or envelope mismatchnone
expiredNot broadcast in time, quota releasednone
For the full lifecycle, see Intent Lifecycle and Intent States.

Chain Reference

Test keys (mndt_test_*): Sepolia (11155111), Base Sepolia (84532). Live keys (mndt_live_*): Ethereum (1), Base (8453).
ChainChain IDUSDC AddressDecimals
Ethereum10xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB486
Sepolia111551110x1c7D4B196Cb0C7B01d743Fbc6116a902379C72386
Base84530x833589fCD6eDb6E08f4c7C32D4f71b54bdA029136
Base Sepolia845320x036CbD53842c5426634e7929541eC2318f3dCF7e6
For the full reference, see Chain Reference.

Default Policy

After registration, every agent gets:
SettingDefault
Per-transaction limit$100
Daily limit$1,000
Address restrictionsNone (all allowed)
Approval requiredNo
Adjust policies via the dashboard or Policy Builder.

Tool-to-Endpoint Map

CLI CommandMethodPath
mandate loginPOST/api/agents/register
mandate activate <address>POST/api/activate
mandate validatePOST/api/validate
mandate validate-rawPOST/api/validate/raw (deprecated)
mandate event <id> --tx-hash 0x...POST/api/intents/{id}/events
mandate status <id>GET/api/intents/{id}/status
mandate approve <id>GET/api/intents/{id}/status (poll)
mandate scan [dir]localScan codebase for unprotected wallet calls
mandate --llmslocalMachine-readable command manifest
mandate --mcplocalStart as MCP stdio server
For CLI installation and usage, see CLI Overview.

The reason Field

Every validation call requires a reason string (max 1000 chars). This is what session keys cannot capture: the intent behind a transaction. Mandate uses the reason to:
  • Scan for prompt injection (18 hardcoded patterns + optional LLM judge)
  • Return a declineMessage on block to counter manipulation
  • Show it to the owner on approval requests (Slack, Telegram, dashboard)
  • Log it in the audit trail permanently
For details, see The reason Field and Prompt Injection Defense.

Integration Plugins

For platforms with hook support, use the plugin instead of raw API calls. Plugins enforce validation automatically.
PlatformInstallDocs
OpenClawopenclaw plugins install @mandate.md/mandate-openclaw-pluginOpenClaw
Claude Codeclaude plugin:install claude-mandate-pluginClaude Code
GOAT SDK@mandate.md/goat-pluginGOAT SDK
AgentKit@mandate.md/agentkit-providerAgentKit
ElizaOS@mandate.md/eliza-pluginElizaOS
For all integrations, see Integrations Overview.

Raw Source

The canonical machine-readable version of this reference is available at:
https://app.mandate.md/SKILL.md
Compatible with any agent framework that consumes SKILL.md files.