Skip to main content
Glama

Interline — agent-to-agent payment router

An agent-to-agent payment router: one agent does work, another agent pays for it, no human keys a card. Interline is a neutral, non-custodial router over the fragmented agent-payment-rail stack — "OpenRouter for agent payments." Built on x402 (HTTP-402 micropayments, USDC), aggregator-shaped so adding a rail is one adapter, not a rewrite.

Today it routes payments across three live railsx402 USDC on EVM (Base Sepolia) and on Solana (devnet), plus MPP on Tempo (Moderato testnet) — all behind one Paywall.gate() call. Real on-chain agent-to-agent settles are confirmed on all three. It ships an MCP router so agents can discover + pay endpoints, and includes a Google-AP2 inbound adapter — a signed AP2 mandate (verified, constraint-checked + freshness-gated) settles non-custodially on the rails.

Run the demo (no wallet, no faucet, no risk)

python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python3 run_demo.py

Expected: DEMO PASS — agent paid agent, settlement receipt issued.

What just happened (the x402 "exact-evm" loop):

buyer GET /work
  -> seller 402 + PaymentRequirements {amount, asset=USDC, payTo, network}
  -> buyer signs an EIP-3009 transferWithAuthorization (gasless USDC auth)
  -> buyer retries with X-PAYMENT header (base64 signed payload)
  -> facilitator VERIFIES the signature (real signer-recovery) + checks policy
  -> facilitator SETTLES (mock: fake tx hash; live: on-chain USDC transfer)
  -> seller 200 + work product + X-PAYMENT-RESPONSE receipt (tx hash)

The facilitator's verify step is real cryptography even in mock mode — it recovers the EIP-712 signer and matches it to the authorization. Only the on-chain broadcast is mocked. So a passing demo proves the buyer's signing is protocol-correct against real USDC.

Related MCP server: Tilde x402 MCP Server

Files

file

role

router/paywall.py

the reusable Paywall primitive — gate any endpoint behind x402 in one .gate() call

router/ledger.py

settlement receipt-ledger → logs/agent_payment_settlements.jsonl (audit trail)

router/seller.py

FastAPI agent that sells work — defines the requirements + work, wires one Paywall.gate()

router/buyer.py

agent that auto-pays 402s (pay_and_get) with a client-side spend limit

router/eip3009.py

the one crypto-subtle file: EIP-3009 typed-data, shared by buyer+facilitator so they can't drift

router/facilitator_mock.py

in-process verify+settle (real sig check, mock chain) — the dry-run rail

router/facilitator_real.py

live x402 facilitator over HTTP via the x402 SDK's own client; get_facilitator() picks mock↔real by config

router/config.py

network/asset facts + .env loader; mock↔testnet↔mainnet is a one-line env change

run_demo.py

end-to-end smoke (ephemeral keys, mock facilitator)

run_live.py

live runner — settles a real x402 payment on Base Sepolia

Go live (Base Sepolia testnet)

  1. Two testnet wallets (buyer signs, seller receives):

    python3 -c "from eth_account import Account; a=Account.create(); print('addr', a.address); print('key', a.key.hex())"

    Do this twice. Keep the keys out of git (use .env).

  2. Fund the buyer with Base Sepolia testnet USDC (Circle faucet) + a little testnet ETH for any gas the facilitator relays.

  3. .env (copy .env.example.env, it's gitignored + auto-loaded):

    APV0_NETWORK=base-sepolia
    APV0_BUYER_PRIVATE_KEY=0x...        # buyer testnet key (signs)
    APV0_SELLER_ADDRESS=0x...           # seller address (receives)
    APV0_FACILITATOR_URL=https://x402.org/facilitator
  4. Run it live:

    python3 run_live.py

    The seller now uses RealFacilitator (the x402 SDK's own facilitator client), the buyer auto-pays the 402, and x402.org broadcasts the EIP-3009 USDC transfer on-chain. You get a real tx hash → https://sepolia.basescan.org/tx/<hash>.

    Gasless: with EIP-3009 the facilitator relays gas, so the buyer only needs testnet USDC, not ETH.

Gate your own endpoint (the product primitive)

from router.paywall import Paywall
from router.facilitator_real import get_facilitator

paywall = Paywall(get_facilitator(), my_requirements_fn)   # mock ↔ real by env

@app.get("/my-endpoint")
def my_endpoint(request: Request):
    return paywall.gate(request, lambda: do_expensive_work())

That one .gate() call handles the whole x402 V2 dance — 402 challenge → verify → settle → record receipt → deliver — and appends every settlement to the receipt-ledger. The deployer never touches the protocol or holds a key.

v1 dogfood — pay an agent, get REAL work back

v0 proved the payment. v1 proves the loop: a buyer agent pays → a seller agent does real inference → returns the result + a settlement receipt. The seller's _do_the_work(task) is the product's integration point (plug in your own model/compute/service).

APV0_OPENROUTER_KEY=sk-or-... python3 run_v1_dogfood.py "your task here"

V1 DOGFOOD PASS — agent paid agent for real work ✅ (mock payment + real model call by default; set APV0_NETWORK=base-sepolia for a real on-chain settle under the same loop). Without a key it returns a stub so the product still runs.

This is the authentic loop: an agent doing real work, metered + paid-for over x402 — the same primitive whether the work is a model call, a compute job, or any other billable agent task.

Available Tools

4 tools
discover_payment_railsA

Probe a paid endpoint and report which payment rails it accepts + the price for each — WITHOUT paying.

The neutral rail-discovery layer: one call tells your agent every way it could pay this endpoint, across whatever rails the endpoint offers. Use this before pay_for_resource to see the price/rails.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYes

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description must carry behavioral info. It states it is non-destructive ('WITHOUT paying'), but lacks details on side effects, authentication, error handling, or response structure. Adequate but not thorough.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with key action ('Probe a paid endpoint...'), no fluff. Every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema or annotations, the description should explain the return format. It says 'report which payment rails... + price' but does not detail the structure. Adequate for a simple probe, but could be more complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description partially compensates by explaining that the url parameter is a 'paid endpoint'. However, it does not specify format, validation, or additional constraints, leaving some ambiguity.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it probes a paid endpoint to discover payment rails and prices without paying. It uses specific verb-resource ('discover payment rails') and distinguishes itself from siblings like pay_for_resource.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Use this before pay_for_resource', providing clear context for when to invoke. However, it does not specify when not to use or mention alternative sibling tools like list_known_rails.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_known_railsA

List EVERY agent-payment rail/protocol Interline knows about + how it relates to each — the neutral catalog.

Separates rails Interline SETTLES natively (route_mode=native-settle: x402, AP2-via-adapter) from protocols it ROUTES you TO but does not settle (route_mode=handoff: Virtuals ACP's own on-chain escrow, OpenAI/Stripe ACP's card-only delegated payment). One call = the whole agent-payment landscape, including the rails we don't move funds on. Pair with discover_payment_rails (what a specific endpoint accepts).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden and effectively discloses behavior: it separates rails into native-settle and handoff categories, includes rails it doesn't move funds on, and implies the output is a catalog. This adds significant behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the main purpose and provides structured detail into two modes and a pairing suggestion. While slightly long, every sentence adds value and avoids redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no annotations, no output schema, and zero parameters, the description adequately covers the tool's purpose, output categorization, and relationship to siblings. It provides enough context for an agent to decide when to use it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero parameters, and the baseline for 0 parameters is 4. The description clearly explains the tool's function without needing parameter-level details, adding no redundancy.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states the action ('List') and the resource ('every agent-payment rail/protocol Interline knows about'), and distinguishes its purpose from the sibling tool 'discover_payment_rails' by noting they pair together for different needs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains when to use this tool ('one call = the whole agent-payment landscape') and how it relates to a sibling tool ('Pair with discover_payment_rails'), providing clear context though not explicit exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pay_for_resourceA

Pay for and fetch a paywalled resource, returning its content + a settlement receipt.

Routes the payment through the rail the endpoint accepts; never pays more than max_price_usdc. Uses the caller's OWN wallet key from APV0_BUYER_PRIVATE_KEY (non-custodial — this server never holds or sees funds). task is appended as a query param for endpoints that take one.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYes
taskNo
max_price_usdcNo

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description effectively discloses key behaviors: non-custodial wallet usage, price cap enforcement, and task query parameter handling. However, it omits details on error handling, async behavior, or settlement receipt format.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Concise three-sentence description with no fluff. Each sentence adds distinct value: purpose, payment constraints, and security detail. Front-loaded with the core action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description adequately states returns (content + receipt). However, for a payment tool, more detail on failure modes or processing expectations would enhance completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so description must explain parameters. It clarifies max_price_usdc (price cap) and task (query param), but url is only implied by the tool's purpose. Defaults are mentioned but not fully explained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the verb 'Pay for and fetch' and the resource 'a paywalled resource'. Differentiates from sibling tools (discover, list, history) by focusing on executing payment and fetching content.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implies usage when needing to retrieve a paywalled resource, but lacks explicit guidance on when not to use or alternatives. Does not mention prerequisites like having discovered payment rails or sufficient funds.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

payment_historyC

Return the most recent cross-rail settlement receipts — the unified ledger across every rail paid through.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo

TDQS

C2.8/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden but only mentions 'most recent' receipts. It does not disclose whether the operation is read-only, requires authentication, affects data, or any other behavioral traits beyond the default implication of a read operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, concise sentence that front-loads the primary action and resource. It contains no extraneous words, though it could benefit from additional useful details without sacrificing conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite low complexity (1 optional parameter, no output schema), the description omits parameter information and usage context. It provides basic purpose but lacks the completeness needed for an agent to confidently invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has one parameter (limit, default 20) with 0% description coverage. The description does not explain the limit parameter, its purpose, or expected values, leaving the agent with no semantic guidance.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool returns 'the most recent cross-rail settlement receipts', specifying the resource (settlement receipts) and scope (unified ledger across all rails paid through). It effectively distinguishes from siblings like discover_payment_rails (discovery) and pay_for_resource (payment).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus alternatives, such as discover_payment_rails or list_known_rails. There are no prerequisites, use cases, or exclusions mentioned.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv0.1.2
    • First observeddiscover_payment_rails
    • First observedlist_known_rails
    • First observedpay_for_resource
    • First observedpayment_history

TDQS

A3.7/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: discovering endpoint-specific rails, listing all known rails, paying for a resource, and viewing payment history. No overlap or ambiguity.

Naming Consistency4/5

Most tools follow a verb_noun pattern (discover_, list_, pay_), but 'payment_history' is a noun_noun pair, creating a minor inconsistency. Overall clear and predictable.

Tool Count5/5

Four tools cover the essential operations for a payment rail server: discovery, listing, payment, and history. The count is well-scoped and appropriate.

Completeness4/5

Core workflows are covered: rail discovery (per-endpoint and global), payment, and history. Missing potential operations like refund or cancellation, but not critical for the stated purpose.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers