Technical guide

How to enforce wallet-level policy under MiCA

A step-by-step walkthrough of turning a written spending/destination policy into a control an AI agent's wallet actions physically cannot bypass, using APL (Agent Policy Language) and Intaglio's real enforcement proxy API.

1. Declare the policy in APL

Limits, required checks, and hard denials are declared once, in a version-controlled policy file — not scattered across application code:

policy treasury-agent v1.0.0
agent  treasury-bot-01
operator acme-gmbh

scope {
  rails      [x402 solana-pay]
  currencies [USDC USDT]
}

limit {
  per_transaction { value 10000 currency USDC }
  per_day         { value 50000 currency USDC }
}

require {
  human_approval_above { value 5000  currency USDC }
  deny_if_sanctioned   true
  deny_if_destination  NOT_IN whitelist.json
}

obligation {
  log_to    solana:devnet
  retention 7y
}

See the APL spec for the full block reference (scope, limit, require, deny, obligation, approval).

2. Route the agent's actions through the enforcement proxy

Evaluate every action before it executes by calling the proxy directly:

curl -X POST http://localhost:3001/v1/actions \
  -H "Authorization: Bearer <agent-secret>" \
  -H "Content-Type: application/json" \
  -d '{
    "action": {
      "rail": "x402",
      "amount": { "value": 500, "currency": "USD" },
      "timestamp": "2026-07-06T00:00:00Z"
    }
  }'

Or evaluate-and-forward in one call, so the request only reaches the upstream target if the policy approves it:

curl -X POST http://localhost:3001/v1/x402/forward \
  -H "Authorization: Bearer <agent-secret>" \
  -H "Content-Type: application/json" \
  -d '{
    "action": { "rail": "x402", "amount": { "value": 50, "currency": "USD" } },
    "x402_request": {
      "target": "external-llm-service",
      "prompt": "Execute the wire transfer."
    }
  }'

3. Wrap it once with the TypeScript SDK

The real @intaglio/sdk client wraps the same endpoints so existing agent code doesn't need to hand-roll the HTTP calls:

import { IntaglioClient } from "@intaglio/sdk";

const client = new IntaglioClient({
  baseUrl: process.env.INTA_PROXY_URL ?? "http://localhost:3001",
  agentToken: process.env.INTA_AGENT_SECRET!,
});

const result = await client.enforce({
  type: "payment",
  amount: 500,
  currency: "USDC",
  destination: "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
});

if (result.decision.outcome === "DENY") {
  throw new Error(`Blocked by policy: ${result.decision.reason ?? "no reason given"}`);
}
if (result.decision.outcome === "REQUIRE_APPROVAL") {
  await client.getApproval(result.approval_id!); // poll until resolved
}
// outcome === "APPROVE" -> proceed with the real transfer

4. Every decision is auditable, whatever the outcome

Each evaluation returns a record with a SHA-256 self_hash and a prev_record_hash pointer, so the full decision history for an agent forms a tamper-evident chain that can be anchored to Solana and exported for a regulator or auditor.

[VERIFY] Whether a hash-chained record satisfies a specific national regulator's record-retention format requirement under MiCA Art. 68/69 has not been confirmed against jurisdiction-specific guidance in this pass.

Start enforcing policy today

MiCA CASP enforcement is active as of July 1, 2026.

Open dashboardRead the APL spec