Merchant API errors
July 30, 2026
HTTP status codes of the FlowAlp Pay Merchant API, the JSON error response shape, and practical retry guidance with exponential backoff.
When a Merchant API call fails, the response combines an HTTP status code with a JSON body that explains the problem. This page lists the status semantics, the error shape, and how to retry safely.
Since API v1.15, failed requests return a status code specific to the failure instead of a generic response — see API versions and changelog.
HTTP status codes
| Status | Meaning | What to do |
|---|---|---|
200 OK | Request processed; check the status field in the body | Continue your flow |
400 Bad Request | Malformed or invalid request (fields, types, encoding) | Fix the payload; do not retry unchanged |
401 Unauthorized | Missing or invalid credentials | Check API secret and auth method; do not retry unchanged |
403 Forbidden | Access denied; also follows sustained overload at the platform edge | Verify permissions and instance; under high volume, back off and retry |
404 Not Found | Unknown resource, ID or path | Check Object, id and version segment |
405 Method Not Allowed | Wrong HTTP verb; also an early rate-limit signal under load | Check the verb mapping; under high volume, back off |
429 Too Many Requests | Standard rate-limit status | Back off and retry later |
5xx | Temporary server-side problem | Retry with exponential backoff |
The documented rate limit surfaces as 405 followed by 403 while the limit stays exceeded; if you ever receive 429, treat it the same way. Details: Merchant API rate limits.
Error response shape
Failed calls return a JSON body with a status field and a human-readable explanation, typically in a message field:
{
"status": "error",
"message": "Description of what went wrong"
}Successful calls return "status": "success" plus a data array. Evaluate the HTTP status code first, then the body. Message texts are not part of the API contract — branch on status codes, never on message strings.
Retry guidance
| Failure class | Retry? | How |
|---|---|---|
400 / 401 / 404 — validation and auth errors | No | Fix the request or credentials first |
405 / 403 under high volume, 429 | Yes | Exponential backoff with jitter |
5xx and network timeouts | Yes | Exponential backoff; cap the attempts |
A proven starting point: initial delay 500 ms, doubling per attempt, random jitter of up to 300 ms, maximum delay 30 s, at most 5 attempts. Make retried operations idempotent in your own system, for example by deduplicating on referenceId.
<?php
function callWithBackoff(callable $request, int $maxAttempts = 5)
{
$delayMs = 500;
for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
[$status, $body] = $request();
if ($status < 400) {
return $body;
}
$retriable = in_array($status, [403, 405, 429], true) || $status >= 500;
if (!$retriable || $attempt === $maxAttempts) {
throw new RuntimeException('FlowAlp Pay request failed: HTTP ' . $status);
}
usleep(($delayMs + random_int(0, 300)) * 1000);
$delayMs = min($delayMs * 2, 30000);
}
}response=$(curl --silent --write-out "\n%{http_code}" \
--url "https://api.pay.flowalp.com/v1.16/Transaction/<transaction-id>/?instance=<instance>" \
--header "x-api-key: <api-secret>")
body=$(printf '%s' "$response" | head -n -1)
status=$(printf '%s' "$response" | tail -n 1)
echo "HTTP $status"
echo "$body"Diagnose authentication failures
- Run the SignatureCheck smoke test to separate credential problems from endpoint problems.
- Verify that the instance name matches the subdomain of your payment page.
- In signature mode, compare your query-string encoding with the reference implementation in Merchant API authentication.
Logging best practices
- Log HTTP status, resource path and your correlation ID (for example
referenceId) — never the API secret orApiSignature. - Separate validation errors from authentication errors in your metrics.
- Prefer webhooks over aggressive polling so transient errors have less impact.
Related: Merchant API rate limits, Request format, First API request.