Skip to main content
Use refunds to return funds for payments that have reached P_SETTLED. Refund requests are idempotent and must reference the original payment token.
Create refunds only after the payment reaches P_SETTLED.

Create a refund

curl --request POST "{{base_url}}/v1/aggregators/{{aggregator_id}}/refunds" \
  --header "X-SFPY-AGGREGATOR-SECRET-KEY: {{secret_key}}" \
  --header "Content-Type: application/json" \
  --data '{
    "request_id": "{{request_id}}",
    "payment_id": "{{payment_token}}",
    "amount": 500,
    "reason": "DuplicatePayment",
    "addtl_info": "Duplicate charge on invoice INV-1024",
    "debitor_iban": "PK12ALFH0031001006540005"
  }'
const baseUrl = '{{base_url}}';
const aggregatorId = '{{aggregator_id}}';
const secretKey = '{{secret_key}}';

const res = await fetch(`${baseUrl}/v1/aggregators/${aggregatorId}/refunds`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-SFPY-AGGREGATOR-SECRET-KEY': secretKey,
  },
  body: JSON.stringify({
    request_id: crypto.randomUUID(),
    payment_id: '{{payment_token}}',
    amount: 500,
    reason: 'DuplicatePayment',
    addtl_info: 'Duplicate charge on invoice INV-1024',
    debitor_iban: 'PK12ALFH0031001006540005',
  }),
});

if (!res.ok) {
  const error = await res.json();
  throw new Error(`Refund failed: ${res.status} ${error.message}`);
}

const payload = await res.json();
console.log('Refund token', payload.data.token);

Body fields

FieldTypeRequired?Notes
request_idstringYesUUID to guarantee idempotency.
payment_idstringYesToken from the original payment response.
amountintegerYesAmount in paisa; cannot exceed the settled payment amount.
reasonstringYesOne of TechnicalProblem or DuplicatePayment.
debitor_ibanstringYesIBAN that received the original payment.
addtl_infostringOptionalFree-form text for audit logs.

Statuses

Refunds are asynchronous. The API returns a status field; list filters include R_INITIATED, R_COMPLETED, R_FAILED, and R_CANCELED.

Webhook events to expect

  • refund.created
  • refund.completed
  • refund.failed
  • refund.canceled

Key endpoints

EndpointPurpose
POST /v1/aggregators/{{aggregator_id}}/refundsCreate a refund.
GET /v1/aggregators/{{aggregator_id}}/refundsList refunds with filters and pagination.
GET /v1/aggregators/{{aggregator_id}}/refunds/{{refund_id}}Read a single refund.

See also