Skip to main content
Authenticated API

This endpoint requires a valid JWT Bearer token. Accessible via the API gateway at /v1/commerce/*.

Refunds API

Process refunds, voids, handle chargebacks, and manage return policies.

Financial Operations

Refund and void operations process real financial transactions. All operations are audit-logged, require manager authorization above configurable thresholds, and cannot be reversed once completed. Ensure refund policies are properly configured before processing.

Overview

AttributeValue
Base Path/api/v1/refunds
AuthenticationBearer Token
Required Rolesstaff, finance, restaurant_manager, tenant_admin, platform_admin, system_admin, super_admin

Refunds

List Refunds

GET /api/v1/refunds

Query Parameters

ParameterTypeDescription
location_iduuidFilter by location
statusstringpending, completed, failed
typestringfull, partial, void
start_datedatePeriod start
end_datedatePeriod end
employee_iduuidFilter by processor

Response

{
"refunds": [
{
"id": "refund_001",
"order_id": "ord_12345",
"order_number": "42",
"type": "partial",
"status": "completed",
"amount": 25.50,
"original_amount": 85.50,
"reason": "item_quality",
"reason_detail": "Steak overcooked",
"items_refunded": [
{
"item_id": "item_001",
"name": "Ribeye Steak",
"quantity": 1,
"amount": 25.50
}
],
"payment_method": {
"type": "card",
"brand": "visa",
"last4": "4242"
},
"processed_by": {
"id": "emp_005",
"name": "Manager Mike"
},
"processed_at": "2026-01-24T19:30:00Z"
}
],
"summary": {
"total_count": 15,
"total_amount": 425.50,
"by_reason": {
"item_quality": 8,
"customer_changed_mind": 4,
"wrong_item": 3
}
}
}

Create Refund

POST /api/v1/refunds

Request Body

{
"order_id": "ord_12345",
"type": "partial",
"items": [
{
"order_item_id": "oi_001",
"quantity": 1,
"amount": 25.50
}
],
"reason": "item_quality",
"reason_detail": "Steak was overcooked, customer complained",
"refund_to": "original_payment",
"notify_customer": true,
"manager_pin": "1234"
}

Response

{
"id": "refund_001",
"order_id": "ord_12345",
"type": "partial",
"status": "completed",
"amount": 25.50,
"refund_breakdown": {
"items": 23.50,
"tax": 2.00,
"tip_adjustment": 0
},
"payment_refund": {
"payment_id": "pay_abc123",
"refund_id": "re_stripe_xyz",
"method": "card",
"status": "succeeded",
"estimated_arrival": "3-5 business days"
},
"receipt_url": "https://...",
"processed_at": "2026-01-24T19:30:00Z"
}

Get Refund

GET /api/v1/refunds/{refund_id}

Response

{
"id": "refund_001",
"order_id": "ord_12345",
"order_number": "42",
"type": "partial",
"status": "completed",
"amount": 25.50,
"original_order": {
"subtotal": 78.50,
"tax": 6.28,
"tip": 15.70,
"total": 100.48
},
"refund_breakdown": {
"items": 23.50,
"tax": 2.00,
"tip_adjustment": 0,
"total": 25.50
},
"items_refunded": [
{
"order_item_id": "oi_001",
"item_id": "item_001",
"name": "Ribeye Steak",
"original_price": 35.00,
"quantity_ordered": 1,
"quantity_refunded": 1,
"refund_amount": 23.50,
"modifiers_refunded": [
{"name": "Medium Rare", "amount": 0}
]
}
],
"reason": "item_quality",
"reason_detail": "Steak was overcooked, customer complained",
"reason_category": "food_quality",
"customer": {
"id": "cust_abc",
"name": "John Smith",
"email": "john@example.com",
"notified": true
},
"payment_details": {
"original_payment_id": "pay_abc123",
"refund_transaction_id": "re_stripe_xyz",
"method": "card",
"brand": "visa",
"last4": "4242",
"status": "succeeded",
"refunded_at": "2026-01-24T19:30:05Z"
},
"processed_by": {
"employee_id": "emp_005",
"name": "Manager Mike",
"role": "shift_manager"
},
"approval": {
"required": true,
"approved_by": "emp_005",
"approval_method": "manager_pin"
},
"audit": {
"created_at": "2026-01-24T19:30:00Z",
"ip_address": "192.168.1.100",
"device": "POS Terminal 1"
},
"receipt_url": "https://..."
}

Full Refund

POST /api/v1/refunds/full

Request Body

{
"order_id": "ord_12345",
"reason": "customer_dissatisfied",
"reason_detail": "Overall experience was poor",
"refund_tip": true,
"manager_pin": "1234",
"notify_customer": true
}

Voids

Void Order

POST /api/v1/refunds/void

Request Body

{
"order_id": "ord_12346",
"reason": "duplicate_order",
"reason_detail": "Order was entered twice by mistake",
"manager_pin": "1234"
}

Response

{
"id": "void_001",
"order_id": "ord_12346",
"type": "void",
"status": "completed",
"amount": 45.50,
"payment_void": {
"payment_id": "pay_def456",
"status": "voided",
"note": "Payment authorization released"
},
"voided_at": "2026-01-24T19:35:00Z"
}

Void Item

POST /api/v1/refunds/void-item

Request Body

{
"order_id": "ord_12345",
"order_item_id": "oi_002",
"reason": "wrong_item",
"reason_detail": "Server entered wrong item",
"manager_pin": "1234"
}

Chargebacks

Chargeback Deadlines

Chargebacks have strict response deadlines imposed by card networks. Failing to respond before the deadline date will result in an automatic loss. Monitor the deadline field and submit evidence promptly.

List Chargebacks

GET /api/v1/refunds/chargebacks

Query Parameters

ParameterTypeDescription
statusstringopen, won, lost, pending
start_datedatePeriod start

Response

{
"chargebacks": [
{
"id": "chbk_001",
"order_id": "ord_11111",
"amount": 125.50,
"reason_code": "fraudulent",
"reason": "Cardholder claims transaction not authorized",
"status": "open",
"deadline": "2026-02-15",
"payment_details": {
"payment_id": "pay_xyz789",
"brand": "visa",
"last4": "1234"
},
"evidence_submitted": false,
"opened_at": "2026-01-20T00:00:00Z"
}
],
"summary": {
"open": 2,
"pending": 1,
"won_ytd": 5,
"lost_ytd": 2,
"total_disputed_ytd": 2500.00
}
}

Get Chargeback

GET /api/v1/refunds/chargebacks/{chargeback_id}

Response

{
"id": "chbk_001",
"order_id": "ord_11111",
"amount": 125.50,
"currency": "USD",
"reason_code": "fraudulent",
"reason": "Cardholder claims transaction not authorized",
"status": "open",
"deadline": "2026-02-15T23:59:59Z",
"order_details": {
"order_number": "125",
"date": "2026-01-15",
"items": [
{"name": "Ribeye Steak", "quantity": 2, "price": 70.00},
{"name": "Wine Bottle", "price": 45.00}
],
"subtotal": 115.00,
"tax": 10.50,
"total": 125.50
},
"customer": {
"name": "Jane Doe",
"email": "jane@example.com"
},
"payment_details": {
"payment_id": "pay_xyz789",
"brand": "visa",
"last4": "1234",
"cardholder_name": "JANE DOE"
},
"evidence": {
"submitted": false,
"available_documents": [
"signed_receipt",
"customer_communication",
"delivery_confirmation"
]
},
"timeline": [
{
"event": "chargeback_opened",
"timestamp": "2026-01-20T00:00:00Z",
"details": "Chargeback received from card network"
}
],
"recommendation": {
"action": "submit_evidence",
"reason": "Order has signed receipt and matches cardholder name",
"win_likelihood": "high"
}
}

Submit Chargeback Evidence

POST /api/v1/refunds/chargebacks/{chargeback_id}/evidence

Request Body

{
"evidence_type": "dispute_response",
"documents": [
{
"type": "signed_receipt",
"file_id": "file_001"
},
{
"type": "customer_signature",
"file_id": "file_002"
}
],
"statement": "Customer dined in and signed receipt. Transaction is legitimate.",
"additional_info": {
"customer_ip": "192.168.1.50",
"service_date": "2026-01-15",
"server_name": "Sarah Johnson"
}
}

Accept Chargeback

POST /api/v1/refunds/chargebacks/{chargeback_id}/accept

Request Body

{
"reason": "Unable to provide sufficient evidence"
}

Refund Policies

Get Refund Policies

GET /api/v1/refunds/policies

Response

{
"policies": [
{
"id": "policy_001",
"name": "Standard Refund Policy",
"type": "default",
"rules": {
"max_refund_age_hours": 24,
"require_manager_approval": {
"always": false,
"threshold_amount": 50.00,
"threshold_percent": 50
},
"allowed_reasons": [
"item_quality",
"wrong_item",
"customer_changed_mind",
"service_issue",
"other"
],
"tip_refund": {
"allowed": true,
"auto_adjust": true
},
"partial_refunds": {
"allowed": true,
"min_amount": 1.00
}
},
"restrictions": {
"no_refund_items": ["gift_cards", "alcohol"],
"final_sale_categories": []
},
"active": true
}
]
}

Update Refund Policy

PUT /api/v1/refunds/policies/{policy_id}

Reports

Get Refund Report

GET /api/v1/refunds/reports

Query Parameters

ParameterTypeDescription
location_iduuidFilter by location
start_datedatePeriod start
end_datedatePeriod end
group_bystringday, reason, employee

Response

{
"period": {
"start": "2026-01-01",
"end": "2026-01-24"
},
"summary": {
"total_refunds": 85,
"total_voids": 12,
"total_amount": 2450.00,
"refund_rate": 0.015,
"avg_refund_amount": 28.82
},
"by_reason": [
{
"reason": "item_quality",
"count": 35,
"amount": 980.00,
"percent": 40
},
{
"reason": "wrong_item",
"count": 25,
"amount": 720.00,
"percent": 29.4
},
{
"reason": "customer_changed_mind",
"count": 15,
"amount": 450.00,
"percent": 18.4
},
{
"reason": "service_issue",
"count": 10,
"amount": 300.00,
"percent": 12.2
}
],
"by_employee": [
{
"employee_id": "emp_001",
"name": "Sarah Johnson",
"refunds_processed": 12,
"amount": 340.00
}
],
"trends": {
"vs_last_period": "+5%",
"highest_day": "2026-01-15",
"highest_day_amount": 185.00
},
"action_items": [
{
"type": "high_refund_item",
"item": "Ribeye Steak",
"refund_count": 8,
"recommendation": "Review preparation consistency"
}
]
}

Webhooks

EventDescription
refund.createdNew refund processed
refund.completedRefund completed
refund.failedRefund failed
void.createdOrder voided
chargeback.openedNew chargeback received
chargeback.resolvedChargeback resolved

Error Responses

StatusCodeDescription
400refund_exceeds_amountRefund exceeds available amount
400order_already_refundedOrder already fully refunded
403manager_approval_requiredManager approval needed
404order_not_foundOrder not found
409payment_not_refundablePayment cannot be refunded
422refund_window_expiredOutside refund window