Errors
Status codes, error shape, and how to handle each kind.
Error response shape
Errors return a JSON object with at minimum:
{
"error": "human-readable message",
"code": "machine-readable code"
}The HTTP status code drives behavior; the error message is for logs; the code is what you branch on.
Status code reference
| Status | code | Meaning | Retry? |
|---|---|---|---|
400 | bad_request | Invalid identifier or query param | No (fix client) |
401 | unauthorized | Missing / malformed bearer | No (check key) |
403 | forbidden | Key revoked, scope mismatch, or out of quota | No |
404 | not_found | Identifier not in our catalog | No |
402 | payment_required | Account past due | After billing fixed |
429 | rate_limited | Throttle or monthly quota exceeded | Yes (Retry-After) |
500 | internal_error | Our problem; check status page | Yes (with backoff) |
502 | upstream_unavailable | Walmart backend transient issue | Yes (with backoff) |
503 | service_unavailable | Maintenance or capacity | Yes (with backoff) |
504 | upstream_timeout | Walmart backend slow | Yes (with backoff) |
Customer-safe upstream messages
retailerapi never echoes raw upstream error messages back to your client. We map upstream failures to canonical messages:
404upstream — "Product not found"401/403upstream — "Service authentication failed" (you don't see our internal auth issues)429upstream — "Rate limited, retry shortly"5xxupstream — "Service temporarily unavailable"
Recommended retry policy
async function callWithRetry(url, opts, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const r = await fetch(url, opts);
if (r.status < 500 && r.status !== 429) return r; // not retriable
if (r.status === 429) {
const retryAfter = Number(r.headers.get('Retry-After') ?? '5');
await sleep(retryAfter * 1000);
continue;
}
if (r.status >= 500 && attempt < maxRetries) {
await sleep(2 ** attempt * 500); // exponential backoff
continue;
}
return r; // give up
}
}Sentry / error tracking
retailerapi's own server errors are tracked in Sentry. We do NOT log your request bodies, only stack traces and route names. If you encounter a persistent 500 on a specific identifier, email hello@retailerapi.com with the identifier and we'll investigate.