Delegus

ReceiptsLaunch

An AI agent can pay. That doesn't mean it was allowed to.

We wrote an MPP extension that checks a company's authority before the seller takes the money. Here's how it works, and how to run it.

Team Delegus

  • 4 min read

If you've built a server that takes MPP payments, you know the loop. A request comes in, you answer 402 with a challenge, the client comes back with a Payment-Authorization header, you verify the credential, you settle, you serve. It's a clean loop and it works.

Now put an AI agent on the client side, buying for a company. The loop still works. The credential tells you who's paying and that the money is there. What it can't tell you is whether anyone at that company allowed this agent to spend $427 with you today. Or whether they did last week and pulled it yesterday. You have no field to look at. So you either trust the agent, or you don't take agent traffic.

We asked the MPP maintainers where that question should live. The answer was: not in the core spec, write an extension. So we did. The draft and a seller you can run are at github.com/delegusai/mpp-delegated-authority.

One new field#

The agent sends one extra header next to its payment:

text
Payment-Authority: profile="delegus-v0.2", grant="<JWS>", proof="<JWS>"

The grant is the company's signed statement of what this agent may buy, from whom, up to how much per order, until when. The proof is the agent's own signature binding that grant to this one request: this seller, this exact purchase, this method and URL, usable once. Both are the Delegus v0.2 formats, byte for byte; the header just carries them. The profile name is there so other ways of expressing authority can use the same field later.

Your 402 challenge gains one parameter, authority, that says you want it, which profiles you accept, and the exact action the proof has to sign. Clients that don't know the parameter ignore it, as the core spec already requires.

What your server does with it#

The order is the whole point, so here it is as the draft specifies it:

  1. Run the core credential checks that have no side effects. If something's wrong there, it's still a 402.
  2. No Payment-Authority and you require one: 403, authority-required. Don't charge.
  3. Check the proof's method and URL against the request yourself. The verifier never sees your request, only the signed artifacts, so this binding is your job. Mismatch: 403.
  4. Call /verify with the grant, the proof and the action as you recorded it in the challenge. You get back ALLOW or DENY with a reason code, signed.
  5. DENY: 403 with the signed decision in the body and payment: "not_attempted". No WWW-Authenticate, no payment receipt. The agent gets AMOUNT_EXCEEDS_AUTHORITY or AUTHORITY_REVOKED or PROOF_REPLAYED and can't talk its way past it.
  6. Verifier unreachable, or the answer isn't a valid receipt: 503 with Retry-After. Never guess yes.
  7. ALLOW: now, and only now, verify the payment and settle. Your Payment-Receipt gets an authority object with the receipt id and hash, and the response carries the decision itself in Payment-Authority-Receipt.

Every settlement gets a fresh decision. The proof's jti is consumed on first use, so a retry needs a new proof. If the company revokes the grant, the next /verify anywhere says DENY, which is a guarantee of the Delegus spec rather than a cache hoping to catch up.

Why we answer 403 and not 402#

This is the part we most want pushback on. The core spec splits the two: 402 means payment is what's missing, 403 means the payment is fine but policy says no. An authority refusal is the second case. Sending a fresh 402 challenge, as an earlier proposal did, invites the agent to pay again for something it was never allowed to buy. Paying again can't fix authority. So the draft answers 403, carries the signed reason, and states plainly that no payment was attempted.

Run the seller#

The example needs Node 22.6 or later and nothing from us but two published packages, @delegus/core and @delegus/conformance.

text
cd example
npm install
npm start

It starts a seller with a stand-in payment method and sends it the public test vectors. The decisions are real signed receipts, and the seller checks every signature. What you'll see:

text
Grant up to $500.00, buys $427.00            200 paid, 1 settlement
The same Proof again                         403 authority-denied PROOF_REPLAYED (payment not_attempted)
Grant up to $426.99, buys $427.00            403 authority-denied AMOUNT_EXCEEDS_AUTHORITY
The company revokes the grant                403 authority-denied AUTHORITY_REVOKED
No Payment-Authority at all                  403 authority-required
Verifier unreachable                         503 Retry-After

One settlement in the whole run. Every refusal happens before the payment credential is touched.

Where this is useful#

An agent paying supplier invoices under a monthly mandate the CFO set. An agent buying compute or API credits for a team, inside a cap. A marketplace or payment processor that wants agent traffic without becoming the party that decides what each buyer's agent was allowed to do. Any seller who has been asked, after the fact, "who approved this?" and had nothing to point at.

For a payment vendor the integration is one check before capture and one object on the receipt. The payment method, the rails and settlement don't change.

What it doesn't do yet#

Each purchase is checked against its own limit. A shared budget across many purchases and sellers is proposed for the next Delegus version and isn't in this draft. There's no MCP transport mapping yet. And it's a draft, not a standard: the right next step is a seller running it for real. If that's you, open an issue on the repo or write to hello@delegus.ai.

Humans lead. Agents do the work. Authority stays with people.