Errors

The status codes the Loyalty API returns, the error bodies each part of the API sends, and how to handle each one.

Check the HTTP status code first. The error body depends on which part of the API you called, and a few errors have an empty body or plain text. Check the Content-Type header before you parse the body.

Status codes

CodeMeaningCommon causes
200, 201SuccessMany write endpoints return an empty {} body. Orders and custom actions are accepted and processed asynchronously, so success doesn't mean points were awarded yet.
400The request is invalidReward Instances without discount_type, or with page_info plus other filters. Tags sent as a string instead of an array. A wrong or already-cancelled reward_text on Approve Redemption Cancellation. An invalid page_info cursor. Product Potential Points without variants.
401Not authenticatedA missing or wrong GUID or API key. On token endpoints, an invalid or expired X-Yotpo-Token. On Authenticated Product Potential Points, a missing customer header or an X-Customer-Token that doesn't match.
403ForbiddenOn token endpoints (Reward Instances, v3.0 VIP Tiers), a missing X-Yotpo-Token, the Loyalty GUID and API key sent instead of a token, or a token for a different store than store_id.
404Not foundAn unknown customer, order, redemption or redemption option. A customer with no anniversary to remove. A store that isn't on the current VIP tiers program (v3.0 VIP Tiers).
422Validation errorA missing required field, no customer identifier, or a value the server rejects: not enough points to redeem, a customer who isn't opted in (Adjust Points), an action_name that doesn't match a Custom Action campaign. Some endpoints also return 422 for an unknown customer.
429Too many requestsYou went over your rate limit. See 429 Too Many Requests.
500Server errorAlso returned for a request body that isn't valid JSON, and for emails sent as a JSON array to Send Referral Emails.

Error bodies

v2.0 endpoints (loyalty.yotpo.com/api/v2)

Errors are JSON, with the message in error or errors. errors is either a string or an object that maps each field to its message:

{
  "errors": {
    "customer": "You must provide one of: customer_email, customer_id, pos_account_id or phone_number"
  }
}
{
  "errors": "Customer has to be opt in for manual adjustment."
}
{
  "error": "merchant not found"
}
WhereStatusBody
Missing GUID or API key401{"error":"Providing one of merchant_id or guid is required"}
Wrong GUID or API key401{"error":"merchant not found"}
Create Redemption, not enough points422{"amount":["You don't have enough points for this amount"]}. The message is under amount, not errors.
Send Referral Emails, every address rejected422{"error":"NO_LEGITIMATE_EMAILS","details":[{"email":"…","reason":"SELF_REFERRAL"}]}
User data, unknown email422Empty object {}
Upload Coupon Codes, unknown redemption option404Empty object {}
Malformed JSON body500{"error":"Internal Server Error"}

Each endpoint page lists the errors it returns, with examples.

Reward Instances (loyalty.yotpo.com/v3) and Product Potential Points

WhereStatusBody
Validation error400{"error":"discount_type is required"}
Missing token, or the GUID and API key instead of a token403{"message":"Forbidden"}
Token for another store403{"message":"Forbidden: Store ID mismatch"}
Invalid or expired token401Plain text: unauthorized
Product Potential Points, unknown store404Empty object {}
Authenticated Product Potential Points, missing customer email401{"email":["Customer email is required"],"error":"customer_email_required"}
Authenticated Product Potential Points, token or store account ID doesn't match401Empty object {}

v3.0 VIP Tiers (api.yotpo.com/loyalty)

Errors use the application/problem+json format:

{
  "type": "about:blank",
  "title": "Program not found",
  "status": 404,
  "detail": "Can't find 'any' program for merchant 'YOUR_STORE_ID'",
  "instance": "/loyalty/v3/stores/YOUR_STORE_ID/vip_tiers/programs/current",
  "code": "LOYALTY_VIP_PROGRAM_NOT_FOUND",
  "exception_id": "de6b113b-51a9-4b8b-90d8-b65fbdaa02ca"
}

code and exception_id aren't on every error. A 400 for an invalid body has title, status, detail and instance only.

Unknown customers don't always return 404

Fetch Customer Details, Create Redemption and Get Active Campaigns return 404 for an unknown customer. Some endpoints return 422 instead: Customer Anniversary and Customer Tags (No customer found), User data ({}), and Adjust Points, which returns the opt-in message for a customer that doesn't exist. If an identifier might be wrong, check it with Fetch Customer Details first.

How to handle each error

400 Bad Request and 422 Unprocessable Entity

Fix the request before you retry: sending it again unchanged returns the same error. The message names the field at fault.

401 Unauthorized and 403 Forbidden

For v2.0 endpoints, check the X-GUID and X-API-KEY headers (see Authentication). For Reward Instances and v3.0 VIP Tiers, request a new access token and retry once; if that fails, check that the token belongs to the store in the path.

404 Not Found

Check the IDs and the customer identifier. For v3.0 VIP Tiers, a 404 with LOYALTY_VIP_PROGRAM_NOT_FOUND means the store isn't on the current VIP tiers program; use Fetch VIP Tiers instead.

429 Too Many Requests

Limits are set per account and can differ between endpoint groups, so read them from the response headers instead of hard-coding a number. Every response carries:

HeaderDescription
RateLimit-LimitRequests allowed in the current window
RateLimit-RemainingRequests left in the current window
RateLimit-ResetSeconds until the window resets
X-RateLimit-Limit-MinuteRequests allowed per minute
X-RateLimit-Remaining-MinuteRequests left this minute

After a 429, wait RateLimit-Reset seconds before you retry, or back off exponentially (1, 2, then 4 seconds). When RateLimit-Remaining gets low, slow down before you hit the limit. Spread bulk syncs (customers, orders) over time instead of sending them in bursts.

500 Internal Server Error

Retry GET requests up to 3 times with exponential backoff. If a request keeps returning 500, check that the body is valid JSON and that list fields have the documented type.

Don't retry a write blindly. If the first attempt went through, a retry of Adjust Points, Record Customer Action or Create Redemption awards or deducts points again or issues a second coupon, and a retry of Create Refund records a second refund. Before you retry, check whether the first call worked with Fetch Customer Details and with_history=true.

What to log

For every failed call, log the HTTP status, the error body, the time, the request method and path, and:

  • the X-Request-Id response header (v2.0 endpoints, Reward Instances and Product Potential Points), or
  • the exception_id in the body (v3.0 VIP Tiers).

Include them when you contact Yotpo support. Don't log your API key, GUID or access tokens.