Inspiration

My negotiation agent, AI-NEGOTIATOR, ranks vendor offers and drafts the negotiation, then stops. A person still has to go and pay. The obvious next step is to let the agent pay, and that is exactly the step that should worry anyone: an agent that can pay is an agent holding your wallet. One swapped payee email, one runaway loop, or one deal agreed at ten times the budget, and the money is gone before a human looks.

What it does

negotiator-payments is the settlement step for a negotiation agent. Once a price is agreed, it pays the vendor through PayPal Payouts, but every payment has to pass a spending check first:

  • Per-payment cap and daily cap. A deal over the cap is refused, and so is a deal that would push the last 24 hours over the daily limit.
  • Payee check. The vendor allowlist ties each vendor name to its PayPal email. Same vendor name with a different email is refused as a possible payee swap.
  • Human approval above a threshold. The payment stops and waits. After a person approves, that exact payment (same vendor, email and amount) goes through once.
  • No double payment. A deal that already has a payout on record is refused.
  • Fails closed. If the check itself errors, the answer is no and PayPal is never called.
  • Tamper-evident log. Every decision is written to a hash-chained log; an edited record no longer verifies.

In the recorded sandbox run, seven payment attempts produced two real payouts ($42.50, and $250.00 after approval) and five refusals. PayPal's API reported SUCCESS for both payout batches, and the five refusals made zero requests to PayPal.

How I built it

  • PayPal: OAuth2 client credentials and the Payouts API (/v1/payments/payouts) through a thin httpx client, no SDK. The sender_batch_id is derived from the approved payment, so a retry reuses it instead of creating a second payout. The client refuses any non-sandbox host unless explicitly allowed.
  • AI: a Groq-hosted open model (openai/gpt-oss-20b), the same model the negotiation agent uses, writes the payout memo the vendor sees. The agent proposes the payment; it never decides whether the payment is allowed.
  • Spending check: a small Python module with the rules in a JSON policy file and a JSONL decision log where each record carries the hash of the one before it. It can also hand the approval decision to Aegis, my approval service for AI agents, so the approver's key is separate from the agent's.
  • Tests: 96 pytest tests with the HTTP layer faked, covering request shapes, every allow, deny and approval path, failing closed, and retry behaviour.

Challenges

  • Deciding what "the same payment" means. An approval has to release one specific payment and nothing else, so approvals are bound to vendor, email, amount and deal.
  • Retries after an unclear failure. If a payout request times out, the payment may or may not have happened. The code records it as unknown rather than unpaid and reuses the same batch id.
  • Being honest about local approval. With only a local file, anyone who can write the log can approve. The README says so, and the Aegis mode exists to close that gap.

What I'm proud of

  • A real sandbox run with payouts confirmed by PayPal's own API, not a mock.
  • Refused payments never reach PayPal at all.
  • I broke seven safety properties on purpose, one at a time, and the test suite caught every one.

What I learned

The hard part of agentic commerce is not calling the payment API. It is making sure the agent cannot be the one who decides it is allowed to.

What's next

  • Wire the settlement step into the live AI-NEGOTIATOR app so an agreed deal can be paid from the same screen.
  • Run the Aegis approval mode end to end with a real agent key.
  • Observe how PayPal answers a repeated batch id in the sandbox and tighten the retry path to match.

Built With

Share this project:

Updates

Submission history