The Error Object
Every error response follows a consistent JSON structure. The structure differs slightly between validation errors (HTTP400) and all other errors.
Validation errors (HTTP 400):
Error codes are stable; changing a code is considered a breaking change. Error messages, however, may be updated over time to provide better clarity. Your integration should switch on
errorCode for programmatic handling - never on the message text.V3 error code anatomy
V3 endpoints use structured error codes in the format{STATUS}_{DOMAIN}_{SEQUENCE}:
HTTP Status Codes
400 – Bad Request
The server could not process the request, usually due to a syntax error in the URL or the JSON body. How to fix- Verify your request body matches the expected schema.
- Ensure all required fields are present (e.g.
variantId,recipient.email,idempotencyKey). - Check that field values are the correct type (e.g. strings vs. integers).
- Inspect
pathin the response body - it points to the specific field that failed validation.
401 – Unauthorized
There is an issue with your API key credentials. How to fix- Missing header. Ensure you are passing the
X-Api-Keyheader on every request. - Invalid key. Double-check that the key hasn’t been mistyped or deleted from the Dashboard.
- Expired key. Check whether the key has reached its expiration date and rotate it if needed. See Authentication & Security.
403 – Forbidden
Your key is valid but does not have permission to access the requested resource. How to fix- Wrong scope. Check that your API key was created with the correct scope for this action (e.g.
orders:createto place an order,products:readto read the catalog). See Authentication & Security. - Wrong environment. Make sure you are not using a Testing API key against a Production resource or vice versa. See Before You Begin.
- Insufficient masking scope. Reading PII fields requires
:read:unmaskedrather than:read:masked. See PII Masking.
404 – Not Found
The requested resource does not exist, or it exists but is not visible to the calling Account. How to fix- Double-check the ID in your request path - copy it directly from a previous API response to avoid typos.
- Verify the resource was successfully created before attempting to retrieve or update it.
- If you’re scoping with
Snappy-Account-Id, verify the resource belongs to that account.
Snappy intentionally returns
404 (rather than 403) in some cases where a resource exists but is not visible to your key - for example, a Collection belonging to a different Account. This prevents exposing the existence of resources your key shouldn’t know about. If you’re confident the resource exists and you should have access, check your key’s scope and account scoping headers.422 – Unprocessable Entity
The request was syntactically valid, but Snappy can’t fulfill it due to a business rule or current resource state. How to fix- Read the
errorCodeandmessageto understand the specific rule that was violated. - Common 422 scenarios on V3:
- Order already in transit -
POST /v3/orders/{orderId}/cancelreturns422once the fulfillment partner has picked up the shipment. - Variant not shippable to country -
POST /v3/ordersreturns422if the shipping address country is outside the variant’s supported locations. - Insufficient billing balance -
POST /v3/ordersreturns422when the Billing Method has insufficient funds. - Idempotency conflict - replaying an
idempotencyKeywith a different request body returns422. Use the same key only with identical bodies.
- Order already in transit -
- Re-issue the request once the underlying state changes (e.g., refunded balance, address updated, order cancelled in time).
429 – Too Many Requests
Your integration has exceeded the API rate limit. How to fix- Pause your requests immediately.
- Respect the
Retry-Afterresponse header - it tells you how long to wait before retrying. - Implement an exponential backoff strategy - wait a short period before retrying, and increase the wait time with each subsequent retry.
- Review your request frequency against the published Rate Limits.
500 – Internal Server Error
Something went wrong on Snappy’s end. How to fix- Check the Snappy Status Page to see if there is an ongoing incident.
- Retry once with a short delay - many
500s are transient. - If no incident is reported and the issue persists, contact support with:
- Request URL and method
- The
errorCodereturned in the response body - A timestamp of when the error occurred
- The
idempotencyKeyyou used (for writes), so support can correlate without risking a duplicate
502 – Bad Gateway
An upstream service returned an invalid response while processing your request. Almost always transient. How to fix- Retry with exponential backoff. For writes, only retry if you supplied an
idempotencyKey- otherwise you risk duplicate side effects.
503 – Service Unavailable
The service is temporarily unavailable, typically during a deployment or under unusual load. How to fix- Retry with exponential backoff. Respect the
Retry-Afterheader if present. - If the issue persists across several minutes, check the Snappy Status Page.
504 – Gateway Timeout
The request took too long to process and timed out. How to fix- Retry with a short delay; most
504s are transient. - For writes, only retry if you supplied an
idempotencyKey(the original request may have actually succeeded before the timeout - the idempotency key lets you safely re-issue without risking a duplicate). - If a specific endpoint times out consistently, contact support with the request details.
Retry & Idempotency
Not all errors are safe to retry. The matrix below summarizes when retrying is the right move.Idempotency keys make retries safe
Many Snappy write endpoints accept an idempotency key. Sending the same key twice returns the same result - no duplicate side effect, no double-charge, no second gift sent.- Generate one stable key per logical operation - e.g.,
user-{userId}-order-{cartId}. Reuse it on every retry of that operation. - Never generate a fresh random key on each retry - that defeats the protection and will result in duplicates.
- Replaying with a different body returns
422(idempotency conflict). Either reuse the original body or pick a new key. - See Duplicate Detection for the full reference.
Exponential backoff
For all retryable error codes, use exponential backoff with jitter:- First retry: wait ~1 second.
- Each subsequent retry: double the wait, with random jitter.
- Cap at ~60 seconds between retries.
- Give up after 5–7 attempts unless the operation is critical and idempotent.
Always respect a
Retry-Afterheader if the response includes one - it overrides your local backoff calculation.