Public previewBetter every weekSee what changed →
All guides

Handling errors

Every endpoint uses one error shape. The HTTP status is meaningful: code is the general class of error, and details.error is the specific Groupon code to branch your logic on.

json
{
  "code": "aborted",
  "message": "Displayed price no longer valid",
  "details": {
    "error": "PRICE_MISMATCH",
    "errorMessage": "Displayed price no longer valid",
    "requestId": "c0ffee00-...",
    "path": "$.items[0]", "expectedPrice": 4500, "currentPrice": 4900, "currency": "USD", "currencyPrecision": 2
  }
}

One helper for every endpoint

ts
function grouponErrorCode(body: any): string {
  return body?.details?.error ?? body?.code ?? "UNKNOWN";
}

function grouponRequestId(body: any): string | undefined {
  return body?.details?.requestId;
}

Error codes

details.errorHTTPcodeMeaning / what to do
BAD_REQUEST400invalid_argumentA field is missing or invalid, or a cursor is bad. errorMessage names the field. Fix the request; for a cursor error, restart the walk.
FORBIDDEN403permission_deniedOutside your inventory scope, or the storefront is deactivated. Do not retry.
INVALID_PRODUCT_ID404not_foundThe product is gone, or the cart has no such line. For a product: mark it not listable. For a cart line: read the cart, and if it comes back empty, create a new one.
INVALID_CART_ID404not_foundNo such cart for your storefront: it never existed, or another storefront created it. Do not retry: create a new cart from your local copy.
INVALID_BOOKING_UUID404not_foundNo such order placed from your carts. Do not retry. Show a neutral message.
PRODUCT_NOT_CARTABLE400failed_preconditionThe deal needs a time-slot booking. Remove it from your listing.
CART_ITEM_LIMIT400failed_preconditionMore than 20 different options in a cart. details carries limit and actual.
PRICE_MISMATCH409abortedexpectedPrice differs from the live price. details.currentPrice is the live per-unit price; details.path points at the item. Nothing was changed: update your price, ask the shopper to confirm, retry.
INVALID_BOOKING_STATE, UNPROCESSABLE_ENTITY400 / 409failed_preconditionReserved. Treat as a non-retryable failure.
RATE_LIMITED429resource_exhaustedToo many requests for this storefront right now. Our own limit is 600 requests per storefront per minute, counted by the calendar minute across all of the storefront's keys. details.retryAfterSeconds says how many seconds are left until it starts again.
UPSTREAM_UNAVAILABLE503unavailableGroupon could not answer right now. Retry with backoff, except adding cart items (see the rule below).

HTTP 401 with code: "unauthenticated" means a missing, wrong, revoked or expired key, on every endpoint that takes one. The message is the same whatever the reason, so it never tells anybody whether a key exists. Do not retry; alert an operator.

Retry policy

Decide whether to retry from the error code first, not the HTTP status alone.

SituationRetry?
UPSTREAM_UNAVAILABLE, a network error, a timeout, or a 5xx with no Groupon error codeYes. Exponential backoff, max 5 tries. Exception: adding cart items, below.
RATE_LIMITED (429)Yes, but wait at least details.retryAfterSeconds seconds first. The answer carries no Retry-After header today. When retryAfterSeconds is missing (Groupon's own limit, passed on), back off exponentially.
Any retryable failure on adding items to a cartNo. Read the cart, compare, then add only what is missing.
Any retryable failure on creating a cartYes. A retry creates a separate new cart, which is harmless. Use the id from the call that succeeded.
BAD_REQUEST with a cursor problem on the products listNot the same page. Discard the cursor and restart the walk from page 1. See Syncing the catalog.
BAD_REQUEST, FORBIDDEN, INVALID_PRODUCT_ID, PRODUCT_NOT_CARTABLE, PRICE_MISMATCH, CART_ITEM_LIMIT, INVALID_BOOKING_UUID, INVALID_BOOKING_STATE, UNPROCESSABLE_ENTITY, INVALID_CART_IDNo. Handle the code as described above.
HTTP 401 (authentication failure)No. Alert an operator: check the key was copied correctly, or mint a new one.

A booking read never changes the order, so it is always safe to retry.