Situation · Payments and refunds
Let an AI agent issue refunds — with approval bound to the exact amount
An agent holding a payments key can move money the moment it decides to. A refund is the clearest case: the provider acts before anything on your side changes, so review has to happen before the call, and it has to name this refund, not the tool. Strix is not affiliated with, endorsed by, or sponsored by Stripe, Inc. Stripe is a trademark of Stripe, Inc.
Answers the question: “How do I safely let an AI agent issue Stripe refunds?”
- Also: “How do I require human approval before an AI agent refunds a customer?”
- Also: “How do I stop an AI agent changing the refund amount after a person approved it?”
- Also: “What should an AI agent be allowed to do with the Stripe API?”
A key that can refund can refund anything
Restricting the key narrows which calls exist. It does not say whether this refund, to this customer, for this amount, should happen now. That decision has to be made at the call and recorded.
Approval of a class, not an instance: a person approves “refunds” and the agent refunds a different order or amount.
Amount drift between approval and execution: the call carries a figure nobody reviewed.
Replay: the same approved call is sent twice and two refunds are issued.
No record of what was checked: afterward there is a log line, not evidence a third party can verify.
Check it, then see it, then pick the id
The first step needs only a laptop. The third is the one that decides whether a hosted call produces evidence.
1 · Check a refusal yourself, offline — no account, no network
git clone https://github.com/Tarshann/solo-builder-core cd solo-builder-core && pip install -e . solo strix-wire verify docs/evidence/payment-refused-v1/.strix/evidence/receipts.jsonl --state-dir docs/evidence/payment-refused-v1/.strix # VERIFIED (local key) — 3/3 records, chain linked
Three signed local receipts: a $2,400 refund held pending approval, a charge denied, and the same refund executing once approval is granted. The wrapped payment is a tripwire that counts calls, so “no money moved” is observed, not inferred. The key is local to the machine that minted them: this shows the mechanism, not Strix-operated custody.
2 · See the amount bind on a live processor, and the browser model
open https://www.strixgov.com/proof/cfx-001 # $9.00 authority, $10.00 proposed open https://www.strixgov.com/demo/refund # simulated adapter, once-only
3 · Which id to use depends on where the call is checked
| Id | Where it is used | Hosted API | Note |
|---|---|---|---|
| finance.refund.issue | Hosted API | Registered | The id the hosted API accepts. Reached through the governed connector path. |
| payment.refund | Scanner and offline policy | Refused as unknown | What the scanner emits and the offline policy classifies. Not a hosted id. |
| payments.refund.issue | Package examples | Refused as unknown | The execution-authority package's own action vocabulary, not a capability id. Sent to the hosted API as a capability, it is refused. |
| rcm.consequence.refund.issue | Healthcare pack | Registered | A different action: a payer refund in the healthcare pack. Not a Stripe refund. |
An id the hosted API refuses as unknown fails closed, but it is a refusal at the contract check: no decision exists and so no signed record does. If you paste the scanner’s id against the hosted API you will get an error, not evidence.
What the kernel requires before a refund executes
Derived from the policy engine at build time, not written by hand. The answer is the same in every environment. This is a precondition, not an authorization: it describes what a decision would be asked for.
| Capability | How Strix delivers it |
|---|---|
| Registered tier | finance.refund.issue resolves CRITICAL and holds for human approval. It requires 3 distinct approvers. |
| Bound to the exact request | In the hosted kernel, approval attaches to the canonicalized payload. A changed amount or customer does not correspond to the grant and is refused before the handler runs. Shown on a live charge in CFX-001. Academy also has real governed Stripe refund evidence; that separate workflow does not establish production execution of this console connector pack. |
| Single-use grant | In the hosted kernel the grant is consumed on first use, so a second identical call fails closed. Production execution of this separate console connector pack is not established here. |
| Signed record | The decision is signed with Ed25519 and checkable against the public key set with npx @strixgov/verifier, with no Strix account. Academy has production-signed refund records and read Stripe's execution confirmation. Records from the offline path are signed by a local key. Signature coverage and provider confirmation are distinct evidence questions. |
| Academy production refunds | Strix governed real Academy Stripe refunds, and Stripe confirmed execution. The examined CFX-009 workflow includes a refused attempt and an executed refund. This is evidence for that workflow, not universal route coverage or production activation of the separate console connector pack. |
| Where it stands | The payments and refunds pack is registered and dormant. Strix governed real Academy Stripe refunds, and Stripe confirmed execution. That evidence is scoped to the examined Academy workflow. The separate console connector pack remains registered and dormant; its production execution is not established here. Neither a signed decision nor provider confirmation establishes that a refund was warranted. |
Proof, not promises
Every claim Strix makes is backed by an artifact you can independently verify.
CFX-001
One live charge. Authority held for $9.00, the same refund proposed at $10.00: the governed attempt was refused before the payment adapter and the processor stayed at $0.00 refunded. The native attempt executed. Not universal bypass resistance, and nothing in it is publicly addressable.
/proof/cfx-001Route drift
A second registered route capable of the same consequence was refused before its handler.
/proof/cfx-002Browser model
Interactive once-only model with a simulated adapter. Not a production receipt.
/demo/refundIndependent verify
Checks that a signed record is intact. The example id is a general production record, not a refund. The verifier does not decide allow or deny.
npx @strixgov/verifier@latest 5686Frequently asked questions
How do I safely let an AI agent issue Stripe refunds?+
Put the refund behind a decision made at the call. In the hosted kernel finance.refund.issue resolves CRITICAL and requires 3 distinct approvers, approval is bound to the exact payload, and the grant is single-use. That narrows what can happen; it does not make a refund correct. Academy has already executed real governed Stripe refunds and read Stripe's execution confirmation. This console connector pack is a separate registered, dormant implementation.
Does Strix issue the refund?+
In the Academy workflow, the governed application calls Stripe and reads Stripe's execution confirmation. Strix controls and records the governed attempt. The separate console connector pack is designed for a connector you operate to call the provider after grant redemption. Submission, provider-confirmed execution, and settlement are distinct facts; report the one the evidence actually establishes.
Is this running against real Stripe today?+
Academy has executed real governed Stripe refunds and read Stripe's execution confirmation. CFX-009 preserves refused and executed cases for the examined Academy workflow. This does not establish current availability or production execution of the separate console connector pack, which remains registered and dormant. CFX-001 is a separate preserved experiment on one live charge; its records are not publicly addressable.
Which action id should I use?+
Use finance.refund.issue against the hosted API. The scanner and offline policy use payment.refund, which the hosted API refuses as an unknown action. Mapping one to the other is a policy decision that has not been made.
What does the signed record prove?+
That a decision was made and what it bound. It does not prove the refund was warranted or that the customer was owed money. Academy also read Stripe's execution confirmation; whether that confirmation is covered by a particular signature is a separate question, and this page makes no settlement claim. Records from the offline path are signed by a local key and show the mechanism, not Strix-operated custody.
Does this replace restricted keys and Stripe's own controls?+
No. Those narrow what a key can do. This decides whether one specific call should run now. Strix is not affiliated with or endorsed by Stripe.
Related paths
Bind approval to the exact request
The amount, customer and route counterfactuals behind the exact-payload bind.
Open →A write gate for MCP tools
The same boundary where the agent reaches a payments tool over MCP.
Open →Stop an AI agent deleting a production database
The same method applied to destructive SQL, offline, with the rows read back after each refusal.
Open →