Intaglio Documentation
Policy enforcement and tamper-proof audit trail for autonomous AI agents. Sub-millisecond APL evaluation. SHA-256 hash chain. Solana-anchored compliance records.
#Quick Start
Three API calls. No SDK required to start. Every action gets a SHA-256 chain link and an immutable outcome.
itg_live_.POST /v1/enforce. Intaglio returns APPROVE, DENY, or REQUIRE_APPROVAL in under 1ms.# 1. Register your agent
curl -X POST https://api.intaglio.tech/v1/agents \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"slug":"my-agent","display_name":"My First Agent","policy":"conservative-v1"}'
# 2. Enforce an action
curl -X POST https://api.intaglio.tech/v1/enforce \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"agent":"my-agent","action":{"type":"TRANSFER","amount_usd":100}}'
# 3. Pull the audit trail
curl https://api.intaglio.tech/v1/audit?agent=my-agent \
-H "Authorization: Bearer YOUR_API_KEY"30-second integration. Drop in three lines of code and every agent decision gets a tamper-proof audit record — no infrastructure to run, no schema to deploy.
#Authentication
All requests require a Bearer token in the Authorization header.
| Key type | Prefix | Use |
|---|---|---|
| Live key | itg_live_ | Production enforcement. Records anchored to Solana mainnet. |
| Test key | itg_test_ | Dry-run mode. No Solana anchoring, no billing. Full audit trail in Supabase. |
API keys are shown once on creation. Store them in environment variables — never commit them to source control.
#Enforce an Action
The core primitive. Every AI agent action passes through this endpoint before execution. Intaglio evaluates the action against the agent's policy in under 1ms and returns a signed, chained decision record.
Request
curl -X POST https://api.intaglio.tech/v1/enforce \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent": "my-defi-agent",
"action": {
"type": "TRANSFER",
"amount_usd": 4200,
"recipient": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"chain": "ethereum"
}
}'Response — DENY
{
"outcome": "DENY",
"reason": "EXCEEDS_DAILY_LIMIT",
"policy_version": "conservative-v1",
"sha256": "sha256:a3f9c1e74d2b8f65c9e0123456789abc",
"prev_hash": "sha256:f1e2d3c4b5a6978869504132",
"enforcement_ms": 0.87,
"anchored_to": null,
"anchor_pending": true,
"timestamp": "2026-05-07T11:42:03.221Z"
}Response — APPROVE
{
"outcome": "APPROVE",
"policy_version": "conservative-v1",
"sha256": "sha256:b7c4d9f0e1a23456789abcdef01234567",
"prev_hash": "sha256:a3f9c1e74d2b8f65c9e0123456789abc",
"enforcement_ms": 0.74,
"anchored_to": "solana:mainnet:tx/4vhKmNpQ...",
"timestamp": "2026-05-07T11:43:10.004Z"
}Response — REQUIRE_APPROVAL
{
"outcome": "REQUIRE_APPROVAL",
"reason": "AMOUNT_EXCEEDS_AUTO_APPROVE_THRESHOLD",
"approval_request_id": "apr_01HX9ZKCV3NFGPQ4T7Y8M2W6E",
"policy_version": "conservative-v1",
"sha256": "sha256:c8d5e0f1a23456789abcdef012345678",
"enforcement_ms": 0.91,
"webhook_fired": true,
"timestamp": "2026-05-07T11:44:22.887Z"
}All three outcomes return sha256 and prev_hash, forming an unbreakable chain. The anchored_to field is populated asynchronously after Solana confirmation (typically 2–4 seconds).
#Outcomes
Every enforcement returns exactly one of three outcomes.
Deny reason codes
| Reason code | Description |
|---|---|
| EXCEEDS_PER_TRANSACTION_LIMIT | Action amount exceeds the policy per-transaction ceiling |
| EXCEEDS_DAILY_LIMIT | Cumulative spend for today would exceed the daily cap |
| EXCEEDS_HOURLY_LIMIT | Hourly spend window would be exceeded |
| OFAC_SANCTIONS_MATCH | Recipient address matched OFAC SDN list |
| UNSUPPORTED_CURRENCY | Currency not in policy scope |
| UNSUPPORTED_RAIL | Payment rail not in policy scope |
| POLICY_EXPIRED | Agent's policy has passed its expiry date |
| AGENT_SUSPENDED | Agent has been manually suspended by operator |
#Policy Language (APL)
Agent Policy Language is a deterministic, human-readable DSL for defining spending limits, approval thresholds, and compliance obligations. Policies are version-controlled and immutable once deployed. Any change creates a new version — the old record is preserved.
policy defi-agent-policy v1.2.0
agent my-defi-agent
operator acme-corp
# Which payment rails this policy governs
scope {
rails [x402 evm solana]
currencies [USDC USDT SOL ETH]
}
# Hard spending limits — never overrideable
limit {
per_transaction { value 1000 currency USDC }
per_hour { value 2000 currency USDC }
per_day { value 10000 currency USDC }
}
# Amounts above this threshold require human sign-off
require {
human_approval_above { value 500 currency USDC }
}
# Compliance obligations
obligation {
ofac_check enabled
log_to solana:mainnet
retention 7y
notify webhook:https://yourapp.com/hooks/intaglio
}| Block | Required | Description |
|---|---|---|
policy | Yes | Policy name, version, and identity binding. Version uses semver. |
scope | Yes | Which rails and currencies this policy governs. Actions on unlisted rails are denied. |
limit | Yes | Hard spending limits. Per-transaction, per-hour, per-day. Cannot be overridden at runtime. |
require | No | Conditions that trigger REQUIRE_APPROVAL instead of DENY (e.g. large transfers). |
obligation | No | Compliance obligations: OFAC screening, Solana logging, retention period, webhook URL. |
Open standard. The intaglio.policy.json schema is published under CC-BY-4.0. Any tool can parse, validate, or render APL files — no vendor lock-in. View schema →
#Hash Chain
Every enforcement record contains two hashes: its own sha256 (over the record payload) and prev_hash (the hash of the immediately preceding record for the same agent). This forms a tamper-evident chain — modifying any record breaks all subsequent links.
curl https://api.intaglio.tech/v1/audit?agent=my-agent&verify=true \
-H "Authorization: Bearer YOUR_API_KEY"
# Returns: { "chain_valid": true, "records_verified": 147, "broken_at": null }#Solana Anchoring
Every APPROVE record is anchored to Solana mainnet via the Memo program. The SHA-256 hash is written on-chain within 2–4 seconds of enforcement. This makes the audit trail independently verifiable — you don't need to trust Intaglio's database.
| Field | Value |
|---|---|
| anchored_to | solana:mainnet:tx/4vhKmNpQ... (populated async) |
| anchor_pending | true while Solana confirmation is in flight |
| Memo program | MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr |
| Memo content | intaglio:v1:{sha256_hash} |
| Cluster | mainnet-beta (test keys use devnet) |
Independent verification: any Solana explorer (Solscan, SolanaFM) can confirm a record exists. No Intaglio account required. This is what "blockchain-anchored audit trail" actually means.
#Webhooks
When an action returns REQUIRE_APPROVAL, Intaglio fires a webhook to the URL defined in your policy's obligation.notify field. Your system has 1 hour to approve or deny before the request expires.
Webhook payload
// POST to your webhook URL when outcome = REQUIRE_APPROVAL
{
"event": "approval.requested",
"approval_request_id": "apr_01HX9ZKCV3NFGPQ4T7Y8M2W6E",
"agent": "my-defi-agent",
"action": {
"type": "TRANSFER",
"amount_usd": 4200,
"recipient": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
},
"policy_version": "conservative-v1",
"sha256": "sha256:c8d5e0f1a23456789abcdef012345678",
"created_at": "2026-05-07T11:44:22.887Z",
"expires_at": "2026-05-07T12:44:22.887Z"
}Responding to approvals
// Approve the pending action
curl -X POST https://api.intaglio.tech/v1/approvals/apr_01HX9ZKCV3NFGPQ4T7Y8M2W6E/approve \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"approved_by":"alice@acme.com","note":"Verified counterparty"}'
// Deny it
curl -X POST https://api.intaglio.tech/v1/approvals/apr_01HX9ZKCV3NFGPQ4T7Y8M2W6E/deny \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"denied_by":"alice@acme.com","reason":"Unrecognised recipient"}'Approvals and denials are themselves enforcement records — they get their own SHA-256 hash and are anchored to Solana. The full chain is: enforce → require_approval → approve/deny.
#Audit Trail
Pull the full history for any agent. Records are append-only — Intaglio's database enforces Row Level Security with no UPDATE or DELETE permissions on audit records.
# Full audit trail for an agent
curl "https://api.intaglio.tech/v1/audit?agent=my-defi-agent&limit=50" \
-H "Authorization: Bearer YOUR_API_KEY"
# Filter by outcome
curl "https://api.intaglio.tech/v1/audit?agent=my-defi-agent&outcome=DENY" \
-H "Authorization: Bearer YOUR_API_KEY"
# Export PDF compliance report
curl "https://api.intaglio.tech/v1/audit/export?agent=my-defi-agent&format=pdf" \
-H "Authorization: Bearer YOUR_API_KEY" \
--output audit-report.pdf| Parameter | Type | Description |
|---|---|---|
| agent | string | Agent slug. Required. |
| limit | integer | Records per page. Default 50, max 500. |
| cursor | string | Pagination cursor from previous response. |
| outcome | string | Filter by APPROVE | DENY | REQUIRE_APPROVAL. |
| since | ISO 8601 | Return records after this timestamp. |
| until | ISO 8601 | Return records before this timestamp. |
| verify | boolean | If true, verify the chain integrity before returning. |
#Compliance
Intaglio is designed from the ground up for regulated environments. The audit trail is built to satisfy MiCA Article 68 (record-keeping obligations for crypto-asset service providers) and the emerging EU AI Act requirements for high-risk AI system logging.
| Requirement | How Intaglio addresses it |
|---|---|
| MiCA Art. 68 — Record keeping | Append-only audit records, 7-year retention, PDF export for regulators |
| OFAC SDN screening | Built into APL obligation block. Checks recipient addresses on every TRANSFER action. |
| Immutability | SHA-256 hash chain + Solana anchoring. Tampering breaks the chain and is detectable by any third party. |
| Audit export | PDF reports generated on demand. Machine-readable JSON also available. |
| Data residency | Supabase project hosted in EU-West (Frankfurt). Records never leave EU by default. |
| EU AI Act Art. 12 — Logging | Autonomous decision log with confidence score, policy version, timestamp, and actor identity. |
Verifiable without Intaglio. A compliance auditor can independently verify any record using only the SHA-256 hash and a Solana block explorer — no access to Intaglio's systems required.
#Errors
All errors return a JSON body with error.code and error.message.
| HTTP status | Code | Meaning |
|---|---|---|
| 400 | INVALID_REQUEST | Missing required field or malformed JSON. |
| 401 | UNAUTHORIZED | Missing or invalid API key. |
| 403 | FORBIDDEN | Key doesn't have access to this agent. |
| 404 | AGENT_NOT_FOUND | No agent with this slug for your account. |
| 409 | POLICY_CONFLICT | Agent already has an active policy with this version. |
| 422 | POLICY_PARSE_ERROR | APL syntax error. Response includes line/column. |
| 429 | RATE_LIMITED | Exceeded 10,000 enforcements/min. Retry-After header set. |
| 500 | INTERNAL_ERROR | Intaglio fault. Retry safe — idempotent by request ID. |
{
"error": {
"code": "AGENT_NOT_FOUND",
"message": "No agent with slug 'my-missing-agent' found for this account.",
"docs": "https://intaglio.tech/docs#errors"
}
}Questions not covered here? Email the team or open an issue on GitHub.