The Interledger Community 🌱

Cover image for Agentic Payments over Interledger Protocol - I tried it, and it works
Santosh Viswanatham
Santosh Viswanatham

Posted on

Agentic Payments over Interledger Protocol - I tried it, and it works

Agentic payments are no longer a distant concept. Razorpay in India, Stripe, and PayPal are all actively exploring how AI agents can initiate and execute payments on behalf of users. The question I kept coming back to was simpler and more specific:

Can the Open Payments standard and the Interledger Protocol support agentic payments today?

I decided to find out if I can orchestrate an Open Payments payment end-to-end—including a cross-currency payment—with value delivered over the Interledger Protocol.

Here's how it went.


The questions I started with

Before I wrote a single line of code, I had a bunch of open questions:

Is Open Payments agent-friendly?

Open Payments was designed to let clients interact with wallets hosted by different Account Servicing Entities (ASEs) through a common API. It wasn't explicitly designed with AI agents in mind.

Would those same APIs translate naturally to an agentic workflow?

Do we need a human in the loop?

Financial transactions carry real risk. Today, we generally assume a human authorizes every payment or sets up the permissions that allow one.

Should an AI agent be allowed to act on a user's behalf? If so, what should authorization look like?

How should authorization work?

Open Payments uses GNAP for authorization.

GNAP's interactive flow is commonly implemented as a browser redirect where the user approves a grant before the client can continue(at least IMO). How well would that model fit an autonomous AI agent?

How do you give an agent enough context to execute an Open Payments workflow?

An Open Payments payment spans multiple resources and authorization steps:

  • resolving a Wallet Address
  • creating an Incoming Payment
  • requesting a Quote
  • creating an Outgoing Payment
  • completing the payment

How does an agent know which step comes next? What information does it already have? Which resources or authorization grants does it still need?

Can an agent actually orchestrate the entire flow?

Even if all of the above could be solved, would an agent correctly sequence the API calls, recover from errors, and complete the payment without a developer guiding every step?

These weren't rhetorical questions. I genuinely didn't know the answers when I started.


What I built

To answer these questions, I built open-payments-mcp — an MCP (Model Context Protocol) server that exposes the Open Payments APIs as tools AI agents can call directly.

https://github.com/devcer/open-payments-mcp

It's still an early proof of concept, so expect rough edges.

MCP is an open protocol that lets AI assistants connect to external tools and services. By exposing Open Payments through MCP, I could give Claude (or any MCP-compatible agent) access to Wallet Address resolution, grant requests, Incoming Payments, Quotes, and Outgoing Payments as native tools.

The configuration looks like this:

"mcpServers": {
  "open-payments-mcp": {
    "command": "node",
    "args": ["/path/to/open-payments-mcp/dist/index.js"],
    "env": {
      "OPEN_PAYMENTS_CLIENT_ADDRESS": "https://ilp.interledger-test.dev/wmtest",
      "OPEN_PAYMENTS_KEY_ID": "your-key-id",
      "OPEN_PAYMENTS_PRIVATE_KEY_PATH": "/path/to/private.key"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The OPEN_PAYMENTS_CLIENT_ADDRESS (wmtest) identifies the Open Payments client.

This client orchestrates interactions with both the sender's and receiver's wallets using authorization grants issued by their respective authorization servers.


What makes Open Payments surprisingly agent-friendly

As I built this, several aspects of Open Payments felt particularly well suited for AI agents already.

Wallet Addresses resolve to standard web resources

A Wallet Address like

$ilp.interledger-test.dev/sendersantosh
Enter fullscreen mode Exit fullscreen mode

resolves to structured metadata containing the wallet's asset information, authorization server, and resource server.

For an AI agent, resolving a Wallet Address feels no different than retrieving any other web resource.


Authorization grants naturally constrain spending

When creating an authorization grant for an Outgoing Payment, the client can request an exact maximum debitAmount.

That gives an agent a precise spending limit, and the authorization server enforces that limit. This is exactly the kind of guardrail you'd want when allowing AI to move money.


A standardized API means agents only learn one workflow

Once the MCP tools exposed the Open Payments resources and operations, Claude was able to sequence the workflow correctly:

Incoming Payment
        ↓
Quote
        ↓
Outgoing Payment
Enter fullscreen mode Exit fullscreen mode

It didn't need provider-specific logic or custom integrations.


Cross-currency payments require very little agent logic

Currency conversion happens naturally as part of the Open Payments flow.

The client creates a Quote, which reflects the exchange rate available through the ILP payment path.

When I paid from a USD wallet to a EUR wallet, the agent didn't have to understand foreign exchange. It simply requested a Quote, received the converted amounts, and used those values to request authorization.


The demo

For the demo, I used the interledger test wallet. I typed this into Claude Desktop:

Let's initiate a payment with the below details
Sender: $ilp.interledger-test.dev/sendersantosh
Receiver: $ilp.interledger-test.dev/receiversantosh
Amount: 10 USD

Claude then orchestrated the complete Open Payments workflow.

1. Wallet Address resolution

Claude resolved both Wallet Addresses and immediately noticed something interesting.

The sender wallet was denominated in USD while the receiver wallet used EUR.

It correctly created the Incoming Payment using the receiver's asset instead of assuming both wallets used the same currency.

Claude verifying both wallet addresses and noticing the USD→EUR cross-currency setup


2. Authorization grant + Incoming Payment

Claude requested authorization from the receiver's authorization server before creating the Incoming Payment.

No manual intervention was required.

request_grant and create_incoming_payment tool calls completing successfully


3. Quote

Next, Claude requested authorization to create a Quote and generated one referencing the Incoming Payment.

The result:

$11.54 USD → €10.00 EUR

with a five-minute validity window.

create_quote result showing $11.54 USD to €10.00 EUR cross-currency rate


4. Outgoing Payment authorization

Claude then requested authorization to create an Outgoing Payment.

The authorization request limited the maximum debit amount to exactly $11.54 USD, and the authorization server returned an approval URL.

Claude presenting the approval URL with full payment details — sender, receiver, debit and receive amounts

I opened the URL, approved the request, and pasted the interact_ref from the callback back into Claude.


5. Payment

Claude continued the authorization flow before creating the Outgoing Payment.

Done.

Payment created successfully — sendersantosh to receiversantosh, $11.54 USD debited, €10.00 EUR received via ILP cross-currency

The entire workflow—from Wallet Address resolution through authorization, Quote creation, and final payment—was orchestrated through a conversation.


The challenges

It definitely didn't work on the first try.

Understanding the resource dependencies

The sequencing matters.

Incoming Payments must exist before Quotes can reference them.

Quotes provide the amounts used when requesting authorization for an Outgoing Payment.

Understanding those relationships took some time.


GNAP authorization is more involved than it first appears

The interactive authorization flow has several moving parts:

  • requesting the grant
  • redirecting the user
  • receiving the callback
  • extracting the interact_ref
  • continuing the grant

Understanding which responsibilities belonged to the client versus the authorization server required several iterations.


Callback hash verification

This was easily the hardest part.

GNAP requires the client to verify the callback by computing a hash from several values, including the nonce, interaction reference, continuation URI, and client challenge.

Understanding this and getting this to work with Agent took me the most time.

For now, I worked around it by manually extracting the interact_ref, but properly implementing callback verification is still on my roadmap.


So — is ILP ready for agentic payments?

I think the answer is largely yes.

The building blocks are already there.

  • Wallet Addresses resolve to discoverable web resources.
  • A standardized API works across providers.
  • Payments naturally support multiple currencies.
  • Authorization grants provide fine-grained spending limits.
  • Clients have identities independent of wallets.

The remaining challenge is authorization.

Today's interactive GNAP flow typically assumes a human approves a browser-based authorization request. For fully autonomous agents, that's the one place where the workflow still pauses for human approval.

Personally, I think that's a sensible default.

But as agentic payments evolve, we'll need to explore questions like:

  • Should wallets issue long-lived delegated grants to trusted agents?
  • Should agents have their own cryptographic identities?
  • Should users be able to authorize spending policies instead of individual payments?

Those feel like protocol and product questions worth exploring.


What's next

For open-payments-mcp, I want to:

  • add more Open Payments tools
  • try out different payment types such as subscriptions
  • explore around making the human approval flow much smoother

More importantly, I'd love to hear from the Open Payments community.

If you've been thinking about how Open Payments and GNAP could evolve to support autonomous agents—while preserving meaningful user consent—I’d love to hear your thoughts.

What should agent-native authorization look like?

Top comments (0)