Skip to main content
This page is reference material.If you are troubleshooting a theme workflow, start with the workflow pages first:Then come back here if you need the exact error shape or status-code meaning.

Error response format

All errors follow a consistent structure:

HTTP status codes


Error codes reference

Payment coupon errors

POST /dev/v1/payments rejects an invalid coupon with 422 VALIDATION_ERROR and an error.subcode such as coupon_invalid, coupon_expired, coupon_exhausted, or coupon_min_order. No invoice is created. Product- and variant-scoped coupons return coupon_requires_products, and coupons restricted to payment methods return coupon_gateway_restricted; use POST /dev/v1/orders with catalog items for both. See the full coupon error table.

Order product errors

POST /dev/v1/orders takes the product id or its uniqid in items[].product_id. A product the shop does not have, or a deleted one, returns 422 VALIDATION_ERROR with error.subcode = "product_not_found" and one error.details entry per unknown item, for example { "field": "items.1.product_id", "message": "Product not found: prod_x." }. No order is created.

Authentication errors

UNAUTHORIZED

HTTP 401. The API key is missing or invalid.
Solution: Check that your API key is correct and included in the Authorization header.

FORBIDDEN (missing scope)

HTTP 403. Your API key is valid but lacks the required scope for this endpoint.
Solution: Go to Settings → API Keys, check which scopes your key has, and add the missing one. Use GET /me/capabilities to inspect active scopes at runtime.

FORBIDDEN (shop suspended)

HTTP 403. Your shop has been suspended by Shoppex.
Solution: Reach out through the Shoppex Discord or Telegram to resolve the suspension. This is an account-level issue, not a key configuration problem.

Validation errors

VALIDATION_ERROR

HTTP 422. One or more fields failed validation.
Solution: Check the details array for specific field errors.

What each request error means

Use the status code as the first signal:
  • 422 VALIDATION_ERROR means the request shape or field values are invalid
  • 400 means the request was understood, but a business rule rejected it
  • 404 ROUTE_NOT_FOUND means the method and /dev/v1/* path do not match a Developer API endpoint
  • 404 can be generic NOT_FOUND or resource-specific like PRODUCT_NOT_FOUND
For example, a wrong email format on POST /customers returns 422 VALIDATION_ERROR. An expired license on POST /licenses/validate returns 400 LICENSE_EXPIRED. An unknown endpoint such as GET /shops/shop_123/revenue returns 404 ROUTE_NOT_FOUND. A missing product on GET /products/prod_xyz returns 404 PRODUCT_NOT_FOUND.

Theme workflow troubleshooting

If you are using the theme automation flow:
  • 401 usually means your API key is missing or invalid
  • 403 usually means your key is missing themes.read or themes.write
  • 422 usually means the request body or params are wrong
  • 500 usually means the server failed while validating, previewing, publishing, or reading the theme
The most common mistake: theme.inspect fails with 403 because your key is missing themes.read, and theme.apply fails with 403 because it needs themes.write. A 422 usually means a bad request body or theme id. A 500 means something broke on the server. Check the error and retry.

Resource errors

ROUTE_NOT_FOUND

HTTP 404. The HTTP method and /dev/v1/* path do not match a Developer API endpoint. Authentication is not attempted because no route was selected.
Solution: Compare the method and path with the API Reference. The current shop comes from the API key, so shop-scoped endpoints do not require a shop ID unless their reference explicitly shows one.

NOT_FOUND

HTTP 404. The requested resource does not exist.
Solution: Verify the resource ID is correct.

PRODUCT_NOT_FOUND

HTTP 404. Specific product not found.

INVOICE_NOT_FOUND

HTTP 404. Specific invoice not found.

PAYMENT_NOT_FOUND

HTTP 404. Payment not found.

CUSTOMER_NOT_FOUND

HTTP 404. Customer not found.

CATEGORY_NOT_FOUND

HTTP 404. Category not found.

COUPON_NOT_FOUND

HTTP 404. Coupon not found.

SUBSCRIPTION_NOT_FOUND

HTTP 404. Subscription not found.

TICKET_NOT_FOUND

HTTP 404. Support ticket not found.

REVIEW_NOT_FOUND

HTTP 404. Review not found.

ESCROW_NOT_FOUND

HTTP 404. Escrow transaction not found.

License errors

LICENSE_NOT_FOUND

HTTP 404. License key not found.

LICENSE_INVALID

HTTP 400. License key is invalid or malformed.

LICENSE_EXPIRED

HTTP 400. License key has expired.

LICENSE_HWID_MISMATCH

HTTP 400. Hardware ID does not match the registered device.

Coupon errors

COUPON_EXPIRED

HTTP 400. Coupon has expired.

COUPON_MAX_USES_REACHED

HTTP 400. Coupon has reached maximum uses.

Idempotency errors

Idempotency key reuse

HTTP 422 VALIDATION_ERROR. Shoppex did not run the request because its idempotency key cannot be used for it:
  • the key was already used with a different request body on the same route
  • the first request with this key is still running (Idempotency-Status: processing)
  • the first request with this key may have completed, but Shoppex has no stored response for it (Idempotency-Status: cached)
POST /dev/v1/products/{id}/serials/claim answers the same cases with HTTP 409 and the code idempotency_conflict. Solution: Each unique request body needs its own idempotency key. If you are retrying a failed request, make sure the body matches the original. If the request is still processing, retry with the same key after a short wait. See the Idempotency section for details.

SERVICE_UNAVAILABLE

HTTP 503. You sent an idempotency key, but Shoppex could not check it right now. The request did not run.
Solution: Retry the same request with the same idempotency key after a short wait.

Revision errors

Workflows and coupons return a revision number. It goes up by one on every change. To update or delete one of them only if nobody changed it since you read it, send that number in the If-Match header, for example If-Match: "3".

REVISION_CONFLICT

HTTP 409. The resource changed after you read it. Shoppex changed nothing, and the idempotency key of the request is still free.
Solution: Read the resource again, check that your change still applies, and send it with the new revision. A retry with an idempotency key that already completed returns the stored response, even if its If-Match is now old.

INVALID_IF_MATCH

HTTP 400. The If-Match header is not a revision number. The request did not run. Solution: Send the revision from your last read, for example If-Match: "3".

Rate limiting

RATE_LIMITED

HTTP 429. Too many requests.
Response headers:
  • X-RateLimit-Limit
  • X-RateLimit-Remaining
  • X-RateLimit-Reset
  • Retry-After when blocked
Rate limits are plan-dependent, so treat any numeric values you see elsewhere as illustrative. Check the response headers from your own requests for your current limits. Solution: Wait for Retry-After or X-RateLimit-Reset before retrying.

Handling errors in code

Every Dev API error response also returns X-Request-Id in the headers. Log that value together with error.code when you need support or want to trace a failing request.

Best practices

Log error codes

Always log the error.code for debugging. It is more reliable than parsing messages.

Handle 429s gracefully

Implement exponential backoff for rate limits. Check X-RateLimit-Reset header.

Validate before sending

Validate inputs client-side to catch errors early and reduce API calls.

Use idempotency keys

For payment creation, use idempotency keys to safely retry failed requests.