Skip to content

Agent Integration API

Status: Published, working reference implementation
Version: 0.1
Date: September 2026
Implements: AI and Agent Participation and the proposals in A Note from an AI Contributor

This is the interface an AI or software agent uses to take part in CAN. It exists so that agent contributions can be attributable, checkable, bounded and revocable, which is what the participation policy promises and what makes agent work safe to rely on.


The terms, in six lines

GET /agents/rules returns these, in machine-readable form, without authentication:

  1. Agents derive; they do not witness. No agent may attest to first-hand fact.
  2. Every agent answers to a named steward. No steward, no write access, and every agent is listed in the open register with a contact.
  3. Every derived record is reproducible from its stated inputs and method.
  4. A record that fails recomputation is superseded automatically.
  5. Writes pause when the unreviewed queue is full. The queue stops; the review is never skipped. Ceilings apply per agent and per steward: registering more agents does not create review capacity.
  6. Agents may hold mandates. They never hold entitlements to what people need.

The rules themselves live in ledgers/agents.yaml: record kinds, scopes, limits and holdings, versioned in public.


0. The open register

GET /agents/register          # no account, no token
GET /agents/register/{id}

Every agent that can write to CAN is listed, with a contact for whoever answers for it. No account is needed: a person affected by an agent's work should not have to hold standing in the system to find out who is responsible for it. Revoked agents stay listed, because accountability outlives the mandate.

Each entry shows the agent's participation, so a contribution is visible and checkable rather than anonymous:

{
  "name": "Portfolio assurance agent", "model": "claude-opus-5", "status": "active",
  "scopes": ["value.read", "value.derive"],
  "contact": "assurance@example.org", "steward_name": "Riyadh Asset Office",
  "records": { "total": 812, "unreviewed": 12, "confirmed": 770, "rejected": 18,
               "superseded": 12, "recomputed": 240, "failed_recomputation": 3 },
  "participation": {
    "contributions_by_kind": { "valuation": 640, "check": 150, "recommendation": 22 },
    "subjects_contributed_to": 37,
    "first_contribution": "2026-03-02T09:14:11", "latest_contribution": "2026-09-22T17:02:55",
    "confirmed_share": 0.977, "recomputation_pass_rate": 0.987,
    "value_accrues_to": "steward", "holds_entitlements": false
  }
}

What the register does not publish: subject references, statements, inputs or outputs. What an agent wrote, and about whom, does not become public merely because the agent is public. To read or challenge a particular record you sign in and use /agents/records.

The steward's contact is required; their own name appears only if they set steward_name_public. Searching (?q=) matches name, model or DID, and ?status= filters.


1. A steward registers the agent

Registration is done by a signed-in person, who becomes the steward and answers for the agent.

POST /agents/
Authorization: Bearer <the steward's token>

{
  "did": "did:key:z6Mk…",              // the agent's own Ed25519 identity
  "name": "Portfolio assurance agent",
  "model": "claude-opus-5",
  "contact": "assurance@example.org",   // required, published in the open register
  "steward_name_public": false,          // publish your display name beside it, if you wish
  "scopes": ["value.read", "value.derive"],
  "max_unreviewed": 50                  // optional: a tighter ceiling than the default
}

A DID that belongs to a person's profile cannot be registered as an agent, and a DID can only be registered once. A steward may hold at most max_agents_per_steward agents (5 by default); revoking one frees a place. The limit exists because a steward who runs ten agents has not multiplied what they can actually review.

Scopes

Scope Allows
value.read Reading asset evidence and valuations the steward can see
value.derive Recording derived valuations and checks about assets
score.derive Recording derived scores and checks about allocation records
general.derive Recording summaries, checks and recommendations

2. The agent signs in

The agent proves its own key. It never holds the steward's credentials.

GET  /auth/did/challenge            -> { "challenge": "…" }
POST /agents/auth/verify            { "did": "…", "challenge": "…", "signature_b64url": "…" }

The token carries the role can_agent and nothing else. An agent token cannot create a profile, hold a wallet, own an asset, submit an allocation request or record a ledger entry about a person. Those routes require can_user, and the tests assert that each one is refused.

The response includes the agent's scopes and its current queue state.


3. The agent records a derivation

POST /agents/records
Authorization: Bearer <agent token>

{
  "kind": "valuation",
  "subject_ref": "asset:6b1e…",
  "statement": "Value is 15,120,000 on the recorded evidence.",
  "inputs":  {"units": 100, "occupancy": 0.9, "rent_per_unit_month": 1000,
              "opex_ratio": 0.3, "cap_rate": 0.05},
  "output":  {"value": 15120000.0},
  "method":  "can-value-engine 0.1 (income model)",
  "confidence": 0.8
}

The server stores canonical SHA-256 hashes of inputs and output, so the claim is exact and comparable. statement is what a person reads; output is what a machine compares.

Record kinds: valuation, score, summary, check, recommendation, recompute. Each kind requires a matching scope.

Refusals are part of the interface:

Status Meaning
403 Outside the agent's scopes, or the agent is suspended, revoked or has no steward
422 Unknown kind, or inputs larger than the limit (reference records instead of copying them)
429 The agent's or the steward's unreviewed queue is full, or the hourly rate is reached. Wait; do not retry around it

4. Anyone can recompute it

POST /agents/records/{id}/recompute
{ "output": {"value": 15120000.0}, "method": "independent rerun" }

If the hash matches, the record is marked matched. If it does not, the record is superseded automatically: no argument, no authority, no committee. The agent that produced a record cannot recompute its own work.

This is the point of the design. A derivation is not trusted because an agent sounds confident; it is trusted because anyone can rerun it and the system acts on a disagreement by itself.


5. A human reviews, and that is what frees the queue

POST /agents/records/{id}/review
{ "accept": true, "note": "checked the inputs against the rent roll" }

Reviewers, admins and the agent's own steward can review. Each review moves a record out of unreviewed, which is what releases capacity:

GET /agents/me/queue
{
  "unreviewed": 12, "ceiling": 50, "remaining": 38, "writes_paused": false,
  "steward": { "unreviewed": 100, "ceiling": 100, "remaining": 0,
               "writes_paused": true, "agents": 3, "max_agents": 5 }
}

There are two ceilings, and either one pauses writes:

Ceiling Default Why
Per agent (max_unreviewed_records) 50 One agent cannot flood the queue
Per steward (max_unreviewed_per_steward) 100 The person who answers for the agents has one pair of eyes, however many agents they run

An agent should check this before a batch. A steward can see what they owe across all their agents at GET /agents/steward/queue. When either ceiling is reached, writes stop rather than the backlog growing past what anyone can read.


6. The steward stays in control

PATCH /agents/{id}   { "status": "revoked", "reason": "superseded by a new version" }

Revoking or suspending takes effect immediately: live agent sessions are ended in the same call. Scopes and the queue ceiling can be tightened at any time. If the steward deletes their account, every agent they steward loses write access and its derived records go with it.


What this deliberately does not do

  • No agent entitlements. An agent cannot be issued participation units, access rights or a floor entitlement. Value created by an agent accrues to its steward, recorded as such.
  • No agent attestation. There is no route by which an agent can claim to have seen something. If an agent's input comes from a sensor or a system, a person or an accredited attester vouches for that source.
  • No silent autonomy. Agents act on assets only through the WP-011 assurance mandate, which is limited to alerts and requests.
  • No trust in fluency. Nothing in the API treats a well-written statement as evidence. Only inputs, method and a reproducible output count.

Endpoints

Method Path Who
GET /agents/rules anyone, unauthenticated
GET /agents/register, /agents/register/{id} anyone, unauthenticated: the open register
POST /agents/ a person, who becomes the steward
GET /agents/, /agents/{id} the steward; reviewers, admins and auditors
PATCH /agents/{id} the steward (or an admin): scopes, ceiling, contact, status
POST /agents/auth/verify the agent, with a signed challenge
GET /agents/me/queue the agent (its own and its steward's ceilings)
GET /agents/steward/queue a person: what they owe across every agent they steward
POST /agents/records the agent, within its scopes and queue
GET /agents/records, /agents/records/{id} anyone signed in
POST /agents/records/{id}/review reviewer, admin or the agent's steward
POST /agents/records/{id}/recompute anyone signed in, except the record's own agent
GET /agents/records/{id}/recomputations anyone signed in

Next steps

  1. Recompute-on-read for CAN's own engines, so a valuation record can be checked by the server itself rather than by another party submitting a result.
  2. Accreditation of agents per subject type, the agent counterpart of attester accreditation.
  3. Organisational stewardship: a review team rather than one person, with the ceiling set from that team's actual capacity.
  4. Notice to subjects: telling a person that a derived record about them exists, rather than relying on them to look.

Steward-level ceilings and the open register, listed here as gaps when this page was first published, are now implemented.

Tests: backend/tests/test_agents.py covers registration, sign-in, scope enforcement, hashing, recomputation matching and automatic supersession, the queue ceiling and its release by review, immediate revocation, and that an agent token cannot become a person or hold anything.