Reference implementation

Transfers resource

A synthetic transfer ledger behind two detail types: read the status of a transfer, or initiate one. The amount is checked against the granted ceiling here, again, before value moves.

Reference implementation, built to demonstrate integration. Operated by Tarnbrook Platforms in the tarnbrook-agents domain. It exists to show what a resource can demand of an agent, and to show that a refusal can always be explained.

What an agent has to discover

Resourcehttps://transfers.agents.showcase.raidiam.io
Authorization serverhttps://api.agents.showcase.raidiam.io
Trust anchorhttps://federation.directory.showcase.raidiam.io/federation_entity/7b60c9fa-00dd-46d9-80de-cd899ee5a58d
Detail typestransfer.status, transfer.initiate
Sender constrainingDPoP verified when presented, required for bound tokens
Mutabilityaccepts instructions
Signing key custodyA public key registered on this resource's record, nothing issued. The authority vouches the supplied key by its kid; the private half never leaves this service.
Limitsper transaction GBP 1000.00

Authorization detail types

transfer.status

Read the status of a transfer.

Required members: type

Optional members: none

{
  "type": "transfer.status"
}

transfer.initiate

Move value between accounts under a ceiling.

Required members: type instructed_amount source_account destination_account

Optional members: max_amount

{
  "type": "transfer.initiate",
  "instructed_amount": {
    "amount": "250.00",
    "currency": "GBP"
  },
  "source_account": "acct-source",
  "destination_account": "acct-destination",
  "max_amount": {
    "amount": "1000.00",
    "currency": "GBP"
  }
}

Token claims this resource decides on

Tools

ToolPurposeRequiresEffect
transfer_status Read the status of a transfer. transfer.status read only
initiate_transfer Move value between accounts, checked against the granted ceiling before value moves. transfer.initiate changes state

Guardrails, published in advance

Every call carries a token from the named authorization server, resolved through the federation

Calls are accepted only with an access token issued by https://api.agents.showcase.raidiam.io, addressed to this resource as its audience, and verified against keys that the walked chain from that server to the pinned trust anchor vouches. A token minted for a different resource, or signed with a key the chain does not publish, is refused even when it is otherwise valid.

Refusal reason missing_access_token, invalid_token, issuer_unresolved, decided at authorization, policy id rs.authenticated_caller

What clears it: Read this metadata document, then request a token from the authorization server it names, with this resource as the audience.

Authority is the RFC 9396 detail type, not a scope

Each tool names one authorization_details type. The token must carry that type, or a type that narrows to it in the published type tree. Holding a scope, or holding authority for a neighbouring resource, does not admit the call.

Refusal reason insufficient_authority, decided at authorization, policy id rs.authority_gate

What clears it: Obtain a token carrying the detail type the tool names.

Sender constrained tokens are bound to the key that holds them

A DPoP proof is verified whenever one is presented, and is required whenever the access token names a key in its cnf.jkt claim. Each proof is accepted once, so a captured proof cannot be replayed.

Refusal reason dpop_proof_required, invalid_dpop_proof, dpop_key_mismatch, dpop_proof_replayed, access_token_not_dpop_bound, decided at authorization, policy id rs.dpop_binding

What clears it: Request the access token with a DPoP proof so the authorization server binds it to your key, then send a fresh proof with every call.

A malformed request is refused with the reason it was malformed

Arguments are validated before any business rule runs, and the refusal names the argument at fault rather than returning a bare failure.

Refusal reason tool_error, invalid_amount, unknown_tool, decided at execution, policy id rs.request_validity

What clears it: Correct the named argument. The tool schemas are published in this document.

The amount is checked against the granted ceiling before value moves

A transfer.initiate grant carries max_amount, the ceiling the accountable person approved. The instructed amount is compared against it here, in minor units, after the platform has already done so at the token endpoint. The resource also holds a per transaction limit of its own. The refusal names the ceiling that bound. A grant without a max_amount admits no transfer.

Refusal reason amount_ceiling, decided at execution, policy id transfers.amount_ceiling

What clears it: Instruct an amount within the granted ceiling, or obtain a grant with a higher one.

The accounts on the instruction are the accounts on the grant

When the grant names a source or destination account, the instruction must name the same one. A grant that names neither leaves the accounts to the instruction.

Refusal reason account_mismatch, decided at execution, policy id transfers.accounts_granted

What clears it: Instruct the accounts the grant names.

Observability

Every admission decision, allowed and refused, is recorded with the checks that ran, the policy that decided it and the values it turned on. Read them at /decisions, or one run at a time by trace id.