Refund an Order
Process a full refund by creating a return order with negative quantities. Covers the complete refund flow with API examples and payment method requirements.
Overview
A full refund in Surfboard is processed by creating a new order with negative quantities and negative amounts, referencing the original order’s orderId as the purchaseOrderId on each line item. When the payment completes, the full amount is returned to the customer.
When to Use Full Refund
| Scenario | Description |
|---|---|
| Product return | Customer returns all items |
| Service not delivered | Full service cancellation |
| Order error | Wrong order fulfilled entirely |
| Post-settlement reversal | Payment already settled, void no longer possible |
If the payment hasn’t settled yet (same day, before 23:00 UTC), consider using Void a Payment instead — it’s faster and avoids refund processing fees.
Step 1: Create a Refund Order
Create a new order with negative quantity and negative amount.total for each line item. Include the original orderId as purchaseOrderId:
POST /merchants/:merchantId/orders
{
"terminal$id": "YOUR_TERMINAL_ID",
"referenceId": "refund-order-001",
"orderLines": [
{
"id": "ITEM-001",
"purchaseOrderId": "ORIGINAL_ORDER_ID",
"name": "Nike Shoes",
"quantity": -2,
"amount": {
"regular": 10000,
"total": -20000,
"currency": "752",
"tax": [
{ "amount": 4000, "percentage": 25, "type": "VAT" }
]
}
},
{
"id": "ITEM-002",
"purchaseOrderId": "ORIGINAL_ORDER_ID",
"name": "Apple Pods",
"quantity": -1,
"amount": {
"regular": 20000,
"total": -20000,
"currency": "752",
"tax": [
{ "amount": 4000, "percentage": 25, "type": "VAT" }
]
}
}
],
"totalOrderAmount": {
"regular": 30000,
"total": -30000,
"currency": "752",
"tax": [
{ "amount": 8000, "percentage": 25, "type": "VAT" }
]
},
"controlFunctions": {
"initiatePaymentsOptions": {
"paymentMethod": "CARD_NP",
"refundProcessingParams": {
"purchasePaymentId": "ORIGINAL_PAYMENT_ID",
"refundReason": "CUSTOMER_INITIATED_RETURN"
}
}
}
}
// Response
{
"status": "SUCCESS",
"data": {
"orderId": "83b2ca45889a317b0b",
"paymentId": "83b2ca4564bd500606"
},
"message": "Order created successfully"
}
The terminal$id only needs to be a valid terminal — it does not have to be the same terminal that processed the original purchase.
Key details:
- Set
quantityto a negative value to indicate a return - Set
amount.totalto a negative value - Include the original
purchaseOrderIdon each line item totalOrderAmount.totalmust be negative (the refund amount)
Payment Method for Refunds
Set paymentMethod to either the method the customer originally paid with, or CARD_NP:
| Original Payment Method | Refund Method |
|---|---|
| CARD | CARD_NP (recommended) or CARD |
| KLARNA | KLARNA |
| SWISH | SWISH |
| Other digital methods | Same as original |
For card refunds, the two card methods behave differently:
| Method | Behaviour |
|---|---|
CARD_NP | Card not present. Refunds straight back to the card that paid — no terminal interaction. This is the recommended default for card refunds. |
CARD | Card present. Triggers a card tap on the terminal, so a card must be physically presented to receive the refund. |
Note: Transaction fees are charged again on refunds.
Refund Processing Parameters
Pass refund metadata through refundProcessingParams inside initiatePaymentsOptions:
{
"controlFunctions": {
"initiatePaymentsOptions": {
"paymentMethod": "CARD_NP",
"refundProcessingParams": {
"purchasePaymentId": "ORIGINAL_PAYMENT_ID",
"refundReason": "CUSTOMER_INITIATED_RETURN"
}
}
}
}
| Parameter | Required | Description |
|---|---|---|
purchasePaymentId | No | The paymentId of the original purchase (returned when the original order was created). This is the payment-level reference, distinct from the purchaseOrderId you set on each line item. |
refundReason | No | Why the refund is being issued. See the allowed values below. |
otherReason | Conditional | Free-text explanation. Required when refundReason is OTHER. |
Refund Reasons
| Value | Meaning |
|---|---|
CUSTOMER_INITIATED_RETURN | The customer returned the goods or requested the refund. |
SUSPECTED_MALFUNCTION | The product is suspected to be faulty or not working. |
SUSPECTED_FRAUD | The transaction is suspected to be fraudulent. |
DUPLICATE_TRANSACTION | The original charge was a duplicate. |
OTHER | Any other reason — requires a message in otherReason. |
When using OTHER, include the explanation:
{
"controlFunctions": {
"initiatePaymentsOptions": {
"paymentMethod": "CARD_NP",
"refundProcessingParams": {
"purchasePaymentId": "ORIGINAL_PAYMENT_ID",
"refundReason": "OTHER",
"otherReason": "Goodwill credit for delayed delivery"
}
}
}
}
Step 2: Check Refund Status
Verify the refund completed:
GET /merchants/:merchantId/orders/:orderId/status
The order status will show PAYMENT_COMPLETED once the refund is processed. You can also track refund status via webhooks.
Adjustments in Refunds
If the original order included adjustments (tips, discounts), the refund includes them by default. Control this with includeAdjustmentsForRefund:
{
"controlFunctions": {
"includeAdjustmentsForRefund": false,
"initiatePaymentsOptions": {
"paymentMethod": "CARD"
}
}
}
For partial returns, by default the first refund order includes adjustments (true) and subsequent ones do not (false).
Refund via Partner Portal
You can also process refunds through the UI:
- Log in to Partner Portal > Merchants > select merchant > Transactions
- Select the transaction to refund
- Click Create Refund > Full Refund > Process Refund
Refund FAQ
How long after a purchase can I issue a refund? Refunds can be issued up to 90 days after the original purchase. This limit is enforced by Surfboard across all payment methods — there is no difference between card, Swish, Klarna, or other methods. If you need to reverse a transaction older than 90 days (e.g., an event ticket refund a year later), it cannot be processed through the API.
How long does it take for the customer to receive the refund? Processing time depends on the payment method:
Payment Method Refund Timeline Card (CARD, CARD_NP) Up to 7 days. Depends on the issuer and acquirer fraud systems. Swish (SSWISH, NSWISH) Instant Vipps (SVIPPS) Instant MobilePay (SMOBILEPAY) Up to 10 banking days Klarna (KLARNA) Up to 10 days
Reference
Ready to get started?
Create a sandbox account and start building your integration today.