Error Response Format
All errors return a JSON object with a single error key containing a human-readable message:
{
"error": "Product not found"
}
Status Codes
The API uses standard HTTP status codes:
| Code | Meaning |
|---|---|
| 200 | Success (read/update) |
| 201 | Created |
| 204 | No content (successful delete) |
| 400 | Bad request (malformed JSON) |
| 401 | Authentication missing or invalid |
| 402 | Preview-tier cap exceeded (see Tenant Tier) |
| 403 | Permission denied |
| 404 | Resource not found |
| 409 | Conflict (idempotency key reuse) |
| 413 | Payload too large (>10 MB) |
| 422 | Validation error |
| 429 | Rate limited |
| 500 | Server error |
Handling Errors
Check the status code first, then read the error message for details:
# Use -w to see the status code
curl -w "\nHTTP %{http_code}\n" \
https://yourshop.zeroshop.io/admin/api/products/99999 \
-H "Authorization: Bearer zspat_..."
resp = requests.get(
"https://yourshop.zeroshop.io/admin/api/products/99999",
headers={"Authorization": "Bearer zspat_..."}
)
if resp.ok:
product = resp.json()
elif resp.status_code == 404:
print("Product not found")
elif resp.status_code == 401:
print("Check your token")
else:
error = resp.json().get("error", "Unknown error")
print(f"Error {resp.status_code}: {error}")
const resp = await fetch("https://yourshop.zeroshop.io/admin/api/products/99999", {
headers: { "Authorization": "Bearer zspat_..." }
});
if (resp.ok) {
const product = await resp.json();
} else if (resp.status === 404) {
console.error("Product not found");
} else {
const { error } = await resp.json();
console.error(`Error ${resp.status}: ${error}`);
}
resp = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
case resp.code.to_i
when 200..299
data = JSON.parse(resp.body)
when 404
puts "Product not found"
when 401
puts "Check your token"
else
error = JSON.parse(resp.body)["error"]
puts "Error #{resp.code}: #{error}"
end