Issue a refund
Reverse a captured Transfer in part or in full.
Goal
Refund a successful charge back to the original payment method, in part or in full. Refunds in Easy Labs are first-class Transfers themselves (with type: "REVERSAL") — they link to the original via parent_transfer, fire their own webhooks, and settle on their own timeline. This guide covers the most common cases: full refund of a recent charge, partial refund (e.g. one returned line item), and detecting that a refund has finished.
Prerequisites
- Easy Labs API key — see Quickstart.
@easylabs/nodeinstalled.- The
transferIdof the original successful charge. From an Order, this isorder.transfer.id.
Implementation
1. Issue a full refund
import { createClient } from "@easylabs/node";
const easy = await createClient({ apiKey: process.env.EASY_API_KEY! });
const { data: original } = await easy.getTransfer(transferId);
const { data: refund } = await easy.createRefund(transferId, {
refund_amount: original.amount, // full amount, in the smallest currency unit
});
// refund.id is the new reversal Transfer.
// refund.parent_transfer === transferIdThe reversal is created in the PENDING state and progresses to SUCCEEDED once the issuer accepts it. The original Transfer's state moves to REVERSED once fully reversed.
2. Issue a partial refund
const { data: partial } = await easy.createRefund(transferId, {
refund_amount: 1000, // $10.00 of the original $50.00 charge
tags: { reason: "returned_one_item", internal_rma_id: "RMA-789" },
});You can issue multiple partial refunds against the same original Transfer up to the original amount. After the sum of reversals equals the original amount, the original transitions to REVERSED.
3. (Optional) Subscribe to the refund webhook
If you want server-side confirmation rather than polling, subscribe to refund.created and refund.updated:
import { EasyWebhooks } from "@easylabs/node";
app.post("/webhooks/easy", async (req, res) => {
const event = EasyWebhooks.constructEvent(
req.rawBody,
req.header("x-easy-webhook-signature") ?? "",
process.env.EASY_WEBHOOK_SECRET!,
);
if (event.type === "refund.updated") {
// event.data is the reversal Transfer
}
res.status(204).end();
});4. Verify in the dashboard
Open the original Order in the Easy Labs dashboard — you will see the linked reversal under "Refunds" with its own state and amount.
Tradeoffs
- Refunds always go back to the original Payment Instrument; you cannot re-route a refund to a different card or to a wallet.
- Crypto Orders are not refundable through
createRefund. For confirmed on-chain payments, open a support ticket and reconcile off-chain. - Refunds fire
refund.created/refund.updatedevents, NOTpayment.updatedevents. Wire up the right handler. - A failed refund (issuer rejects) sets the reversal's
statetoFAILED; the original Transfer is unchanged. Surface thefailure_messageto your ops team.