Errors
The status codes the UGC 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 some errors are plain text, not JSON. Check the Content-Type header before you parse the body.
Status codes
| Code | Meaning | Common causes |
|---|---|---|
200 | Success | Storefront endpoints also return 200 with empty data for an unknown product ID. See Storefront: no error for unknown products. |
400 | The request is invalid | A missing or malformed parameter, such as a since_date that isn't YYYY-MM-DD. A repeated review (duplicate_review). The token sent the wrong way for custom albums. A wrong API secret or grant_type when you request a token. |
401 | Not authenticated | A missing, invalid or expired access token. The Insights API called with X-Yotpo-Token instead of Authorization: Bearer. |
403 | Forbidden | The Privacy endpoints return 403 instead of 401 when the token is missing. |
404 | Not found | An unknown store ID, review ID or other resource. A path that doesn't exist. An unknown store ID when you request a token. |
429 | Too many requests | You went over a rate limit. See Rate limits. |
500 | Server error | Also returned for some invalid values, such as an unknown vote_type when voting on a review, or an unsupported coupon_action when uploading coupon codes. |
Error bodies
Merchant endpoints (api.yotpo.com)
api.yotpo.com)Most merchant errors use this shape:
{
"status": {
"message": "Parameter since_date must be a string in the format YYYY-MM-DD",
"code": 400,
"error_type": "Exceptions::InvalidDate",
"uuid": "31b5c909-fbcf-4add-9d19-6826944eb9d3"
}
}| Field | Description |
|---|---|
status.message | What went wrong, in plain English. Show it in your logs, not to shoppers. |
status.code | The HTTP status code, repeated in the body. |
status.error_type | The error class. Examples: Exceptions::AccessDenied (401), Exceptions::InvalidParams (400), Exceptions::InvalidDate (400), Exceptions::RecordNotFound (404). |
status.uuid | A unique ID for this request. Log it, and include it when you contact Yotpo support. |
Responses can include other fields. Ignore any field that isn't listed here.
Other error shapes
| Where | Status | Body |
|---|---|---|
A path that doesn't exist on api.yotpo.com | 404 | {"status":404,"error":"Not Found"}. Here status is a number, not an object. |
| Email analytics, invalid parameter value | 400 | {"error":"date_bucket is invalid, must be one of: day, month, year","code":3} |
| Privacy endpoints without a valid token | 403 | {"message":"Forbidden"} |
| Insights API, missing or wrong authentication | 401 | Plain text: unauthorized |
Storefront endpoints (api-cdn.yotpo.com), unknown store ID | 404 | Plain text: Account not found |
Access token errors (POST /oauth/token)
POST /oauth/token)| Cause | Status | Body |
|---|---|---|
| Wrong API secret | 400 | {"error":"invalid_client"} |
grant_type missing or not client_credentials | 400 | {"error":"unsupported_grant_type"} |
| Unknown store ID | 404 | The merchant error shape, with "message": "Couldn't find Account" |
Storefront: no error for unknown products
Storefront endpoints don't return 404 for a product ID Yotpo doesn't know. They return 200 with no reviews. For example, V3 Retrieve product reviews returns this (shortened):
{
"pagination": { "page": 0, "perPage": 5, "total": 0 },
"bottomline": { "totalReview": 0, "averageScore": 0.0 },
"products": [],
"reviews": []
}To tell "no reviews yet" apart from "wrong product ID", check that the product ID is the one your store sends to Yotpo. Storefront endpoints also don't return an error when you ask for more than the maximum page size. They return the maximum instead, so check pagination.perPage (or per_page) in the response.
How to handle each error
400 Bad Request
Fix the request before you retry: sending it again unchanged returns the same error. status.message names the parameter at fault.
401 Unauthorized
Request a new access token and retry the call once. If it fails again, check your store ID and API secret. For the Insights API, send the token as Authorization: Bearer <token>. For custom albums, send it as the utoken query parameter. See Authenticate and make your first call.
403 Forbidden
On the Privacy endpoints, this means the token is missing or invalid. Handle it like a 401.
404 Not Found
Check the IDs in the path. On storefront endpoints, a 404 with Account not found means the store ID is wrong.
429 Too Many Requests
Wait before you retry. Responses carry these headers:
| Header | Description |
|---|---|
RateLimit-Limit | Requests allowed in the current window |
RateLimit-Remaining | Requests left in the current window |
RateLimit-Reset | Seconds until the window resets |
X-RateLimit-Limit-Minute | Requests allowed per minute |
X-RateLimit-Remaining-Minute | Requests left this minute |
Wait for RateLimit-Reset seconds, or back off exponentially (1, 2, then 4 seconds). Limits differ by endpoint, so read the headers instead of hard-coding a number. To stay under them, cache storefront responses and use batch endpoints such as Retrieve bottomline scores.
500 Internal Server Error
Retry read requests (GET, and the search and Insights POST requests) up to 3 times with exponential backoff. If an endpoint keeps returning 500 for one request, check the parameter values: some endpoints return 500 for an invalid value.
Don't retry a create call blindly. If the first attempt went through, a retry of Create review, Create question, Create an answer, a vote or an image import creates a second one. Create review returns 400 duplicate_review for a repeat, but other create calls may not detect duplicates. Check whether the first call succeeded before you retry.
What to log
For every failed call, log the HTTP status, status.error_type and status.uuid (when present), the time, and the request method and path. Don't log access tokens or your API secret.
Updated about 11 hours ago
What’s Next
How to test your integration without affecting real shoppers