# For agent and commerce platforms · Integra

> Build once for many sellers and agents: the agreement rides the protocols your agents already speak.

URL: https://integraledger.com/for-platforms

For agent and commerce platforms

## Build once, for many sellers and many agents.

The agreement rides beside the protocols your agents already speak, and the same check runs before every payment, whatever the agent is built with. [Source: lcp docs: agentic checkouts⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/guides/checkouts.md) · [Source: @integraledger/terms README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms/README.md)

**Sources (2)**

[lcp docs: agentic checkouts⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/guides/checkouts.md) · [@integraledger/terms README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms/README.md)

Carried in the protocols

### The reference travels in the protocol’s own field.

For each protocol, where the ATR hash travels — the unique fingerprint of the agreement’s Agentic Transaction Record (ATR). A2A and MCP deliver it; the payment carries it. [Source: lcp docs: agentic checkouts⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/guides/checkouts.md) · [Source: LCP §10⁠ (opens in a new tab)](https://github.com/legal-context-protocol/legal-context-protocol/blob/c8df26d/spec/legal-context-protocol-v1.md#10-mcp-as-delivery-mechanism)

| Protocol | Where the ATR hash rides |
| --- | --- |
| [x402](https://integraledger.com/protocols/x402) | The seller’s 402 challenge carries the ATR hash and a link to the ATR; the payment carries the ATR hash in the rail’s own field. |
| [MPP](https://integraledger.com/protocols/mpp) | The MPP challenge itself carries the ATR hash: its id is derived from it, so whatever the payer signs over the challenge commits to it. |
| [ACP](https://integraledger.com/protocols/acp) | The checkout session’s id is the ATR hash, with the link to the ATR in the session’s metadata. |
| [UCP](https://integraledger.com/protocols/ucp) | A `legal_context` link in the checkout carries the ATR hash, before the business signs the checkout. |
| [AP2](https://integraledger.com/protocols/ap2) | The merchant-signed checkout carries the ATR hash, and the buyer’s Checkout Mandate commits to that checkout. |
| [ACK](https://integraledger.com/protocols/ack) | The seller-signed Payment Request takes the ATR hash as its id. |
| [Visa TAP](https://integraledger.com/protocols/visa-tap) | The agent’s payer signature covers a field holding the ATR hash. |
| [Verifiable Intent](https://integraledger.com/protocols/mastercard-vi) | A Verifiable Intent mandate signs the hash of a checkout that carries the ATR hash. |
| [A2A](https://integraledger.com/protocols/a2a) | A2A delivers the ATR hash and a link to the ATR with the task; the payment for the task carries the ATR hash in its own pairing. |
| [MCP](https://integraledger.com/protocols/mcp) | MCP delivers legal context to agents as tools, whatever protocol the payment uses. |

**Sources (2)**

[lcp docs: agentic checkouts⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/guides/checkouts.md) · [LCP §10⁠ (opens in a new tab)](https://github.com/legal-context-protocol/legal-context-protocol/blob/c8df26d/spec/legal-context-protocol-v1.md#10-mcp-as-delivery-mechanism)

#### The standard

For each protocol, the place the package puts the ATR hash, and how many of its pairings have the buyer’s signature cover it. A2A and MCP deliver it; the payment carries it. [Source: lcp docs: agentic checkouts⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/guides/checkouts.md) · [Source: LCP §10⁠ (opens in a new tab)](https://github.com/legal-context-protocol/legal-context-protocol/blob/c8df26d/spec/legal-context-protocol-v1.md#10-mcp-as-delivery-mechanism)

Each count is read from the package’s registry, `BINDINGS`, when the site is built. [Source: lcp docs: pairings reference⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/reference/pairings.md)

| Protocol | Pairings | Buyer signs it | Public proof |
| --- | --- | --- | --- |
| x402 | 29 | 23 | 23 |
| MPP | 26 | 13 | 18 |
| ACP | 2 | 0 | 0 |
| UCP | 4 | 2 | 0 |
| AP2 | 1 | 1 | 0 |
| ACK | 1 | 0 | 0 |
| Visa TAP | 1 | 1 | 0 |
| Verifiable Intent | 2 | 2 | 0 |
| A2A | Delivery |  |  |
| MCP | Delivery |  |  |

#### The data

Read from the published packages when the site was built; nothing here is typed by hand.

On x402, the seller’s challenge: the ATR hash and the ATR’s link, in `extensions.legalContext`

```
{
  "x402Version": 2,
  "resource": {
    "url": "https://api.seller.example/v1/market-data"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:84532",
      "amount": "40000000",
      "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
      "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
      "maxTimeoutSeconds": 60,
      "extra": {
        "name": "USDC",
        "version": "2"
      }
    }
  ],
  "extensions": {
    "legalContext": {
      "info": {
        "type": "sha256",
        "value": "0x8448dc1b716a5103287cb8f35e36b614ffd91e630ab8b7911833c54748ad5ca6",
        "legalContextUrl": "https://atr.seller.example/0x8448dc1b716a5103287cb8f35e36b614ffd91e630ab8b7911833c54748ad5ca6"
      },
      "schema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "type": {
            "const": "sha256"
          },
          "value": {
            "type": "string",
            "pattern": "^0x[0-9a-f]{64}$"
          },
          "legalContextUrl": {
            "type": "string",
            "pattern": "^https://"
          }
        },
        "required": [
          "type",
          "value",
          "legalContextUrl"
        ]
      }
    }
  }
}
```

#### The code

Compiled against the published packages when the site is built.

Count the pairings yourself, from the same registry

src/snippets/registry.ts

```
// The package's registry holds every pairing with its pattern record: here, the pairings whose fingerprint anyone can
// read back from the settled transaction alone.
import { BINDINGS } from '@integraledger/lcp';

export const recoverable = BINDINGS.filter((b) => b.pattern.zeroPartyRecoverable).map((b) => b.id);
```

One buyer gate

### One check before every payment, in three forms.

Before the agent’s wallet signs anything, the gate fetches the ATR the seller serves, hashes its exact bytes and compares them with the ATR hash the seller advertised. Only on a match does it hand the signer a request built with that ATR hash; on any difference it declines, and the signer is never called. [Source: @integraledger/terms README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms/README.md) · [Source: lcp docs: the buyer gate⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/concepts/buyer-gate.md) It runs in the agent’s own process, with its HTTP client and its signer. It holds no keys, moves no funds, and never reads the ATR’s content: what the ATR says is for the buyer and its principal to judge. [Source: @integraledger/terms README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms/README.md)

@integraledger/terms

TypeScript

The gate as a library, for agents built in TypeScript. [Source: @integraledger/terms README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms/README.md)

integraledger-terms

Python

The same gate for Python agents, passing the same vectors. [Source: integraledger-terms (Python) README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms-py/README.md)

@integraledger/terms-mcp

MCP

The gate’s operations as MCP tools, with a skill that teaches an agent to confirm the ATR before it pays. [Source: @integraledger/terms-mcp README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms-mcp/README.md)

**Sources (6)**

[@integraledger/terms README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms/README.md) · [lcp docs: the buyer gate⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/concepts/buyer-gate.md) · [integraledger-terms (Python) README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms-py/README.md) · [@integraledger/terms-mcp README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms-mcp/README.md) · [LCP §12.7⁠ (opens in a new tab)](https://github.com/legal-context-protocol/legal-context-protocol/blob/c8df26d/spec/legal-context-protocol-v1.md#127-agent-side-security-considerations) · [lcp docs: the agreement URL⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/concepts/buyer-gate.md#the-agreement-url)

#### The standard

The gate as a library: `transact` in one call, or `confirm` then `finish` when the key signs elsewhere. [Source: @integraledger/terms README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms/README.md)

##### The gate’s named declines

The decisions are made on bytes and structured values, never on the ATR’s prose. Each decline has a name: [Source: lcp docs: the buyer gate⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/concepts/buyer-gate.md) · [Source: LCP §12.7⁠ (opens in a new tab)](https://github.com/legal-context-protocol/legal-context-protocol/blob/c8df26d/spec/legal-context-protocol-v1.md#127-agent-side-security-considerations)

**`hash-mismatch`**

The bytes the link served do not hash to the advertised ATR hash. [Source: lcp docs: the buyer gate⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/concepts/buyer-gate.md)

**`atr-unfetchable`**

The ATR could not be fetched: the link answered with an error, a redirect, or a content coding other than identity.

**`link-not-https`**

The ATR’s link, or the agreement URL, is not an https address.

**`atr-too-large`**

The ATR is larger than 1,048,576 bytes.

**`offer-unreadable`**

The seller’s offer cannot be read as the pairing’s challenge or checkout.

**`no-payable-option`**

No option in the offer is one this pairing can pay.

**`pairing-not-supported`**

The gate has no buyer side for the pairing it was asked to pay.

**`signer-failed`**

Your signer did not sign.

**`signed-not-bound`**

What was signed does not carry the ATR hash of these bytes.

**`agreement-not-offered`**

The pairing’s payment is not a public proof, and the offer names no agreement URL. [Source: lcp docs: the agreement URL⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/concepts/buyer-gate.md#the-agreement-url)

**`agreement-pending`**

An agreement payment for this ATR is already settling.

**`agreement-failed`**

The agreement payment did not end in a recorded agreement for this ATR.

#### The code

Compiled against the published packages when the site is built.

The gate in an agent: compare, then pay; keep the ATR

src/snippets/buyer.ts

```
// The buyer's agent, before its wallet signs: the gate fetches the record from its link, hashes the exact bytes,
// compares them with the fingerprint the seller advertised, and only then hands the signer a payment that carries it.
import { BINDINGS } from '@integraledger/lcp';
import { transact, type Signer } from '@integraledger/terms';

export async function pay(challenge: unknown, signer: Signer, keep: (record: Uint8Array) => Promise<void>) {
  const binding = BINDINGS.find((b) => b.id === 'x402/exact/eip155/eip3009')!;
  const result = await transact(challenge, binding, signer, fetch);
  if ('decline' in result) throw new Error(`${result.decline.code}: ${result.decline.detail}`);
  if ('approve' in result) return result; // an agreement payment for the agent to approve first
  await keep(result.bytes); // the record it compared, byte for byte
  return result.signed; // the payment, carrying the fingerprint
}
```

#### Check it yourself

1. Run the gate’s published vectors against your own buyer side: the TypeScript and Python gates pass the same ones. [Source: integraledger-terms (Python) README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms-py/README.md)

The seller side

### One contract for the seller’s side.

A connector, your platform’s plugin or a seller’s checkout backend, speaks one server-to-server contract to the seller door. Four operations cover an agreement from offer to settlement. [Source: @integraledger/agentic-connectors README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-connectors/blob/48500fe/contract/README.md) · [Source: connectors docs: the seller door⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-connectors/blob/48500fe/docs/concepts/seller-door.md)

**issue**

Before the buyer approves: assemble the ATR, write it to the seller’s storage, hash it, and return what to place in the payment request. [Source: @integraledger/agentic-connectors README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-connectors/blob/48500fe/contract/README.md)

**claim**

When the buyer presents a payment, before it moves: the one check that the payment carries this ATR’s hash. [Source: @integraledger/agentic-connectors README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-connectors/blob/48500fe/contract/README.md)

**report**

After payment: the platform’s payment reference, keyed by the ATR hash. [Source: @integraledger/agentic-connectors README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-connectors/blob/48500fe/contract/README.md)

**status**

Any time: the record, and what it proves. [Source: @integraledger/agentic-connectors README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-connectors/blob/48500fe/contract/README.md)

Integra’s hosted appliance answers the seller door, with each seller its own tenant, and it is free on test networks. [Source: connectors docs: the seller door⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-connectors/blob/48500fe/docs/concepts/seller-door.md)

**Sources (2)**

[@integraledger/agentic-connectors README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-connectors/blob/48500fe/contract/README.md) · [connectors docs: the seller door⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-connectors/blob/48500fe/docs/concepts/seller-door.md)

#### The standard

The contract is an OpenAPI 3.1 document in `@integraledger/agentic-connectors`, with TypeScript types, a refusal table and vectors: `POST /issue`, `POST /claim`, `POST /report` and `GET /status/{atrHash}`. [Source: @integraledger/agentic-connectors README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-connectors/blob/48500fe/contract/README.md)

#### The data

Read from the published packages when the site was built; nothing here is typed by hand.

`issue`, from the contract’s published vector: one x402 option on Base Sepolia

request

```
POST /issue

{
  "mintRequestId": "chk_7Q2:v1",
  "resource": "quote",
  "lifetimeSeconds": 60,
  "offers": [
    {
      "pairing": "x402/exact/eip155/eip3009",
      "option": {
        "scheme": "exact",
        "network": "eip155:84532",
        "amount": "10000",
        "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
        "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
        "maxTimeoutSeconds": 60,
        "extra": {
          "name": "USDC",
          "version": "2"
        }
      }
    }
  ],
  "request": {
    "method": "GET",
    "path": "/v1/report",
    "query": "",
    "bodyDigest": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
  },
  "content": [
    {
      "slot": "terms",
      "bytes": "IlBheSAxMDAwMCBiYXNlIHVuaXRzIG9mIFVTREMgZm9yIG9uZSByZXBvcnQuIg=="
    }
  ]
}
```

response

```
{
  "atrHash": "0x3c2394624c8c9a61ebaf7d8750a6f9ac21bf73e6369b7c0b64c83e34509cc3d3",
  "link": "https://atr.seller.example/0x3c2394624c8c9a61ebaf7d8750a6f9ac21bf73e6369b7c0b64c83e34509cc3d3",
  "expiresAt": "2026-09-21T14:14:20.000Z",
  "mintRequestId": "chk_7Q2:v1",
  "carriers": {
    "lcp": "lcp:sha256:0x3c2394624c8c9a61ebaf7d8750a6f9ac21bf73e6369b7c0b64c83e34509cc3d3",
    "legalContext": {
      "type": "sha256",
      "value": "0x3c2394624c8c9a61ebaf7d8750a6f9ac21bf73e6369b7c0b64c83e34509cc3d3",
      "legalContextUrl": "https://atr.seller.example/0x3c2394624c8c9a61ebaf7d8750a6f9ac21bf73e6369b7c0b64c83e34509cc3d3"
    },
    "legal_context": {
      "type": "sha256",
      "value": "0x3c2394624c8c9a61ebaf7d8750a6f9ac21bf73e6369b7c0b64c83e34509cc3d3",
      "legal_context_url": "https://atr.seller.example/0x3c2394624c8c9a61ebaf7d8750a6f9ac21bf73e6369b7c0b64c83e34509cc3d3"
    }
  },
  "pairings": [
    {
      "pairing": "x402/exact/eip155/eip3009",
      "pattern": {
        "pattern": "native-field",
        "canonical": false,
        "profile": "x402/exact/eip155/eip3009",
        "buyerSigns": true,
        "onChain": true,
        "zeroPartyRecoverable": true,
        "forwardIndexable": true,
        "publicProof": true,
        "proves": "The payer signed an EIP-3009 transfer authorization whose nonce is this ATR's hash. The token contract verified that signature when it executed the transfer, and the hash is on chain as the nonce topic of its AuthorizationUsed event in the settlement transaction. This does not show that amount, payee, asset or timing match the ATR's content."
      }
    }
  ]
}
```

#### Check it yourself

1. Run the contract’s vectors against your connector, or against your own seller door: each fixes a request and the answer it must get. [Source: @integraledger/agentic-connectors README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-connectors/blob/48500fe/contract/README.md)

What stays yours

### Your keys, your storage, your network readers.

#### Keys and signing

The packages hold no key and sign nothing. The buyer’s gate hands your signer a request; the signer is yours. [Source: @integraledger/lcp: what it guarantees⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/lcp/README.md#what-it-guarantees-and-what-it-does-not) · [Source: @integraledger/terms README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms/README.md)

#### The ATR’s storage

The packages store no ATR: the seller and the buyer each keep their own copy, and the seller serves its copy at a link. [Source: @integraledger/lcp: what it guarantees⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/lcp/README.md#what-it-guarantees-and-what-it-does-not) · [Source: lcp docs: the ATR⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/concepts/atr.md)

#### Reading the network

Settlement is read through a reader you supply: the endpoint, the credentials, the timeouts and the retries are yours. [Source: lcp docs: reading settlement⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/guides/rails.md#reading-settlement)

#### Settling

The package calls no facilitator. Settlement is the rail’s, through whichever facilitator or processor you use; one x402 facilitator, for the Tron and Polkadot profiles, is published as a package. [Source: @integraledger/lcp: what it guarantees⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/lcp/README.md#what-it-guarantees-and-what-it-does-not) · [Source: @integraledger/profile-facilitator README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-connectors/blob/48500fe/profile-facilitator/README.md)

**Sources (5)**

[@integraledger/lcp: what it guarantees⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/lcp/README.md#what-it-guarantees-and-what-it-does-not) · [@integraledger/terms README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-terms/blob/c094847/agentic-terms/README.md) · [lcp docs: the ATR⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/concepts/atr.md) · [lcp docs: reading settlement⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/guides/rails.md#reading-settlement) · [@integraledger/profile-facilitator README⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-agentic-connectors/blob/48500fe/profile-facilitator/README.md)

#### The standard

A reader is an interface you implement over your own node. `EvmReader`, for one, is four calls: `eth_getTransactionReceipt`, `eth_getBlockByNumber` for the safe and finalized marks, `eth_getTransactionByHash` and `eth_call`. A reader that fails never makes a payment read as failed. [Source: lcp docs: reading settlement⁠ (opens in a new tab)](https://github.com/IntegraLedger/integra-protocol/blob/66274bf/docs/guides/rails.md#reading-settlement)

#### The code

Compiled against the published packages when the site is built.

Your reader, your node: read the hash back from a settled transfer

src/snippets/recover.ts

```
// Anyone, from the chain alone: read the fingerprint back from a settled EIP-3009 transfer, through your own node.
import { isRefusal } from '@integraledger/lcp';
import type { Eip155, EvmReader, Hex } from '@integraledger/lcp/evm';
import { exactEip3009 } from '@integraledger/lcp/x402';

export async function fingerprintOf(network: Eip155, asset: Hex, transaction: Hex, reader: EvmReader) {
  const h = await exactEip3009.recover({ network, asset, transaction }, reader);
  return isRefusal(h) ? null : h; // compare it with the hash of the record you hold
}
```

### Ready to see your own agreements proved?

Tell us what you sell, buy or carry, and we will show you where the agreement rides in it.

The hosted appliance is free on test networks, with test-network USDC.

[Talk to us](https://integraledger.com/contact)
