Commerce API
Errors
One error type, stable codes. Branch on the code, never the text.
import { MercestackError } from "@mercestack/commerce";
try {
await mercestack.addToCart({ variantId });
} catch (error) {
if (error instanceof MercestackError) {
error.code; // "OUT_OF_STOCK"
error.status; // 400
error.requestId; // quote this to support
error.isRetryable; // network, rate limit, 5xx
error.details; // anything else the API sent
}
}Messages are written for humans and get rewritten. A client that does if (message.includes("out of stock")) breaks the day somebody improves the wording — branch on code.
| Code | What happened |
|---|---|
OUT_OF_STOCK | Not enough available, and backorders are off |
PRODUCT_NOT_AVAILABLE | Unpublished or archived since it was added |
INVALID_VARIANT | No such variant in this store |
PRICE_CHANGED | The price moved between display and checkout |
CART_EXPIRED | Untouched too long. The SDK recovers from this for you |
CART_EMPTY | Nothing to check out |
DISCOUNT_INVALID | Expired, exhausted, or never existed |
GIFT_CARD_INVALID | Wrong code, cancelled, expired, or empty |
PAYMENT_FAILED | The provider declined it |
UNAUTHORIZED | Missing or revoked key |
FORBIDDEN | Key exists but is not allowed to do this |
RATE_LIMITED | Too many requests. Back off and retry |
Every response carries a Mercestack-Request-Id header, and it matches a line in Commerce → Developers → API logs. It is the fastest way to have someone find out what actually happened.
The SDK retries transient failures — network errors, rate limits, 5xx — with exponential backoff. It does not retry a 400: that is the same wrong request sent again.