Inspiration

Agentic commerce is arriving faster than the infrastructure to dispute it safely. Standards like AP2 are emerging for how an agent proves it was authorized to buy something, but almost nothing exists for the other side of that transaction: what happens when the buyer disputes it afterward? Today, a merchant selling to an AI shopping agent has no better defense than "the payment went through." We wanted to build the missing half — a way for a merchant to answer a dispute with actual evidence of what was agreed, not just a hope that PayPal sides with them.

We also wanted to take a hard stance against a pattern we kept seeing in "AI + payments" demos: an LLM quietly making the decision that moves money. Warrant's core rule, enforced in code rather than just promised in a prompt, is the LLM writes words; code decides; a human approves; only then does anything reach PayPal.

What it does

  1. A buyer's AI agent presents a signed mandate when it buys — the user's spending limit, allowed merchant and categories, and validity window, cryptographically signed with the user's own key (ed25519, canonical JSON). The agent signs a separate cart for the exact purchase. Warrant verifies both signatures and that the cart stays inside what the mandate allows before it ever creates a PayPal order.
  2. The purchase goes through PayPal's real sandbox checkout — either an approval click, or, through a connected PayPal Vault payment method, a fully autonomous no-click charge.
  3. When a dispute lands — automatically, through a verified PayPal webhook, or by manual import — Warrant's merchant-side pipeline looks up the order, re-verifies the mandate, runs a deterministic decision rule (contest / offer a partial refund / accept the claim / escalate to a human), and assembles an evidence pack.
  4. An LLM (Gemini or Anthropic, with validated, bounded output) writes a plain-language explanation for the merchant and drafts the note PayPal's reviewer will see. It cannot change the decision, invent a number not already in the verified facts, or submit anything itself. If it fails any check, a deterministic template is used instead, and the merchant always sees which one they got.
  5. The merchant reviews everything on an approval screen — the finding, the AI's explanation, an editable note — and only their click sends anything to PayPal's Disputes API.
  6. A separate AG Studio analytics dashboard lets the merchant (or an AI analyst agent, on Gemini or OpenAI, with read-only access to PayPal's own MCP server) explore dispute trends: which buyer agents are driving disputes, which findings come up most, and more — pre-built with real charts, and able to build new ones from a plain-language request.

How the project meets the technology requirement

PayPal developer platform (sandbox):

  • Sandbox REST API — Orders. Creates and captures real sandbox orders for every purchase, approval-based or autonomous.
  • PayPal Vault. Stores a buyer's saved payment method so the agent can charge it with no click once authorized.
  • Disputes API. Submits the merchant's actual response — contest with evidence, or accept the claim — directly to PayPal, with a stable idempotency key so retries can't double-submit.
  • Webhooks. A verified CUSTOMER.DISPUTE.CREATED event (signature-checked, deduplicated) triggers the entire dispute pipeline automatically, with no manual import.
  • Log In with PayPal (OAuth). The buyer signs in with their real PayPal identity on /user before setting a spending permission.
  • PayPal's official MCP server. Gives the Studio analyst agent read-only sandbox context (list_disputes, get_dispute, list_product, show_product_details) — allow-listed and unable to approve, submit, or move money.

AI tools:

  • Google Gemini (gemini-3.1-flash-lite by default) does two jobs, both strictly advisory: it writes the plain-language explanation the merchant sees and the evidence note PayPal's reviewer sees (validated against the verified facts, length-capped, template fallback on any failure), and it powers the optional Studio analyst chat agent that can query live dispute data and build new charts on request. Since Gemini has no native MCP connector, we built our own bridge (geminiAgentBridge.ts) that speaks PayPal's MCP protocol directly and translates tool calls into Gemini's function-calling format.
  • Anthropic Claude is a drop-in alternative for the same explanation/drafting role (used automatically if no Gemini key is set).
  • OpenAI is a supported alternative provider for the Studio agent, using its native MCP connector — implemented but not exercised live in this submission, since no OpenAI account was available.

In every case, the AI only explains or drafts. The dispute decision itself (contest / accept / offer partial refund / escalate) is a pure, unit-tested function with zero LLM involvement, and nothing reaches PayPal until a human merchant clicks approve.

Additional sponsor tools used

  • Channel3 — real product search for the buyer agent, and verification: Warrant checks what was actually bought against Channel3's own product data, with a confirmed category mismatch becoming a blocking finding. A refused checkout also gets in-mandate alternatives from the same search.
  • Elastic — the merchant agent's investigation trace is indexed and searchable, and disputes are indexed as cases with a hybrid (semantic + keyword) search surfacing similar past outcomes on the approval screen (advisory only, never changes the decision).
  • Zapier — a full two-way evidence loop: Warrant asks for delivery proof it doesn't have, a Zap fetches it from the carrier and posts it back, and the proposal automatically re-runs.
  • AG Grid — the real, sortable/filterable dispute queue on the merchant approval screen.
  • AG Studio — the analytics dashboard (/studio), with a custom Mandate-gauge widget, PayPal theming, and the optional Gemini-backed analyst agent.
  • Render — the live deployment, with a persistent disk so dispute history survives restarts.
  • Postman / OpenAPI — postman_collection.json and openapi.yaml describe the full HTTP API.

How we built it

  • Backend: Node/TypeScript, Express, SQLite (node:sqlite). Mandates and carts are signed with ed25519 over canonical (recursively key-sorted) JSON and hashed with SHA-256.
  • PayPal integration: a sandbox-pinned REST client for orders, captures, and Vault payment tokens; a Disputes API client for evidence/accept-claim/make-offer; a webhook receiver that verifies PayPal's signature and deduplicates events before anything runs.
  • The decision layer is a pure function with zero LLM involvement: findings in, one of four actions out. It is unit tested exhaustively and is the one thing in the system an LLM cannot touch.
  • The AI layer sits only after the decision: strict JSON-schema validation, a numeric cross-check against the verified facts, length limits, and a deterministic template fallback on any failure. Mandate text from third parties is always passed to the model as explicitly quoted, untrusted data.
  • Sponsor integrations, each genuinely load-bearing, not just wired up: Channel3 (product search, and verifying what was actually bought against Channel3's own catalog data — a confirmed category mismatch becomes a blocking finding), Elastic (indexing the merchant agent's investigation trace and hybrid semantic+keyword precedent search), Zapier (a two-way loop — Warrant asks for delivery evidence it doesn't have, a Zap fetches it and posts it back, the proposal re-runs), AG Grid and AG Studio (a real dispute queue and a full analytics dashboard), and PayPal's own MCP server for read-only sandbox context.
  • The Studio AI agent runs on Gemini with no OpenAI account required — we built a from-scratch bridge (geminiAgentBridge.ts) that speaks MCP directly via the official @modelcontextprotocol/sdk and translates AG Studio's tool-call protocol into Gemini's function-calling, including handling Gemini 3's thought-signature replay requirement and preserving discriminated-union tool schemas that a naive JSON-Schema-to-Gemini translation would otherwise flatten.
  • Deployed on Render with a persistent disk for SQLite, a registered PayPal webhook verifying live traffic, and the dashboard shipping pre-built rather than opening to a blank canvas.

Challenges we ran into

  • PayPal's sandbox doesn't always offer the response you'd expect. An UNAUTHORISED dispute at the CHARGEBACK stage only offers provide_evidence and accept_claim — no partial-refund make-offer — so our partial-refund scenario had to become a blocked proposal that explains to the merchant why it can't be sent, instead of a submission. We'd rather show that honestly than fake a response that would fail in reality.
  • Gemini has no native MCP connector, unlike OpenAI's Responses API, so giving our Studio agent access to PayPal's MCP server on Gemini meant implementing the MCP client ourselves and bridging tool calls by hand — including a subtle bug where translating AG Studio's JSON Schema into Gemini's function-declaration format silently flattened a legitimately deep (10+ level), non-cyclic schema to a bare object, because the original depth guard couldn't tell "deep" apart from "cyclic." The fix was to track the actual $ref chain, not raw recursion depth.
  • Bugs that only showed up in the real browser harness, never in unit tests or single-turn smoke scripts — an async/sync mismatch in the LLM adapter contract, and Gemini 3's requirement that a thoughtSignature be replayed on every reconstructed function call, which AG Studio's own tool-call wire format has no field to carry. Both were found only by driving the actual chat UI, which is now a standing lesson for how we test this kind of integration going forward.

Accomplishments that we're proud of

  • A dispute pipeline where an LLM is genuinely useful (clear explanations, drafted evidence notes) and genuinely incapable of being the point of failure if it misbehaves — validated, bounded, and backed by a template fallback that's always disclosed to the merchant.
  • Every major path — checkout, capture, dispute creation, import, contest, accept-claim, autonomous no-click payment via PayPal Vault, and a live webhook — has been run against the real PayPal sandbox, not just mocked. 233+ automated tests pass alongside that live verification.
  • Three sponsor integrations that each change a real outcome: Channel3 catching a declared-category purchase that didn't match what was actually bought, Elastic surfacing similar past cases, and a full two-way Zapier loop that fetches missing delivery evidence and flips a stuck proposal to a contest.
  • A second, independent AI provider path (Gemini) for the Studio agent, built because an OpenAI account wasn't available — rather than skip the feature, we implemented PayPal's MCP protocol ourselves.

What we learned

That "AI decides, human approves" is a much stronger safety property than "AI decides, human can veto" — and that it's cheap to enforce in code once you draw the line in the right place (after the decision, not around it). Also, that a live browser run finds classes of bugs that mocked unit tests structurally cannot: adapter-contract mismatches, multi-turn provider requirements, and schema translation lossiness all live in exactly the code path a mock bypasses.

What's next for Warrant

  • The user's own key signing the mandate directly (today it's demonstrated with the agent and user keys co-located for the demo; production needs a wallet or passkey binding).
  • Verifying product category against a trusted merchant catalog in every case, not only when a Channel3 product ID is present.
  • Deeper AI involvement in triage — flagging suspicious mandates for human review, or drafting a request for the specific evidence a non-"unauthorized" dispute needs — always advisory, never decisive.

Try it out

Built With

Share this project:

Updates

Submission history