Skip to Content
RefundsRefunds

Refunds

A refund returns money from a successful charge back to the shopper. Each refund is one attempt, with its own id and its own status, and it always points at the chargeId it belongs to.

You can create refunds through the API, or from your merchant account in Lighthouse . Both produce the same refund object.

When a refund succeeds, Beam records a transaction for it, so the money going out appears in your accounting records the same way the money coming in does. That transaction’s transactionType is either REFUND or VOID. Both mean the refund succeeded, and the refund itself does not tell you which one you will get, so treat them the same. See Transaction types.

A refund never changes the charge it points at. The charge stays SUCCEEDED after a successful refund.

What can be refunded

  • The charge must have status SUCCEEDED. A PENDING or FAILED charge cannot be refunded.
  • Refunds are supported on these payment method types: CARD, CARD_INSTALLMENTS, QR_PROMPT_PAY, ALIPAY, and WECHAT_PAY.
  • Partial refunds are only supported on CARD charges. For every other refundable payment method, one refund has to cover the full amount of the charge.
  • Refunds use your available Beam balance. If your balance is not enough, the request can be rejected.

Refund flow

  1. Shopper asks for a refund: through your support flow, your app, or your own admin tool.

  2. Create the refund: your backend calls POST /api/v1/refunds with the chargeId of the successful charge, and optionally an amount and a reason.

  3. Beam returns the refund id: the refund is created with status PENDING. Store the refundId against your order.

  4. Tell the shopper it is in progress: the refund is not final yet, so do not promise the money has arrived.

  5. Beam submits the refund: this is not instant, and it is not the same as the shopper being paid. How long the money takes to appear depends on the shopper’s bank or wallet provider.

  6. Beam notifies your server: when the refund reaches a final status, Beam sends a webhook to your endpoint.

  7. Your server acknowledges: respond with HTTP 2xx.

  8. Tell the shopper the outcome: on refund.succeeded, tell the shopper the refund is on its way, not that it has arrived. On refund.failed, tell the shopper and create a new refund to retry.

Refund lifecycle

A new refund starts as PENDING. Beam then submits it to the payment provider and moves it to SUCCEEDED or FAILED.

StatusMeaning
PENDINGBeam is still processing the refund and the outcome is not known yet.
SUCCEEDEDThe payment provider accepted the refund. Beam creates a transaction for it.
FAILEDThe refund could not be submitted. See Refund failure codes.

SUCCEEDED and FAILED are final. A refund never changes status again after it reaches one of them.

Important

SUCCEEDED does not mean the shopper has their money back. It means Beam submitted the refund and the payment provider accepted it. The money then moves on the provider’s own schedule, which can take several days depending on the shopper’s bank or wallet.

Beam has no way to confirm that the shopper received the money, and neither the API nor the webhooks report it. Tell the shopper the refund is on its way, not that it has arrived. If they ask when it will arrive, tell them to check with their bank or wallet provider.

Refund failure codes

When a refund is FAILED, the failureCode field says why. There is one code:

failureCodeMeaningWhat to do
RE_PROCESSING_FAILEDThe refund could not be processed.Create a new refund and try again.
Note

A failure code is not an API error. A refund that fails still returns HTTP 2xx on creation, because Beam accepted your request. HTTP 4xx and 5xx responses mean the request itself was rejected: for example 422 with REFUND_PENDING when a refund on that charge is still being processed. See Error Handling.

Track the refund

The create call only tells you the refund exists. To learn the outcome, use webhooks.

Recommended: listen for webhooks. Subscribe to refund.succeeded and refund.failed. Beam calls your endpoint as soon as the refund reaches a final status, so you do not have to ask for it. Record the refund when refund.succeeded arrives, not when the create call returns, because the create call only tells you the refund was accepted.

Fallback: poll the refund. If you cannot receive webhooks yet, call GET /api/v1/refunds/{refundId} until the status is SUCCEEDED or FAILED. Polling costs you requests and delays the outcome, so use it only until your webhook endpoint is ready. Poll with exponential backoff and jitter, because polling too fast gets 429 responses. See Rate limits and retries.

Remember that a final status means the payment provider accepted the refund, not that the shopper has been paid. See Refund lifecycle.

Webhook events for refunds

  • refund.succeeded: the payment provider accepted the refund. It does not confirm the shopper has been paid.
  • refund.failed: the refund could not be submitted.
  • transaction.created: Beam recorded the transaction for a successful refund.

See Event Types for each payload and the Webhook guide for how to set your endpoint up. For which event to act on, see Track the refund.

Next steps

  • Refunds API: the endpoints, with request and response examples.
  • Transactions: how a successful refund appears in your accounting records.
Last updated on