PerxDevelopers

Building the integration

Refunds & voids

Reverse the points a sale earned, and re-credit any reward that was redeemed against it.

POST/webhooks/genericorPOST/v1/refundComing
Not yet enabled in production

The refund path is built and in review. The shape below is final — build your sender against it now and Perx will confirm the enablement date. Until then, send only sale.completed.

Sending a refund

Send sale.refunded when a sale is refunded, whole or in part. Perx reverses the points earned on the original sale — proportionally for a partial refund — and re-credits any points reward redeemed against it.

{
  "eventId": "evt_2026-08-27_00099",
  "eventType": "sale.refunded",
  "occurredAt": "2026-08-27T11:02:10Z",
  "store": { "id": "12345" },
  "transaction": {
    "id": "INV-2026-0042",
    "currency": "MVR"
  },
  "refund": {
    "id": "CRN-2026-0007",
    "amount": 45.00
  }
}
FieldReqNotes
transaction.idyesThe original sale’s id, exactly as sent on the earn event. This is how Perx finds what to reverse.
refund.idyesUnique id for this refund — the idempotency key for the reversal.
refund.amountnoOmit for a full refund. When present, points reverse in proportion to the original order total.

Response statuses

statusMeaning
REVERSEDPoints removed and/or re-credited as shown.
ALREADY_PROCESSEDThis refund.id was already handled. Success.
NOTHING_TO_REVERSENo matching earn or redemption — e.g. the original sale never reached Perx. Not an error.

Voids and cancellations

  • A void before you ever sent the sale needs no event at all — just do not send the sale.
  • A void after you sent sale.completed should go as sale.refunded with the full amount.
  • sale.voided is accepted and ignored. It is useful as a harmless no-op for a “Test connection” button in your settings screen.

Edge cases you do not have to handle

  • Refunding more than was earned. If the customer has already spent those points, Perx applies the merchant’s underflow policy. Do not check balances first.
  • Refund arriving before its sale. Handled — ordering is not required.
  • Two partial refunds of one sale. Distinct events, because idempotency is on refund.id, not transaction.id.