# How do I record a void or reversal of an AI agent's payment on an append-only ledger?

**Short answer:** Don't delete the original payment record, and don't edit it to zero in place. An append-only ledger is built so that changing or removing an entry breaks the hash chain, and even in ordinary books a silent overwrite hides what a reviewer needs to see. Post a new reversing entry that points at the original: its entry id, the reason, who approved the void, and when. Both entries stay visible, and their net (the original amount plus the reversing amount) is what the period should show. Everyday bookkeeping already works this way: QuickBooks Online keeps a voided transaction in your records at zero and marked void; deleting it removes it everywhere except the audit log. On the card rail the same split appears. Stripe lets you cancel a PaymentIntent that has not yet succeeded, but once it has succeeded you create a separate Refund object — you cannot cancel it, you can refund part of what is left, and you cannot refund more than remains on the charge. IAS 8 tells entities to correct material prior-period errors by restating the comparative figures and disclosing the nature and amount of the correction (paragraphs 42 and 49), not by leaving no trace that figures changed. PCAOB AS 1105 asks auditors to test the completeness of company-produced information, and names completeness as the assertion that all transactions that should be presented are included: a deleted payment drops out of the population they sample, while a linked reversal stays in it. On Rightshold, record the original with record_action, then record the reversal under a new client_event_id that names the original event id. Reusing the original key with different content is rejected as a conflict; there is no edit or delete. ledger_verify checks the public ledger those commitments sit on. This page is about reversing a recorded payment. Making the log append-only so an admin can't silently delete entries, catching backdated posts after month-end close, and matching spend to the bank feed are covered on separate pages.

## Checklist
1. Keep the original payment record as it was written: its event id, amount in minor units, currency, payee, time, approver and policy version. Do not edit those fields later.
2. Decide what void means on the payment rail. If the charge was authorized but not captured, cancel it (Stripe: you can cancel a PaymentIntent that has not succeeded; a succeeded PaymentIntent cannot be canceled). If it has already succeeded, create a refund for some or all of the remaining amount — Stripe creates a separate Refund object and will error if you try to refund more than is left.
3. Get a human approval for the void when the original payment needed one, bound to the original entry id, the refund or cancel reference, the amount and the reason.
4. Write the reversal as a new entry with a new client_event_id (for example void:<original_event_id>) and action_type payment.reversed or payment.voided. Name the original event id, the reversing amount and currency, the reason, the approver and the provider's refund or cancel id.
5. If you don't want those details in summary, put them in a private sidecar, hash its exact bytes, and send that SHA-256 as action_sha256. Keep names, emails and account numbers out of summary and client_event_id: recorded events can't be edited or deleted.
6. Never reuse the original client_event_id for the reversal. The same key with the same content comes back as a duplicate of the first receipt (a retry), and the same key with different content is rejected because that key is already bound to different event content.
7. When you report the period, net each original with the reversals that name it. Rightshold does not compute that net, move money or talk to your card provider.
8. Check both receipts: the stream chain for the pair, and ledger_verify for the public commitments. Keep the pair together for as long as you keep the books.

## Why shouldn't I delete or overwrite an AI agent's original payment when I void it?
- A hash-chained log works because each entry commits to the one before it. Removing or editing the original payment changes every hash after it, which is exactly what the log exists to expose. Overwriting the amount to zero in place has the same problem: a later reader sees only the zero, not that a payment was once recorded and then taken back.
- Ordinary books make the same distinction. QuickBooks Online's help (updated 7 September 2026) says that when you void a transaction you keep a record in your books that doesn't affect your totals, that voided transactions are zero and show as void, that you can't undo a void, and that deleting a transaction removes it everywhere except the audit log.
- Card networks keep history the same way. Stripe's refunds documentation says you can cancel a payment before it is completed, but a PaymentIntent can't be canceled after it has succeeded; from then on you create a refund. The Refunds API creates a new Refund object against the original Charge or PaymentIntent. You can refund part of a charge, more than once, until nothing remains, and the API errors if you try to refund more than is left or refund a charge that has already been fully refunded. Some refunds issued shortly after the original charge appear as a reversal (the original charge drops off the customer's statement) rather than a separate credit, but that is still a new Refund object on Stripe's side, not an edit of the charge.
- IAS 8 requires material prior-period errors to be corrected by retrospective restatement in the first statements authorized after discovery, and paragraph 49 requires disclosure of the nature of the error and the amount of the correction. That is about the figures presented in the statements, not a license to erase the underlying entries. PCAOB AS 1105.10 tells the auditor to test the accuracy and completeness of information produced by the company (or the controls over it), and AS 1105.11 defines completeness as the assertion that all transactions that should be presented in the financial statements are included. A payment that was deleted is no longer in that population. A payment that was reversed, with the reversal pointing at it, still is.

## What should a reversing ledger entry for an AI agent's voided payment contain?
- The original entry id (so a reader can join the pair without guessing).
- The reversing amount and currency, equal and opposite for a full void, or the remaining amount for a partial refund. The net of original plus every reversal that names it should be what you report.
- The reason (duplicate payment, order cancelled, goods returned, charged in error) and who approved the void, with the policy version in force at approval time.
- When the reversal was recorded, from a clock you don't control (on Rightshold, received_at is set when the event arrives; occurred_at is the business time you give).
- The provider's reference: a Stripe refund id (re_...) or the canceled PaymentIntent id, so the ledger entry and the rail can be matched.
- A new client_event_id. The original key has to stay bound to the original content; that is how a retry of the original recording stays a retry, and how a later reader can still fetch it.

## What does Rightshold do, and not do, when I record an AI agent payment reversal?
- record_action appends the event you send to your account's private stream and puts a salted commitment to it on the public ledger. The event (action_type, outcome, occurred_at, summary, action_sha256, client_event_id) can't be edited or deleted. A receipt proves what was submitted and when, and that it hasn't changed since. It does not prove the payment or the refund happened.
- Rightshold does not compute original-plus-reversal nets, does not cancel or refund a card charge, and does not talk to Stripe, your bank or your accounting software. Canceling or refunding on the rail, getting approval and adding the two amounts when you report are steps you run around those records.

## Ask Rightshold (free, no key)
Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code (one-click setup: https://www.rightshold.com/start?ref=seo), then ask: "Record a reversal of the agent payment I already logged as act_ORIGINAL. The vendor canceled the order. Name the original entry, the reason, that our Controller approved it, and the Stripe refund id, under a new event key so the original stays as it was written."

```json
{
  "tool": "record_action",
  "arguments": {
    "action_type": "payment.reversed",
    "outcome": "success",
    "occurred_at": "2026-11-08T11:04:00Z",
    "client_event_id": "void:act_ORIGINAL",
    "summary": "Reverses act_ORIGINAL, 150.00 USD, reason: vendor canceled order, approver: Controller, refund: re_STRIPE_REFUND"
  }
}
```
- Needs your API key (or accept_terms:true once to open a free account; the key comes back once). Use a new client_event_id; reusing the original key with different content is rejected.
- Put the original event id, reversing amount, reason, approver and provider refund id in summary, or hash a private sidecar and send action_sha256 (64-character hex). Recorded events can't be edited or deleted.
- ledger_verify is free and keyless and checks the public ledger the commitments sit on.
- Cancel or refund the charge with your payment provider yourself. Rightshold never holds or moves money.

_Rightshold records the events you send in a private, append-only stream and puts a salted commitment to each on its public ledger. It does not edit or delete events, compute original-plus-reversal nets, cancel or refund card charges, or connect to Stripe, your bank or your accounting software. Posting the linked reversal, getting approval and reporting the net are steps you run. Not accounting, tax, audit or legal advice._

## Sources
- [QuickBooks Online: Void or delete transactions (void keeps a zeroed record; delete removes it except from the audit log; updated 7 September 2026)](https://quickbooks.intuit.com/learn-support/en-us/help-article/list-management/void-delete-transactions-quickbooks-online/L5sZV8GYh_US_en_US)
- [Stripe Docs: Refund and cancel payments (cancel before completion; a succeeded PaymentIntent can't be canceled; create a Refund afterwards; partial refunds; some refunds appear as reversals)](https://docs.stripe.com/refunds)
- [Stripe API: Create a refund (separate Refund object; cannot refund more than remains; reason may be duplicate, fraudulent or requested_by_customer)](https://docs.stripe.com/api/refunds/create)
- [IFRS Foundation: IAS 8 Basis of Preparation of Financial Statements (paragraphs 42 and 49: retrospective restatement and disclosure of prior-period errors)](https://www.ifrs.org/content/dam/ifrs/publications/html-standards/english/2026/issued/ias8.html)
- [PCAOB: AS 1105, Audit Evidence (paragraph .10, accuracy and completeness of company-produced information; paragraph .11, completeness assertion)](https://pcaobus.org/oversight/standards/auditing-standards/details/AS1105)
- [Operations records on Rightshold](https://www.rightshold.com/operations)

## Related
- [How to make an AI agent's audit log append-only so even an admin can't silently delete entries](https://www.rightshold.com/answers/how-to-make-an-ai-agents-audit-log-append-only-so-even-an-admin-cant-silently-delete-entries)
- [How to catch backdated entries posted into a closed month after month-end close](https://www.rightshold.com/answers/how-to-catch-backdated-entries-posted-into-a-closed-month-after-month-end-close)
- [How to reconcile an AI agent's spend against the bank feed at month end](https://www.rightshold.com/answers/how-to-reconcile-an-ai-agents-spend-against-the-bank-feed-at-month-end)
- [How to stop two AI agents from paying the same vendor invoice twice](https://www.rightshold.com/answers/how-to-stop-two-ai-agents-from-paying-the-same-vendor-invoice-twice)

_Not legal advice. Updated 2026-11-08. JSON: https://www.rightshold.com/answers/how-to-record-a-void-or-reversal-of-an-ai-agents-payment-on-an-append-only-ledger.json_