API reference

Every endpoint on the Mandate Labs platform — onboarding through authorization — with the auth it needs, its parameters, and a real request/response pair. All requests are HTTPS and exchange JSON.

Introduction

The Mandate Labs API is organized around the object hierarchy Client → Program → Principal → Agent → Mandate → Authorization. If you haven't yet, read Core concepts for how those objects nest and why.

All endpoints share a single base URL and are versioned under /api/v1:

https://api.mandatelabs.ai/api/v1

Requests and responses are application/json. Monetary amounts are strings or numbers in the minor-unit-free decimal form (e.g. "42.99"); IDs are prefixed by object type (cli_, prg_, prn_, agt_, mnd_, auth_). Errors use a uniform envelope — see Errors & idempotency.

Three credential planes

The platform has three distinct authentication contexts: the Client key drives onboarding, the Principal key drives the live agent/authorization endpoints, and the Admin key provisions Clients. Each endpoint below notes which one it expects.

Authentication

Mandate Labs uses three credential types. Which one an endpoint accepts depends on the plane it belongs to.

Client API key onboarding

Pass a Client key in the X-API-Key header. Client keys are issued by Mandate Labs when your organization is provisioned (or via the Admin API) and authenticate the onboarding endpoints — everything that creates Principals, Agents, and Mandates on behalf of your tenant.

X-API-Key: mdt_live_…    # live
X-API-Key: mdt_test_…    # sandbox

Principal API key runtime

Also passed as X-API-Key, a Principal key authenticates the runtime endpoints — /authorize, /agents, /mandates, /webhooks, and /thresholds. Every read and write on these planes is scoped (tenant-isolated) to the authenticated Principal. In the sandbox playground, a per-Principal sandbox key is minted for you (see Onboarding).

Provisioning

Client provisioning and credential lifecycle are performed by Mandate Labs using an internal operator key. Those endpoints are not part of the public API — your Client and its API key are issued to you during onboarding (book a call).

OAuth2 & environments

OAuth2 client-credentials is also supported for Client authentication — present the issued bearer token as Authorization: Bearer … instead of X-API-Key. The environment is implied by the key prefix: mdt_live_ is live, mdt_test_ is sandbox. Sandbox keys behave identically but never touch real rails.

Onboarding

Client-authenticated endpoints that build your tenant graph. The core invariant: a Principal is one stable prn_ that owns many Agents — create the Principal once, then add agents to it. All create endpoints accept an Idempotency-Key header (see idempotency).

Create a full onboarding bundle

POST /api/v1/onboard

Atomically creates a Principal, its first Agent, and a Mandate in one call. Client key Ideal for quickstart and sandbox; use the decoupled endpoints below to add more agents later. Returns 201 (or 202 when the Principal needs platform verification).

Body paramTypeReqNotes
principalobjectyesA full Principal registration object (see Register a Principal).
agentobjectyesname (required), plus optional capabilities, program_id, external_agent_ref, metadata.
mandateobjectyesrails + limits (see Create a Mandate).
curl -X POST https://api.mandatelabs.ai/api/v1/onboard \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -d '{
    "principal": {
      "principal_kind": "merchant",
      "program_ids": ["prg_…"],
      "client_customer_ref": "acme-001",
      "profile": { "display_name": "Acme Corp", "email": "[email protected]", "country": "US" },
      "verification": {
        "type": "KYB", "mode": "client_attested",
        "attestation": {
          "attested_by": "[email protected]",
          "scope": "Tier-2 CDD",
          "statement": "Acme performed CDD on this merchant",
          "evidence_ref": "case-123"
        }
      }
    },
    "agent": { "name": "Shopping Assistant v1", "capabilities": ["payments.authorize"] },
    "mandate": {
      "rails": ["card"],
      "limits": { "max_amount_per_transaction": 500, "max_daily_amount": 2000, "currency": "USD" }
    }
  }'
{
  "principal": {
    "id": "prn_…",
    "client_id": "cli_…",
    "principal_kind": "merchant",
    "client_customer_ref": "acme-001",
    "verification_status": "VERIFIED",
    "verification_mode": "client_attested",
    "risk_tier": "LOW",
    "programs": ["prg_…"],
    "agents": [],
    "verification_session": null,
    "created_at": "2026-06-27T18:04:11Z"
  },
  "agent": {
    "id": "agt_…",
    "principal_id": "prn_…",
    "program_id": "prg_…",
    "did": "did:key:z6Mk…",
    "name": "Shopping Assistant v1",
    "status": "ACTIVE",
    "trust_level": "REGISTERED",
    "kya_score": null
  },
  "mandate": {
    "id": "mnd_…",
    "agent_id": "agt_…",
    "program_id": "prg_…",
    "status": "ACTIVE",
    "rails": ["card"],
    "limits": { "max_amount_per_transaction": 500.0, "max_daily_amount": 2000.0, "currency": "USD" },
    "mandate_hash": "sha256:…",
    "valid_until": "2027-06-27T18:04:11Z"
  }
}

Register a Principal

POST /api/v1/principals

Registers a Principal under the Client and enrolls it into one or more Programs. Client key Returns 201 for client_attested (verified immediately) or 202 for platform_provider (verification pending; the response carries a verification_session).

Body paramTypeReqNotes
principal_kindstringyes"personal" or "merchant".
program_idsstring[]yes≥1 Program the Client owns; the Principal is enrolled in each.
profileobjectyesdisplay_name, email (required); optional phone (E.164), country.
verificationobjectyestype (KYC/KYB), mode (client_attested/platform_provider), and attestation (required for client_attested).
client_customer_refstringnoYour own reference; unique per Client.
step_upobjectnomethod (sms/email) + optional phone.
metadataobjectnoArbitrary key/value pairs.
curl -X POST https://api.mandatelabs.ai/api/v1/principals \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -d '{
    "principal_kind": "merchant",
    "program_ids": ["prg_…"],
    "client_customer_ref": "acme-001",
    "profile": { "display_name": "Acme Corp", "email": "[email protected]", "country": "US" },
    "verification": {
      "type": "KYB", "mode": "client_attested",
      "attestation": { "attested_by": "[email protected]", "scope": "Tier-2 CDD",
        "statement": "Acme performed CDD on this merchant", "evidence_ref": "case-123" }
    }
  }'
{
  "id": "prn_…",
  "client_id": "cli_…",
  "principal_kind": "merchant",
  "client_customer_ref": "acme-001",
  "verification_status": "VERIFIED",
  "verification_mode": "client_attested",
  "risk_tier": "LOW",
  "programs": ["prg_…"],
  "agents": [],
  "verification_session": null,
  "created_at": "2026-06-27T18:04:11Z"
}

Get a Principal

GET /api/v1/principals/{principal_id}

Returns the authenticated Principal's own record. Principal key A Principal can only read itself — requesting another prn_ returns 403.

curl https://api.mandatelabs.ai/api/v1/principals/prn_… \
  -H "X-API-Key: mdt_live_…"
{
  "id": "prn_…",
  "principal_kind": "merchant",
  "verification_status": "VERIFIED",
  "risk_tier": "LOW",
  "client_customer_ref": "acme-001"
}

Enroll a Principal into another Program

POST /api/v1/principals/{principal_id}/programs

Adds an existing Principal to an additional Program (many-to-many). Client key Idempotent — re-enrolling is a safe no-op. Returns the full list of enrolled program IDs.

Body: program_id (string, required) — a Program the Client owns.

curl -X POST https://api.mandatelabs.ai/api/v1/principals/prn_…/programs \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -d '{ "program_id": "prg_crypto_…" }'
{
  "principal_id": "prn_…",
  "programs": ["prg_…", "prg_crypto_…"]
}

Add an Agent under a Principal

POST /api/v1/principals/{principal_id}/agents

Registers a new Agent under an existing Principal — call once per agent. Client key This is how you honor the one-identity-many-agents invariant. If the Principal is enrolled in exactly one Program the agent inherits it; otherwise pass program_id.

Body paramTypeReqNotes
namestringyesDisplay name for the agent.
program_idstringnoRequired only when the Principal is enrolled in 0 or >1 Programs.
capabilitiesstring[]noDeclared capabilities (defaults to ["PURCHASE"]).
external_agent_refstringnoYour own reference for the agent.
metadataobjectnoArbitrary key/value pairs.
curl -X POST https://api.mandatelabs.ai/api/v1/principals/prn_…/agents \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -d '{ "name": "Shopping Assistant v2", "capabilities": ["payments.authorize"] }'
{
  "id": "agt_…",
  "principal_id": "prn_…",
  "client_id": "cli_…",
  "program_id": "prg_…",
  "did": "did:key:z6Mk…",
  "name": "Shopping Assistant v2",
  "status": "ACTIVE",
  "trust_level": "REGISTERED",
  "kya_score": null,
  "created_at": "2026-06-27T18:06:02Z"
}

List a Principal's Agents

GET /api/v1/principals/{principal_id}/agents

Lists every Agent registered under the Principal. Client key

curl https://api.mandatelabs.ai/api/v1/principals/prn_…/agents \
  -H "X-API-Key: mdt_live_…"
{
  "principal_id": "prn_…",
  "agents": [
    { "id": "agt_…", "name": "Shopping Assistant v1", "status": "ACTIVE", "trust_level": "VERIFIED", "kya_score": 0.81 },
    { "id": "agt_…", "name": "Shopping Assistant v2", "status": "ACTIVE", "trust_level": "REGISTERED", "kya_score": null }
  ],
  "count": 2
}

Create a Mandate for an Agent

POST /api/v1/agents/{agent_id}/mandates

Grants spending authority to an Agent — card, crypto, or both. Client key When crypto is in rails, a crypto block is required.

Body paramTypeReqNotes
railsstring[]yesSubset of {"card","crypto"}.
limitsobjectyesmax_amount_per_transaction, max_daily_amount (both >0), currency (ISO 4217).
allowed_mccsstring[]noAllowed Merchant Category Codes.
allowed_countriesstring[]noAllowed ISO country codes.
cryptoobjectcond.chains, assets, optional max_transfer. Required iff crypto ∈ rails.
valid_untildatetimenoExpiry; defaults to ~1 year.
curl -X POST https://api.mandatelabs.ai/api/v1/agents/agt_…/mandates \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -d '{
    "rails": ["card"],
    "limits": { "max_amount_per_transaction": 500, "max_daily_amount": 2000, "currency": "USD" },
    "allowed_mccs": ["5411", "5812"],
    "allowed_countries": ["US"]
  }'
{
  "id": "mnd_…",
  "agent_id": "agt_…",
  "program_id": "prg_…",
  "status": "ACTIVE",
  "rails": ["card"],
  "limits": { "max_amount_per_transaction": 500.0, "max_daily_amount": 2000.0, "currency": "USD" },
  "mandate_hash": "sha256:…",
  "valid_until": "2027-06-27T18:08:40Z",
  "created_at": "2026-06-27T18:08:40Z"
}

Mint a sandbox key for a Principal

POST /api/v1/principals/{principal_id}/sandbox-key

Mints a per-Principal sandbox API key so a freshly onboarded dev Principal can drive the runtime endpoints itself. Client key (sandbox) Playground-only — refused (403 sandbox_only) with a live credential. The key is shown once.

curl -X POST https://api.mandatelabs.ai/api/v1/principals/prn_…/sandbox-key \
  -H "X-API-Key: mdt_test_…"
{
  "principal_id": "prn_…",
  "api_key": "mdt_test_…",
  "env": "sandbox",
  "message": "Sandbox key for this Principal — use as X-API-Key. Shown once."
}

Authorization

The runtime decision plane. POST /authorize is the core operation — every transaction an agent attempts is evaluated here against its mandate, velocity limits, and KYA trust score, and recorded as an immutable Authorization. Principal key

Authorize a transaction

POST /api/v1/authorize

Evaluates a transaction and returns a real-time APPROVE / DECLINE / STEP_UP decision with reason codes, KYA score, and a structured risk assessment. Provide at least one of agent_id or agent_did. intent_context is mandatory on every request.

Body paramTypeReqNotes
agent_id / agent_didstringoneIdentify the agent (agt_ id or its DID).
amountdecimalyesTransaction amount, >0.
currencystringnoISO 4217, defaults to USD.
mccstringno4-digit Merchant Category Code.
merchant_name / merchant_idstringnoMerchant display name / identifier.
countrystringnoISO 3166-1 alpha-3.
intent_contextobjectyesintent_type, task_reference (required), plus optional reasoning_summary, confidence, alternatives_considered.
railstringnoCARD (default) or CRYPTO; CRYPTO requires a crypto block.
idempotency_keystringno8–128 chars; prevents duplicate authorizations.
curl -X POST https://api.mandatelabs.ai/api/v1/authorize \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_…",
    "amount": "42.99",
    "currency": "USD",
    "merchant_name": "Whole Foods Market #1042",
    "mcc": "5411",
    "intent_context": {
      "intent_type": "PURCHASE",
      "task_reference": "weekly_grocery_purchase",
      "reasoning_summary": "Weekly organic produce restock; compared 3 nearby grocers",
      "confidence": 0.91,
      "alternatives_considered": 3
    }
  }'
{
  "authorization_id": "auth_…",
  "decision": "APPROVE",
  "reason_codes": [],
  "reason_detail": "",
  "agent_id": "agt_…",
  "mandate_id": "mnd_…",
  "kya_score": 0.87,
  "trust_level": "VERIFIED",
  "risk_score": 0.12,
  "risk_assessment": {
    "score": 0.12, "reason_codes": [], "condition_code": "00",
    "velocity_indicator": false, "highest_severity": "NONE"
  },
  "daily_amount_used": 128.40,
  "daily_count_used": 3,
  "intent_context_provided": true,
  "intent_anomaly_score": 0.05,
  "intent_anomaly_triggered": false,
  "cognitive_limit_active": false,
  "cognitive_limit_multiplier": 1.0,
  "processing_time_ms": 8.4
}

Get an authorization log entry

GET /api/v1/authorize/log/{authorization_id}

Retrieves a single authorization decision from the audit log. Principal key Tenant-scoped — only the owning Principal's authorizations are visible.

curl https://api.mandatelabs.ai/api/v1/authorize/log/auth_… \
  -H "X-API-Key: mdt_live_…"
{
  "id": "auth_…",
  "agent_id": "agt_…",
  "mandate_id": "mnd_…",
  "amount": 42.99,
  "currency": "USD",
  "mcc": "5411",
  "merchant_id": null,
  "country": "USA",
  "decision": "APPROVE",
  "reason_codes": [],
  "kya_score": 0.87,
  "trust_level": "VERIFIED",
  "processing_time_ms": 8.4,
  "created_at": "2026-06-27T18:10:55Z"
}

List an agent's authorization history

GET /api/v1/authorize/log/agent/{agent_id}

Returns the agent's authorization history, newest first, paginated. Principal key

Query: standard pagination params (e.g. limit, cursor).

curl https://api.mandatelabs.ai/api/v1/authorize/log/agent/agt_…?limit=2 \
  -H "X-API-Key: mdt_live_…"
{
  "items": [
    { "id": "auth_…", "decision": "APPROVE", "amount": 42.99, "currency": "USD", "created_at": "2026-06-27T18:10:55Z" },
    { "id": "auth_…", "decision": "STEP_UP", "amount": 4800.00, "currency": "USD", "created_at": "2026-06-27T17:55:01Z" }
  ],
  "next_cursor": "…"
}

Agents

Manage and query agents under the authenticated Principal. Principal key Note: in onboarding you add agents via /principals/{id}/agents; these endpoints operate on the runtime plane.

Register an agent

POST /api/v1/agents

Registers a new agent for the authenticated Principal. Principal key If principal_id is supplied it must match the key's Principal.

Body paramTypeReqNotes
display_namestringyesAgent display name.
capabilitiesstring[]yes≥1 of PURCHASE, SUBSCRIPTION, REFUND_REQUEST, BALANCE_INQUIRY, TRANSFER.
didstringnoW3C DID; a did:key is auto-generated if omitted.
public_key_jwk + registration_proofobject / stringnoAgent key + proof of possession (required for Verifiable Intent).
curl -X POST https://api.mandatelabs.ai/api/v1/agents \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -d '{ "display_name": "Procurement Bot", "capabilities": ["PURCHASE"] }'
{
  "id": "agt_…",
  "did": "did:key:z6Mk…",
  "did_method": "key",
  "display_name": "Procurement Bot",
  "principal_id": "prn_…",
  "status": "ACTIVE",
  "trust_level": "REGISTERED",
  "capabilities": ["PURCHASE"],
  "total_transactions": 0,
  "decline_rate": 0.0,
  "created_at": "2026-06-27T18:12:00Z"
}

List agents

GET /api/v1/agents

Lists agents belonging to the authenticated Principal. Principal key

Query: status, trust_level, page (≥1), page_size (1–100).

curl "https://api.mandatelabs.ai/api/v1/agents?trust_level=VERIFIED&page_size=50" \
  -H "X-API-Key: mdt_live_…"
{
  "agents": [ { "id": "agt_…", "display_name": "Procurement Bot", "trust_level": "VERIFIED", "status": "ACTIVE" } ],
  "total": 1,
  "page": 1,
  "page_size": 50
}

Get an agent

GET /api/v1/agents/{agent_id}

Fetches a single agent (must belong to the authenticated Principal). Principal key

curl https://api.mandatelabs.ai/api/v1/agents/agt_… \
  -H "X-API-Key: mdt_live_…"
{
  "id": "agt_…",
  "display_name": "Procurement Bot",
  "trust_level": "VERIFIED",
  "status": "ACTIVE",
  "capabilities": ["PURCHASE"],
  "total_transactions": 214,
  "decline_rate": 0.03
}

Get agent metrics

GET /api/v1/agents/{agent_id}/metrics

Returns behavioral metrics and trust-promotion status for an agent. Principal key

curl https://api.mandatelabs.ai/api/v1/agents/agt_…/metrics \
  -H "X-API-Key: mdt_live_…"
{
  "agent_id": "agt_…",
  "trust_level": "VERIFIED",
  "total_transactions": 214,
  "successful_transactions": 207,
  "declined_transactions": 7,
  "decline_rate": 0.03,
  "dispute_deflection_rate": 0.98,
  "trust_promotion_eligible": true,
  "next_trust_level": "TRUSTED",
  "promotion_criteria": { "min_successful_txns": { "required": 200, "actual": 207, "met": true } }
}

Update agent status

PATCH /api/v1/agents/{agent_id}/status

Suspends, reactivates, or revokes an agent. Principal key

Body: status (new AgentStatus) and reason (1–500 chars), both required.

curl -X PATCH https://api.mandatelabs.ai/api/v1/agents/agt_…/status \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -d '{ "status": "SUSPENDED", "reason": "Manual review pending" }'
{
  "id": "agt_…",
  "status": "SUSPENDED",
  "trust_level": "VERIFIED",
  "display_name": "Procurement Bot"
}

Mandates

Create and query spending mandates on the runtime plane. Principal key The agent a mandate targets must belong to the authenticated Principal.

Create a mandate

POST /api/v1/mandates

Creates a new spending mandate for an agent (AP2-compatible). Principal key

Body paramTypeReqNotes
agent_idstringyesTarget agent (owned by the Principal).
valid_untildatetimeyesMandate expiry.
max_amount_per_transactiondecimalyes>0, 2 decimal places.
currencystringnoISO 4217, defaults to USD.
max_daily_amount / max_monthly_amountdecimalnoVelocity caps.
allowed_mccs / blocked_mccsstring[]noMCC allow/block lists.
allowed_countries / blocked_countriesstring[]noCountry allow/block lists.
allowed_chains / allowed_assets / allowed_counterpartiesstring[]noCrypto-rail constraints.
curl -X POST https://api.mandatelabs.ai/api/v1/mandates \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_…",
    "valid_until": "2027-01-01T00:00:00Z",
    "max_amount_per_transaction": "500.00",
    "max_daily_amount": "2000.00",
    "currency": "USD",
    "allowed_mccs": ["5411", "5812"]
  }'
{
  "id": "mnd_…",
  "agent_id": "agt_…",
  "principal_id": "prn_…",
  "status": "ACTIVE",
  "valid_from": "2026-06-27T18:14:30Z",
  "valid_until": "2027-01-01T00:00:00Z",
  "max_amount_per_transaction": 500.00,
  "currency": "USD",
  "max_daily_amount": 2000.00,
  "allowed_mccs": ["5411", "5812"],
  "mandate_hash": "sha256:…",
  "created_at": "2026-06-27T18:14:30Z"
}

Get a mandate

GET /api/v1/mandates/{mandate_id}

Fetches a mandate (ownership is verified through its agent). Principal key

curl https://api.mandatelabs.ai/api/v1/mandates/mnd_… \
  -H "X-API-Key: mdt_live_…"
{
  "id": "mnd_…",
  "agent_id": "agt_…",
  "status": "ACTIVE",
  "max_amount_per_transaction": 500.00,
  "currency": "USD",
  "valid_until": "2027-01-01T00:00:00Z"
}

List an agent's mandates

GET /api/v1/mandates/agent/{agent_id}

Lists all mandates for a given agent. Principal key

Query: status (optional MandateStatus filter).

curl https://api.mandatelabs.ai/api/v1/mandates/agent/agt_… \
  -H "X-API-Key: mdt_live_…"
{
  "mandates": [ { "id": "mnd_…", "status": "ACTIVE", "max_amount_per_transaction": 500.00, "currency": "USD" } ],
  "total": 1
}

Webhooks

Register HTTPS endpoints to receive real-time events. Principal key Webhook URLs must be public HTTPS endpoints; the signing secret (used to verify X-Mandate-Signature) is returned once on create. See the Webhooks guide for payloads and signature verification.

Register a webhook

POST /api/v1/webhooks

Creates a webhook subscription and returns its signing secret (shown only once). Principal key

Body paramTypeReqNotes
urlstringyesPublic HTTPS endpoint (≤2048 chars).
event_typesstring[]yes≥1 of gate.fired, kya.zone.red, kya.zone.critical, session.terminate, authorization.decline, trust.promotion, step_up.created, *.
descriptionstringno≤255 chars.
curl -X POST https://api.mandatelabs.ai/api/v1/webhooks \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/mandate-ai",
    "event_types": ["gate.fired", "authorization.decline", "trust.promotion"],
    "description": "Production alerting webhook"
  }'
{
  "webhook": {
    "id": "wh_…",
    "url": "https://your-app.com/webhooks/mandate-ai",
    "event_types": ["gate.fired", "authorization.decline", "trust.promotion"],
    "active": true,
    "consecutive_failures": 0,
    "created_at": "2026-06-27T18:16:10Z"
  },
  "signing_secret": "whsec_…"
}

List webhooks

GET /api/v1/webhooks

Lists all webhooks for the authenticated Principal (paginated). Principal key

curl https://api.mandatelabs.ai/api/v1/webhooks \
  -H "X-API-Key: mdt_live_…"
{
  "items": [ { "id": "wh_…", "url": "https://your-app.com/webhooks/mandate-ai", "active": true, "last_status_code": 200 } ],
  "next_cursor": null
}

Get a webhook

GET /api/v1/webhooks/{webhook_id}

Fetches a single webhook by ID. Principal key

curl https://api.mandatelabs.ai/api/v1/webhooks/wh_… \
  -H "X-API-Key: mdt_live_…"
{
  "id": "wh_…",
  "url": "https://your-app.com/webhooks/mandate-ai",
  "event_types": ["gate.fired", "authorization.decline"],
  "active": true,
  "last_delivery_at": "2026-06-27T18:15:00Z",
  "last_status_code": 200,
  "consecutive_failures": 0
}

Update a webhook

PATCH /api/v1/webhooks/{webhook_id}

Updates a webhook's URL, events, active flag, or description. Principal key Re-enabling (active: true) resets the failure counter.

Body (all optional): url, event_types, active, description.

curl -X PATCH https://api.mandatelabs.ai/api/v1/webhooks/wh_… \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -d '{ "event_types": ["*"], "active": true }'
{
  "id": "wh_…",
  "url": "https://your-app.com/webhooks/mandate-ai",
  "event_types": ["*"],
  "active": true,
  "consecutive_failures": 0
}

Send a test event

POST /api/v1/webhooks/{webhook_id}/test

Dispatches a realistic sample payload to the webhook so you can verify your handler. Principal key The payload includes "test": true. The webhook must be active.

Query: event_type (defaults to gate.fired).

curl -X POST "https://api.mandatelabs.ai/api/v1/webhooks/wh_…/test?event_type=authorization.decline" \
  -H "X-API-Key: mdt_live_…"
{
  "status": "sent",
  "event_type": "authorization.decline",
  "message": "Test 'authorization.decline' event dispatched to https://your-app.com/webhooks/mandate-ai."
}

Delete a webhook

DELETE /api/v1/webhooks/{webhook_id}

Permanently deletes a webhook. Principal key Returns 204 No Content.

curl -X DELETE https://api.mandatelabs.ai/api/v1/webhooks/wh_… \
  -H "X-API-Key: mdt_live_…"
# → 204 No Content

List webhook events

GET /api/v1/webhooks/events

Returns every available event type with a description and a sample payload — use it to build and test your handler. No auth required

curl https://api.mandatelabs.ai/api/v1/webhooks/events
{
  "event_types": [
    {
      "type": "gate.fired",
      "description": "Intent Anomaly Gate triggered — suspicious behavioral shift detected in agent session.",
      "sample_payload": { "agent_id": "agent_sample_01", "decision": "STEP_UP", "anomaly_score": 0.62 }
    }
  ],
  "wildcard": "Use '*' when registering to receive all event types."
}

Thresholds

Tune your own gate, risk, and trust-promotion thresholds. Principal key Reads return the fully-resolved values (your overrides merged over the platform defaults). Updates are validated for logical consistency (e.g. trust zones must stay ordered green > amber > red).

Get resolved thresholds

GET /api/v1/thresholds

Returns effective thresholds along with which fields you've customized vs. defaults. Principal key

curl https://api.mandatelabs.ai/api/v1/thresholds \
  -H "X-API-Key: mdt_live_…"
{
  "thresholds": { "authorize_step_up_threshold": 0.6, "cts_green_threshold": 0.8, "risk_score_hard_decline": 0.85 },
  "overrides": { "authorize_step_up_threshold": 0.6 },
  "platform_defaults": { "authorize_step_up_threshold": 0.5, "cts_green_threshold": 0.8 }
}

Update thresholds

PUT /api/v1/thresholds

Sets issuer-specific overrides — include only the fields you want to change; set a field to null to revert it to default. Principal key Validates cross-field consistency.

Body: any subset of threshold fields, e.g. authorize_step_up_threshold, cts_green_threshold, risk_score_hard_decline, verified_min_successful_txns.

curl -X PUT https://api.mandatelabs.ai/api/v1/thresholds \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -d '{ "authorize_step_up_threshold": 0.6, "risk_score_hard_decline": 0.9 }'
{
  "status": "updated",
  "fields_changed": ["authorize_step_up_threshold", "risk_score_hard_decline"],
  "effective_thresholds": { "authorize_step_up_threshold": 0.6, "risk_score_hard_decline": 0.9 }
}

Reset thresholds

DELETE /api/v1/thresholds

Deletes all your overrides, reverting every threshold to the platform default. Principal key

curl -X DELETE https://api.mandatelabs.ai/api/v1/thresholds \
  -H "X-API-Key: mdt_live_…"
{
  "status": "reset",
  "message": "All thresholds reverted to platform defaults"
}

Next steps