Skip to content

Error codes

Markdown

The error codes returned by the endpoints and their meanings.

All errors are returned with a body in the same format:

{ "error": "refused", "detail": "origin_unverified: www.yourbrand.com" }

error indicates the type of error and detail its specifics; both are codes. Some details contain a value after a colon (field_missing: customer_email). Do not show codes to visitors as they are; convert them into a text from your own translation files.

Status Code Meaning
400 invalid / <field> A field is missing or invalid. The detail names the field concerned: <field>_required, <field>_too_long, <field>_out_of_range.
400 invalid_json The body could not be read, or a text in the body contains a character that cannot be stored (NUL \u0000 or an unpaired surrogate)
400 invalid / invalid One of the query parameters contains a character that cannot be stored (NUL or an unpaired surrogate)
401 In the Admin API, no credentials or an invalid key; in the review writing flow, no token (token_required); in the Ingest API, an invalid server key (refused) or an invalid signature (signature_refused)
403 refused / … The request was recognised but not permitted; details below
404 not_found The record was not found or belongs to another brand
405 method_not_allowed The HTTP method is not supported; see the Allow header
429 rate_limited The rate limit was exceeded; for the values, see Limits
Code Meaning
origin_missing The request does not include a domain (no Origin or Referer header)
origin_unverified: <domain> The domain is not verified; the value is the domain in the request’s Origin (or, failing that, Referer) header
unknown_site_key The site key is not recognised
revoked_site_key The site key has been cancelled
channel_inactive The channel is off
unknown_key, malformed_key The server key is not recognised or its format is invalid
revoked_key The server key has been cancelled
tenant_inactive The service of the brand the key belongs to is frozen or closed (for a frozen brand, review reading and SSR requests keep working)
scope_missing The key is not permitted to perform this operation
unknown_channel The channel code is wrong or the channel is off
server_only This endpoint can only be called with a server key
Code Meaning
invalid / product The product code is missing or longer than 128 characters
sort_not_allowed The sort order is not on the market’s permitted list
invalid / rating The rating is outside 1–5
invalid / q_too_long, topic_too_long, topic The search expression or topic word is invalid
invalid / style, style_too_long The layout in the SSR request is not cards or sidebar
invalid / theme, theme_too_long The design in the SSR request is not warm, trust, editorial, minimal, soft, bold, natural or night
refused / no_site_key The channel has no site key in use and no page of your own is linked for the channel’s method statement

The codes of the GET /v1/viewer and GET /v1/viewer/order calls. If these endpoints are called from the browser, 403 refused / server_only is returned.

Code Meaning
invalid / customer The X-Sayproof-Customer header is missing, contains no @ or is longer than 254 characters
invalid / order, order_too_long The order number is missing from the order page query or is longer than 128 characters

For these codes, the text shown to the visitor is determined by the script; you will not encounter them in headless use either.

Code Meaning
token_required No writing token was sent
token_refused / token_unknown, token_expired, token_spent, token_wrong_kind, token_foreign_tenant The token is not recognised, has expired, has already been used, is of the wrong kind or belongs to another brand
token_refused / line_already_written A review has already been written for this order line
token_refused / line_out_of_scope The order line is not within the scope of this token
token_refused / token_foreign_market The link was opened on the site of a channel of a market other than the order’s
invalid / rating_out_of_range The rating is invalid
invalid / title_too_long: 200, body_too_long: 5000, author_too_long: 120 The text exceeds the permitted length
invalid / aspect_unknown, aspect_out_of_range, aspect_required A rating topic is invalid or a required topic was left empty
invalid / too_many_reviews More than 20 products were sent in a single call
invalid / too_many_items: 6 More than 6 photos or videos were added to the review
invalid / media_not_available The file was not uploaded for this order
invalid / review_not_revisable The review is not in a state that can be corrected
Status Code Meaning
400 refused / type_not_allowed: <type> The file type is not supported
400 refused / too_large: <MB> The file size limit was exceeded
400 refused / too_many_items: 18 The number of files uploaded for this order and not yet added to a review reached the limit (18 per order line)
422 refused / video_too_long: 60 The video is longer than 60 seconds; the file was refused at upload
413 refused / too_large: <MB> The request body exceeds the permitted size
422 refused / quarantined The file was quarantined by the security scan
422 refused / image_unreadable The image could not be read or is not jpeg, png or webp
422 refused / image_too_large The image is over 40 megapixels
422 refused / video_unreadable, video_stream_missing The video could not be read or has no picture
422 refused / video_frame_too_large: 3840x2160 The video picture is larger than 3840×2160 (2160×3840 for a portrait video)
422 refused / video_frame_rate_too_high: 60 The video has more than 60 frames per second
422 refused / video_codec_not_allowed The video is not encoded with H.264, HEVC, MPEG-4, VP9 or AV1
422 refused / scan_failed, processing_failed The file could not be scanned or processed

The video limits are checked at upload when the server can read the video at that point. A video that cannot be read then is refused with the same limits while it is processed and is not shown on the site.

Code Meaning
invalid_reason The report reason is not on the list
invalid / vote The vote is not up, down or none
Code Meaning
refused / questions_disabled The brand has not turned on questions and answers (403)
invalid / body_required, body_too_long, email_invalid, email_too_long, name_too_long, asker_too_long, product_required, product_too_long A missing or wrong field in the question or answer form
token_required, token_refused / token_unknown, token_expired, token_wrong_kind, token_foreign_tenant, token_foreign_market The token sent with an answer is missing or not valid
token_refused / not_a_buyer The token’s order does not contain the question’s product
token_refused / asker_expired, asker_invalid The signed-in customer’s question token has expired, is not valid or belongs to another brand; the script turns the form into the form of a visitor who is not signed in
not_found The question was not found, is not live or belongs to another market (404)
answer_refused / text_steering, text_health_claim, text_personal_data, text_profanity, question_not_published Admin API: the brand answer steers, makes a health claim, contains personal information or swearing, or the question is not live (409)
Status Code Meaning
401 refused / unknown_key, malformed_key, revoked_key The server key sent with Authorization: Bearer is not recognised, is malformed or has been cancelled
403 refused / scope_missing The server key does not have the send orders (orders) permission
401 signature_refused / signature_missing, timestamp_missing With signed sending, the signature or time header is missing
401 signature_refused / timestamp_invalid The time value could not be read or contains no time zone
401 signature_refused / timestamp_outside_window The time difference is more than ±5 minutes
401 signature_refused / signature_mismatch The signature does not match
401 signature_refused / secret_unknown The password ID is not recognised, the password has been cancelled or it cannot be used for this operation
429 rate_limited More than 60 requests from the same IP address were refused in 5 minutes because of the key, password or signature; for the values see Limits
400 invalid / body_invalid, body_empty The body is not valid JSON or is empty
400 invalid / batch_too_large: 100 More than 100 records were sent in a single request (the limit for email events is 500)
400 invalid / field_missing: <field>, field_invalid: <field>, field_too_long: <field> A field is missing, invalid or too long; a character that cannot be stored (NUL \u0000 or an unpaired surrogate) also makes the field invalid
400 invalid / market_required, market_without_policy: <market> The market could not be determined or no rules are defined for it
400 invalid / channel_unknown The channel code is wrong or the channel is off
400 invalid / market_channel_mismatch: <market> The order’s market is not the market of the channel the order is linked to
400 invalid / status_unmapped: … The state value is not recognised

The main codes returned by the panel and the Admin API. The panel turns these codes into sentences on screen.

Status Code Meaning
403 forbidden / scope_missing The user’s role or the key’s permission is not sufficient for this operation
403 forbidden / brand_inactive The brand’s service is frozen or closed; in the panel only the data export can be prepared and downloaded
403 forbidden / panel_session_required, refused / panel_session_required The operation can only be done by a user signed in to the panel, not with an API key (order connection operations, the invitation email test send and the invitation delivery settings; on user, channel, key and personal data request operations a key receives forbidden / scope_missing)
400 invalid / scope_reserved: write Only the Sayproof team can grant the change settings (write) permission
400 invalid / username_taken The username is used by another brand; a user can belong to only one brand. An account that no longer belongs to any brand is added only if it is entered together with the email address registered on the account.
400 invalid / current_password The current password was wrong when changing the password
400 invalid / password_guessable, password_names_account The new password is easy to guess (a common word, team or name with a year or a run of digits) or contains Sayproof, the brand’s name or the username
400 invalid / email_required No email address was entered when adding a user, or a password link was requested for a user without an email address
400 invalid_passcode The verification code in two-step sign-in is wrong, expired or already used
400 second_step_expired More than 10 minutes passed after the password step, or there was no password step; signing in starts again
409 invalid / second_step_on Two-step sign-in is already on
400 invalid / address_needs_credentials The order connection address points to another server; the sign-in details have to be entered again too
400 invalid / cta_required The Write a review button section is required in an invitation email template
400 invalid / template_scope_taken There is already an invitation email template for this invitation type, language, market and channel; edit or remove that one first
400 invalid / channel The channel code does not exist in this brand (method statement, invitation email template, audit report and statistics requests)
400 invalid / verification_locked, sort_not_offered: <option>, default_sort_not_allowed, review_window_days_out_of_range, valid_from_past The market rules version could not be opened: proof of purchase required by the Sayproof rule cannot be turned off; the sort option is not in the Sayproof rule; the default sort is not among the options offered; the time to write is outside 7–365 days; the start date is in the past
400 invalid / channel_market_mismatch In an audit report, statistics or market rules request, the channel sent does not belong to the market sent
400 invalid / sender_domain_unverified The sender address’s domain is not verified
400 invalid / webhook_url_required, webhook_secret_missing If your own system sends invitations, a notification address and a notification address password are needed
400 invalid / addresses_required, addresses The opt-out lookup has no addresses, the list is invalid or it is longer than 1,000 addresses
400 invalid / url_invalid The address could not be read; enter a full https address
400 invalid / host_unverified The address given to the page check is not on one of your verified domains
400 invalid / review_style, review_theme The layout (cards, sidebar) or design (warm, trust, editorial, minimal, soft, bold, natural, night) sent for the channel is not recognised
400 identifier_mismatch The email address given when asking for the copy of a personal data access request does not match the request
400 invalid / base_url, remote_channel, <field>_required, address_needs_credentials For an order connection, the address uses a scheme other than https (if no scheme is written, https:// is added) or contains user details, a query string or # besides the domain; the Omnitron channel number is not made of digits; a required connection field is empty (for example username_required, client_secret_required, consumer_key_required); the address was changed to another domain without sending the sign-in details again
400 platform_refused / login_refused, credentials_missing, shop_address_invalid, api_credentials_missing, api_credentials_refused, api_scope_missing, host_unresolved, http_status: <code> … The platform could not be reached while trying an order connection; what the codes mean: Akinon, Shopify, WooCommerce
409 source_exists This channel already has an order or marketplace connection to this platform
409 source_inactive A read cannot be started for a paused order or marketplace connection
400 invalid / seller_id_locked, feed_url_required, feed_url_not_https, feed_url_not_applicable, file_required, column_missing: <column>, file_unreadable, unsupported_format, too_large, too_many_rows, reviews A missing or invalid field on a marketplace connection: a change of the seller number was tried, the address is not https, the file cannot be read or lacks a required column, no review to remove was found
409 source_has_reviews A marketplace connection with imported reviews live, or with the record of a review removed by a personal data request, cannot be removed
409 channel_inactive A read cannot be started for an order connection whose channel is off
409 channel_in_use The channel has reviews, orders or an order connection, so it cannot be removed; it can be turned off
409 channel_quota The channel allowance is full; no new channel can be created and no channel that is off can be turned back on. Send a request to the Sayproof team with Request another channel
409 channel_request_open A request for another channel is already waiting for an answer
409 refused / template_preset, template_default, template_assigned, template_retired The rating topic list could not be changed: a Sayproof preset list cannot be retired; the general list and a list assigned to a product type cannot be retired; no new version can be published for a retired list
404 not_found / export_not_ready The data export is not ready yet or its download period has ended
409 domain_in_statement / <channel code/language> The domain cannot be removed because the method statement address of the channel and language named in the detail uses it; change the address in Market rules › Method statement first
400 proof_refused / proof_not_found, token_mismatch, dns_value_mismatch, dns_unreachable The domain could not be verified: neither the verification file nor the TXT record was found; the file’s content is not the verification text; the TXT record was found but its value is different; there is no file and the domain’s DNS server could not be reached (try again shortly). The response also carries the path, dns_name and token fields.
409 domain_in_use / channels: <channel codes> The domain cannot be removed because the invitation landing page address of the channels named in the detail uses it; change the channel’s address first
409 seller_response_refused / text_personal_data, text_profanity, text_steering The seller reply was not saved: the text contains personal data (email, phone, ID, IBAN, card or address), abusive language or a sentence steering the customer into changing the review or rating
409 seller_response_refused / seller_response_open, parent_review_not_published The review already has a pending, live or hidden seller reply (withdraw it before writing a new one), or the review is not published
409 resolution_refused / text_personal_data, text_profanity, text_steering The resolution note was not saved; the reasons are the same as for a seller reply
409 resolution_refused / review_not_live A resolution note can only be added to a review that is published or hidden for now
409 statement_changed The method statement changed during confirmation; put the new text on your page and confirm again
409 sender_domain_refused / sender_domain_in_use The sender domain cannot be removed because the sender address on the Invitation sending screen or in a channel’s Sender email address field uses it
409 not_copyable The request is not a completed access request, so its copy cannot be downloaded again
502 sender_domain_check_failed / dns_unreachable The domain’s DNS server could not be reached; try again shortly
502 page_unreadable / … The page could not be read during the page check (for example http_status: 404)

These codes are not returned in an HTTP response; they are shown on the Reads tab of a source opened from the Products › Product sources tab as the reason a read failed.

Code Meaning
page_limit_reached: <limit> The read reached the page limit before the catalogue ended; the next read continues from where it stopped
cursor_repeated The source returned the same next-page cursor again; the read was stopped

Example: converting an error code into a translation key

Section titled “Example: converting an error code into a translation key”

The part of the detail value before the colon is the code itself. By combining it with the error value, you can build the key to look up in your own translation file. For example, the response {"error": "refused", "detail": "origin_unverified: www.yourbrand.com"} becomes the key sayproof.refused.origin_unverified.

export function sayproofErrorKey(problem) {
const detail = String(problem?.detail ?? "").split(":")[0].trim();
const error = String(problem?.error ?? "unknown");
return detail ? `sayproof.${error}.${detail}` : `sayproof.${error}`;
}
export async function sayproofProblem(answer) {
const problem = await answer.json().catch(() => ({}));
return { status: answer.status, key: sayproofErrorKey(problem), requestId: answer.headers.get("X-Request-Id") };
}