SettleFlow API

Error Handling

Understanding API error responses

Error Format

All API errors return a consistent JSON format:

{
  "code": "VALIDATION_ERROR",
  "message": "Invalid currency code",
  "details": { "field": "currency" },
  "requestId": "req_abc123"
}

Error Codes

HTTP StatusCodeDescription
400VALIDATION_ERRORRequest body or parameters are invalid
401UNAUTHORIZEDMissing or invalid API key
403FORBIDDENAPI key does not have permission for this action
404NOT_FOUNDThe requested resource does not exist
409CONFLICTThe request conflicts with the current state (e.g., double capture)
500INTERNAL_ERRORAn unexpected error occurred on our side

Refund limits

A merchant account can carry a maximum number of refunds per day. Once it is reached, every refund you request answers 400:

{
  "code": "VALIDATION_ERROR",
  "message": "Daily refund limit reached: 20 of 20 refunds already requested today. Contact us to refund more today.",
  "details": { "reason": "DAILY_REFUND_LIMIT_REACHED", "limit": 20, "used": 20 },
  "requestId": "req_abc123"
}

Branch on details.reason rather than on the message. The counter covers the refunds you request — from the API or from your dashboard — over a UTC calendar day, and resets at 00:00 UTC. A partial refund counts as one, like a full one. Failed refunds do not count. Refunds initiated by the payment provider are never blocked and never count against it.

Retrying does not help before the next UTC day: contact us to have the limit raised or lifted.

Declined refunds

When the payment provider refuses a refund, the refund endpoint answers 400:

{
  "code": "VALIDATION_ERROR",
  "message": "Refund declined by the payment provider: Refund declined by issuer",
  "details": { "reason": "REFUND_DECLINED_BY_PSP", "pspMessage": "Refund declined by issuer" },
  "requestId": "req_abc123"
}

No money moved. The attempt is recorded and shows as failed on the payment's refund list; it does not count against your daily refund limit. In sandbox, trigger this case with the test card 4000000000005126 (the payment succeeds, any refund of it is declined).

Handling Errors

const response = await fetch("https://api.settleflow.io/v2/payments", {
  method: "POST",
  headers: {
    "X-Api-Key": apiKey,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(payload),
});

if (!response.ok) {
  const error = await response.json();
  console.error(`${error.code}: ${error.message}`);
  // Handle specific error codes
  if (error.code === "VALIDATION_ERROR") {
    // Show validation errors to the user
  }
}

Request IDs

Error responses carry a requestId, as in the example above. Successful responses do not.

You can also set your own on the way in, with an X-Request-Id header, and it will be the one echoed back on an error — useful for stitching a failure to the call in your own logs.

On this page