On this page
Error Handling#
The API uses standard HTTP status codes and returns structured JSON error responses. Every error includes a machine-readable error code and a human-readable message.
Response Format#
Success Responses#
All successful responses include a meta object carrying request metadata.
{
"data": {
"id": "abc123",
"name": "Premium Wireless Headphones",
"description": "Noise-cancelling over-ear headphones",
"price": 299.99,
"currency": "USD",
"category": "Electronics"
},
"meta": { "creditsConsumed": 2 }
}Error Responses#
{
"error": "not_found",
"message": "Product not found",
"statusCode": 404
}Error Codes#
| Status | Error | Meaning |
|---|---|---|
| 400 | bad_request | Invalid request body or parameters — check the validation message |
| 401 | unauthorized | Missing or invalid API key |
| 402 | payment_required | Account balance exhausted — the request was not performed |
| 403 | forbidden | API key lacks the required scope, or tier too low |
| 404 | not_found | Resource does not exist or belongs to another account |
| 409 | conflict | Duplicate resource — a product or FAQ with the same identifier exists |
| 429 | too_many_requests | Rate limited — wait for the Retry-After period and retry |
| 500 | internal_error | An unexpected server error — if persistent, contact support |
Handling Errors in Code#
Always check the HTTP status code before parsing the response body:
const response = await fetch(url, {
headers: { "X-API-Key": process.env.GYDR_API_KEY },
})
if (!response.ok) {
const error = await response.json()
console.error(`API error ${error.statusCode}: ${error.message}`)
if (response.status === 429) {
const retryAfter = response.headers.get("Retry-After")
// Wait and retry
}
return
}
const { data } = await response.json()Batch operations: per-row results#
Upsert, bulk delete and reconcile never fail a whole batch because one row is bad. The request returns 200 and each row carries an outcome; failures carry a stable code you can branch on. A failed row is not charged.
| Code | Meaning |
|---|---|
MISSING_MATCH_KEY | The row omitted the field named by matchBy. |
DUPLICATE_IN_BATCH | Two rows in the same request share a key. Both are rejected rather than one silently overwriting the other. |
AMBIGUOUS_MATCH | More than one stored row carries this key. Match on externalId or clean up the duplicates. |
VALIDATION_FAILED | The row failed schema or attribute validation. The offending field is named in validationErrors. |
NOT_FOUND | Delete only — no live row carries this key. |
LIMIT_EXCEEDED | Writing this row would push the knowledge base past its 10,000-item ceiling. |
WRITE_CONFLICT | The row collided with a unique field held by a different row — usually an externalId already in use while matching on sku. Nothing was written and nothing was charged for this row. |
Unknown fields#
A field name we do not recognise is rejected rather than quietly dropped, so a typo surfaces on your first request instead of looking like data loss weeks later. The offending field name is included in the message string.
{
"error": "bad_request",
"message": "Unrecognized field: warehouseCode",
"statusCode": 400
}