Skip to content
Founding beta: 7 of 50 free spots leftClaim yours

Refund reasons you can correct later, and a webhook when they change

Feature buildMediumPython · FastAPIPaymentsData integrityTesting45 min

Refund reasons: correct them later, and tell merchants when they change

Owner: Dana (product, payments) · Status: Shaped · Appetite: one round, API only

Goal

Merchants' support teams often pick the wrong reason when they refund, or none at all, and then have no way to fix it. Finance reconciles refunds by reason at month end and their integrations want to hear about corrections. Two merchants asked for this in the same week:

"Our agents hit Refund in a hurry and choose 'duplicate' for anything. At month end we want to fix those, and for the odd ones we need to write down what really happened, like 'goodwill, late delivery'. And when someone changes it, our accounting system should hear about it by webhook like it does for everything else." (Northwind)

"We use the refund list to build our returns report. We would love to filter it by reason." (Sakura)

Requirements

What good looks like:

  • A refund's reason can be added, changed or removed after the refund was made.
  • There is a fifth, catch-all reason other, which comes with a short written note.
  • Merchants can see the note on the refund, list refunds by reason, and subscribe to a webhook for changes.

Decided (these are what we ship; reasons in brackets):

  1. New reason value other next to the three that exist. A refund with the reason other must carry a note in a new field reason_note (1-200 characters). A note is only allowed together with other. Setting other without a note is a missing-parameter error on reason_note; a note with any other reason, or with no reason, is an invalid-parameter error on reason_note. Refund objects show reason_note (null when there is none). [Finance needs to see why "other" was chosen.]
  2. Refunds can be updated with POST /v1/refunds/{id}, changing only reason, reason_note and metadata. Fields that are not sent stay as they are. metadata merges like on customers (an empty value removes a key). Sending reason: null removes the reason and its note. Moving a refund away from other drops its note by itself. The amount, currency, status and payment can never be changed (like any unknown field, they are refused). [A reason is a label; money must not move through this call.]
  3. A new event charge.refund.updated is recorded when an update changes something. Its data.object is the refund after the change. An update that changes nothing records nothing. Creating a refund does not record it. Merchants can put it in a webhook endpoint's enabled_events like any other event and * includes it. [Same rule as customer.updated; the name matches what merchants moving from Stripe already listen for.]
  4. GET /v1/refunds accepts reason as a filter (one of the four values; anything else is an invalid parameter). It combines with the existing payment_intent filter and with paging.
  5. Everything the API promises elsewhere applies: another merchant's refund looks missing, updates take an Idempotency-Key, errors have the usual shape, and nothing that works today changes.

Open questions

  • Should a merchant be able to see who changed a reason? (Not now; Dana will ask finance.)
  • Should changing a reason also notify the customer? (No, out of scope.)
  • How do we explain to integrators the difference between refund.created and the new event? (Builder: note it wherever the API's behaviour is documented in the repo.)

No-gos

  • No dashboard changes, no new roles, no changing refund amounts or statuses, no soft delete.

Acceptance

  • A refund can get a reason after creation; the change is visible on the refund, in the event list and as a delivery for subscribed endpoints.
  • other without a note, and notes on other reasons, are refused with the errors above, and refused requests change nothing.
  • The reason filter works, and the existing refund behaviour (limits, balance, refund.created) is untouched.
  • Add tests for what you build.

© AICodingRound. Ticket text for practice on this site; see Terms.

How it works

  1. 1Fix the problemin a real codebase.
  2. 2Use your ownAI, or none.
  3. 3Submit, then answera few short questions.
  4. 4Get your gradeand feedback.

Guides that use this problem

All guides

More on Paylane payments

View all

Related problems

View all