Appearance
Error Handling
The Shopwave API uses standard HTTP status codes combined with a structured error body. This page covers the error format, common status codes, and best practices for robust error handling.
Error response format
Error responses follow a consistent structure with an error object and the standard api envelope:
json
{
"error": {
"code": 400,
"message": "Validation failed",
"details": [
"name is required",
"storeId must be an integer"
]
},
"api": {
"message": {
"error": {
"101": {
"id": 101,
"code": "validationError",
"statusCode": 400,
"title": "Validation failed",
"details": "One or more fields failed validation."
}
}
},
"codeBaseVersion": "2.0",
"executionTime_milliSeconds": 12
}
}The error object
| Field | Type | Description |
|---|---|---|
code | integer | HTTP status code or application-specific error code |
message | string | Human-readable summary of the error |
details | string[] | Array of specific error messages (e.g. per-field validation failures) |
The api envelope
The api.message object may contain an error map even on partially successful requests. Always check this alongside the HTTP status code.
Each API message has:
| Field | Type | Description |
|---|---|---|
id | integer | Unique message identifier |
code | string | Machine-readable code (e.g. tokenValid, validationError) |
statusCode | integer | Associated HTTP status code |
title | string | Short human-readable title |
details | string | Detailed explanation |
objectRef | string | Reference to the specific object this error relates to (useful in batch operations) |
HTTP status codes
| Status | Name | When it occurs |
|---|---|---|
200 | OK | Successful GET request |
201 | Created | Resource successfully created or updated (POST/PUT) |
205 | Reset Content | Resource successfully deleted (DELETE) |
400 | Bad Request | Malformed request body or invalid data |
401 | Unauthorized | Missing, invalid, or expired authentication token |
403 | Forbidden | Valid token but insufficient permissions (wrong scope or role) |
404 | Not Found | Requested resource does not exist |
415 | Unsupported Media Type | Invalid file type on upload (/uploader) |
422 | Unprocessable Entity | Request is well-formed but contains semantic errors (e.g. missing required fields) |
500 | Internal Server Error | Unexpected server error |
205 for deletes
Shopwave returns 205 Reset Content for successful deletions, not the more common 204 No Content. The response body still includes the api envelope.
Example error responses
401 — Invalid token
json
{
"error": {
"code": 401,
"message": "Authentication is missing or the token is invalid/expired"
},
"api": {
"message": {
"error": {
"100": {
"id": 100,
"code": "tokenInvalid",
"statusCode": 401,
"title": "Token is invalid",
"details": "The provided token could not be validated."
}
}
},
"codeBaseVersion": "2.0",
"executionTime_milliSeconds": 3
}
}403 — Insufficient scope
json
{
"error": {
"code": 403,
"message": "The authenticated user does not have permission to perform this action"
},
"api": {
"message": {
"error": {
"103": {
"id": 103,
"code": "insufficientScope",
"statusCode": 403,
"title": "Insufficient scope",
"details": "This operation requires the 'admin' scope."
}
}
},
"codeBaseVersion": "2.0",
"executionTime_milliSeconds": 5
}
}422 — Validation errors
json
{
"error": {
"code": 422,
"message": "Validation failed",
"details": [
"title is required",
"startDate must be a valid ISO 8601 date-time",
"endDate must be after startDate"
]
},
"api": {
"message": {
"error": {
"110": {
"id": 110,
"code": "validationError",
"statusCode": 422,
"title": "Unprocessable entity",
"details": "The request body contains semantic errors."
}
}
},
"codeBaseVersion": "2.0",
"executionTime_milliSeconds": 8
}
}Partial failures in batch operations
When submitting multiple objects in a single POST request, some may succeed while others fail. In this case:
- The HTTP status is still
201 - Successful objects appear in the response data as normal
- Failed objects appear in
api.message.errorwith theirobjectRefmatching your request key
json
{
"products": {
"valid-product": {
"id": 135594,
"name": "New Burger"
}
},
"api": {
"message": {
"success": {
"200": {
"id": 200,
"title": "Product created",
"objectRef": "valid-product"
}
},
"error": {
"110": {
"id": 110,
"code": "validationError",
"statusCode": 422,
"title": "Validation failed",
"details": "name is required",
"objectRef": "invalid-product"
}
}
},
"codeBaseVersion": "2.0",
"executionTime_milliSeconds": 45
}
}Always check api.message.error
Even on 200 and 201 responses, partial failures can occur. Always inspect api.message.error to catch items that were silently rejected.
Handling errors in client code
js
async function shopwaveRequest(endpoint, options = {}) {
const response = await fetch(`https://api.staging.merchantstack.com${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${accessToken}`,
'x-accept-version': '2.0',
'Content-Type': 'application/json',
...options.headers
}
})
const data = await response.json()
// Handle HTTP-level errors
if (!response.ok) {
const message = data.error?.message || response.statusText
const details = data.error?.details || []
throw new Error(`${response.status}: ${message} — ${details.join(', ')}`)
}
// Check for partial failures in the API envelope
const apiErrors = data.api?.message?.error
if (apiErrors) {
console.warn('Partial failures:', apiErrors)
}
return data
}bash
# Use -w to print the HTTP status code alongside the response
curl -s -w "\nHTTP Status: %{http_code}\n" \
https://api.staging.merchantstack.com/product \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "x-accept-version: 2.0" | jq .Best practices
- Check both the HTTP status and the
api.message.errorobject — a201response can still contain partial failures - Use the
detailsarray — it provides specific, actionable error messages (e.g. which fields failed validation) - Handle 401 gracefully — implement automatic token refresh when you receive an expired token error
- Don't retry 4xx errors blindly — these indicate a problem with your request. Fix the input before retrying
- Retry 500 errors with backoff — server errors are usually transient. Retry with exponential backoff up to a reasonable limit
- Log the
executionTime_milliSeconds— useful for monitoring API performance from your application - Use
objectRef— in batch operations, match errorobjectRefvalues back to your original request keys to identify which items failed