Skip to content
ShopAssist Docs
API

Errors

The error envelope, every error code and the detail reasons the ShopAssist API returns.

Every non-2xx JSON response has the same shape:

{
  "error": {
    "code": "forbidden",
    "message": "This API key lacks the required scope.",
    "details": { "required_scope": "leads:read" },
    "request_id": "req_01k6a8x3qv6f2m9c4j7t5r0bwe"
  }
}
  • code is stable; branch on it, not on message or the HTTP status alone.
  • details depends on the code (for validation errors it lists the invalid fields).
  • request_id identifies the request in our logs.

Validation errors are always 422 validation_error, with details.fields as [{ loc, msg, type }]. Unknown request fields are rejected. Ignore unknown fields and unknown enum values in responses: they may be added at any time.

Error codes

Error codes
CodeMeaning
bad_requestThe request is malformed, for example invalid JSON or a missing required header. Fix the request before retrying.
invalid_idAn id has the wrong prefix (for example `sto_` where `conv_` was expected) or cannot be decoded.
invalid_cursorThe pagination cursor is invalid or has expired. Start again from the first page.
unauthenticatedNo valid credentials were sent. Send `Authorization: Bearer sa_live_…` (merchant API) or sign in again.
session_invalidThe widget session is missing, expired or revoked. The widget creates a new session automatically.
identity_requiredThe operation needs a verified shopper identity (signed in, or an order verified by email code).
identity_invalidThe identity token could not be verified. `details.reason` says which check failed (signature, issuer, audience, expiry).
mfa_requiredMulti-factor authentication is required, or a recent sign-in is needed for a sensitive change.
signature_invalidA webhook, plugin or proxy signature did not verify. Check the secret and the server clock.
forbiddenThe credentials are valid but not allowed to do this, for example a missing API key scope or a test key calling a write endpoint.
origin_not_allowedThe page's origin is not in the store's allowed domains. Add the domain in the dashboard.
csrf_failedThe request's `Origin` header could not be verified. Browsers send it automatically; reload the page.
email_not_verifiedThe account email must be verified before this action.
plan_feature_unavailableThe feature is not in the current plan. `details.required_plan` names the lowest plan that has it.
plan_limit_exceededA plan limit was reached. `details` holds `limit`, `value` and `max`.
store_suspendedThe store is suspended. Contact support.
organization_suspendedThe organization is suspended. Contact support.
challenge_requiredA bot-protection challenge must be solved before the request is accepted.
verification_code_invalidThe one-time code is wrong. `details.attempts_remaining` says how many attempts are left.
not_foundThe resource does not exist or is not visible to these credentials.
method_not_allowedThe HTTP method is not allowed on this path.
conflictThe request conflicts with the current state. `details.reason` explains the conflict.
response_in_progressThe assistant is still answering in this conversation. Wait for the current reply.
conversation_closedThe conversation is closed. Start a new one.
action_not_pendingThe proposed action is no longer waiting for confirmation (already confirmed, declined or expired).
sync_in_progressA sync of this kind is already running for the store.
idempotency_in_progressA request with the same `Idempotency-Key` is still being processed. Retry after a moment.
action_expiredThe confirmation card expired before it was confirmed.
verification_expiredThe verification (for example an email code) expired. Request a new one.
token_expiredThe link or token has expired or was already used.
version_conflictThe resource was changed by someone else since you read it. Reload and apply your change again.
payload_too_largeThe request body exceeds the size limit of the endpoint.
message_too_longThe chat message exceeds the maximum length.
file_too_largeThe uploaded file exceeds the size limit.
unsupported_media_typeThe content type is not supported by this endpoint.
validation_errorThe request failed validation. `details.fields` lists each field with its location, and `details.reason` names rule failures.
idempotency_key_reusedThe `Idempotency-Key` was already used with a different request body.
action_no_longer_eligibleThe action is no longer possible, for example because the order shipped in the meantime.
verification_lockedToo many wrong codes were entered. Request a new code later.
rate_limitedToo many requests. Wait for the number of seconds in `Retry-After`; `details.scope` names the limit.
quota_exceededThe usage quota was reached. `details.reason` says which quota (for example `free_cap_reached`).
internal_errorSomething went wrong on our side. Retry with backoff and contact support with the `request_id` if it persists.
not_implementedThe endpoint exists in the contract but is not available yet.
platform_errorThe store platform did not respond as expected. `details.retryable` says whether a retry can help.
service_unavailableShopAssist is temporarily unavailable, for example during maintenance. Retry after `Retry-After`.

Detail reasons

Some codes carry details.reason with a more specific cause:

unauthenticated

details.reason values of unauthenticated
ReasonMeaning
code_invalidThe connection or pairing code is unknown, expired, already used or does not match the platform.

identity_invalid

details.reason values of identity_invalid
ReasonMeaning
malformedThe token is not a valid JWT.
algorithmThe token is not signed with HS256.
unknown_kidThe `kid` header does not match the store's current or previous identity key.
signatureThe signature does not verify with the identity secret.
issuer`iss` is not `generic:{store_id}` (or the platform issuer).
audience`aud` is not `shopassist`.
session_mismatch`sid` is not the widget session that requested the token.
expiredThe token has expired.
not_yet_valid`iat` or `nbf` lies in the future (check the server clock).
lifetime_too_long`exp − iat` is longer than 300 seconds.

mfa_required

details.reason values of mfa_required
ReasonMeaning
mfa_pendingSign-in is waiting for the second factor.
recent_auth_requiredThis change needs a recent sign-in or a fresh MFA code.

session_invalid

details.reason values of session_invalid
ReasonMeaning
missingNo session token was sent.
malformedThe session token cannot be parsed.
signatureThe session token signature is invalid.
store_mismatchThe session belongs to another store.
origin_mismatchThe session was created on another origin.
expiredThe session expired.
revokedThe session was revoked.

signature_invalid

details.reason values of signature_invalid
ReasonMeaning
headers_missingSignature headers are missing.
unknown_storeThe store in the signature is unknown.
unknown_keyThe key id is not known for the store.
timestampThe timestamp is outside the allowed window; check the server clock.
nonceThe nonce was already used.
store_mismatchThe key belongs to a different store.
signatureThe signature does not match.

forbidden

details.reason values of forbidden
ReasonMeaning
abuse_blockedThe visitor or session is blocked by abuse protection.
test_keyTest keys cannot call write endpoints.
email_mismatchThe invitation is for a different email address.
ip_not_allowedThe request IP is not allowed for this endpoint.
support_access_not_grantedThe merchant has not granted support access.
operator_mfa_requiredOperators need TOTP multi-factor authentication.
feature_disabledThe feature is switched off for this store.
not_genericThis endpoint only works for stores connected with the Generic connector.

challenge_required

details.reason values of challenge_required
ReasonMeaning
invalid_solutionThe challenge solution was wrong.
expiredThe challenge expired.

conflict

details.reason values of conflict
ReasonMeaning
identity_changedThe signed-in shopper changed during the conversation.
identity_required_for_conversationThis conversation belongs to a signed-in shopper.
store_already_connectedThe site is already connected to another ShopAssist store.
clone_detectedThe connection looks like a copy of another site (staging clone).
feed_authoritativeA product feed owns this catalog; the Push API cannot write to it.
generic_onlyThe operation is available only for Generic stores.
no_deletion_scheduledNo deletion is scheduled that could be cancelled.
scope_requiredA platform scope is missing (`details.scope`).
handoff_activeA handoff is already active.
open_conversations_limitToo many open conversations for this session.
images_limitThe image limit of the conversation is reached.
retry_not_allowedThe message cannot be retried.
already_taken_overAnother agent already took over.
not_assigneeOnly the assigned agent can do this.
mode_not_humanThe conversation is not in human mode.
billed_by_shopifyThe account is billed by Shopify; change the plan in Shopify.
manual_billingThe account is billed manually by COEC.
contact_salesThis change needs a sales contact.
subscription_existsA subscription already exists.
unpaid_invoicesThere are unpaid invoices.
currency_lockedThe billing currency cannot change after the first invoice.
no_subscriptionThere is no subscription.
no_changeThe requested plan is the current plan.
payment_past_dueA payment is past due.
payment_method_requiredAdd a payment method first.
no_scheduled_changeNo plan change is scheduled.
no_customerNo billing customer exists yet.
annual_cancel_in_dashboardCancel annual plans in the dashboard.
scheduled_change_pendingA plan change is already scheduled.
not_shopifyThe account is not billed by Shopify.
run_closedThe replace_all run is already finished or expired; start a new run.

validation_error

details.reason values of validation_error
ReasonMeaning
too_shortThe password is too short.
password_too_longThe password is too long.
context_wordThe password contains your name, email or the product name.
common_passwordThe password is too common.
breached_passwordThe password appeared in a data breach.
password_requiredA password is required.
terms_version_outdatedThe terms were updated; reload and accept the current version.
https_requiredThe URL must use HTTPS.
port_not_allowedThe URL uses a port that is not allowed.
url_not_publicThe URL does not resolve to a public internet address.
ssrf_blockedThe URL points to a private or reserved network.
base_url_forbiddenThis base URL is not allowed.
privacy_policy_url_originThe privacy policy URL must be on the store's own domain.
malware_detectedThe file failed the malware scan.
residency_ack_requiredConfirm the BYOK data-processing attestation.
invalid_key_formatThe API key does not have the provider's format.
key_provider_mismatchThe key belongs to a different provider.
gemini_free_tierFree-tier Gemini keys are not accepted; use a paid-tier key.
unknown_modelThe model is not known for this provider.
api_key_requiredAn API key is required.
rule_overrideThe text tries to override a fixed assistant rule.
discount_code_not_registeredThe text mentions a discount code that is not registered.
ai_disclosure_conflictThe text would hide or deny that the assistant is an AI.
persona_name_implies_humanThe assistant name suggests a human.
unfair_practice_lintThe text uses fake urgency or scarcity.
consent_text_lintThe consent text is not specific enough.
unknown_consent_text_versionThe consent text version is unknown.
cmp_category_map_requiredMap your consent tool's categories first.
attestation_requiredAn attestation must be confirmed first.
version_not_currentThe legal document version is not the current one.
store_requiredThe attestation needs a store.
site_mismatchThe ShopAssist store is connected to a different site.
use_shopify_app_storeShopify stores are installed from the Shopify App Store.
signature_invalid_check_offloader_headerMagento could not verify our requests; set the offloader header.
waf_blockedA firewall blocked ShopAssist.
basic_authThe store is protected by HTTP Basic authentication.
unreachableShopAssist could not reach the store.
acl_missingThe Magento integration lacks permissions.
rest_blockedThe WordPress REST API is blocked for our requests.
signature_invalidThe connection signature could not be verified; check the server clock.
not_purchasableThe product cannot be bought.
out_of_stockThe variant is out of stock.
excludedThe product is hidden from the assistant.
max_qtyThe quantity exceeds the maximum.
max_extensionsThe confirmation cannot be extended again.
in_stockThe variant is in stock, so no back-in-stock alert is needed.
consent_requiredConsent is required first.
credential_rejectedThe integration rejected the credentials.
currency_not_allowedThe currency is not offered.
country_requiredA billing country is required.
trial_plan_invalidTrials are only for the trial plan.
trial_already_redeemedA trial was already used for this store domain.
store_not_connectedConnect the store first.
currency_mismatchThe currency does not match the billing account.
amount_out_of_rangeThe amount is outside the allowed range.
url_not_allowedThe URL is not https on one of the store's origins or allowed link domains.
template_invalidThe URL template is invalid (unknown placeholders, or {items} missing).
mapping_invalidThe field mapping could not be applied to the feed.
header_not_allowedThis HTTP header name may not be set on outgoing feed or RPC requests.
run_fields_requiredThis request needs the run fields (run_id and mode) of an open import run.
provider_pricedThis billing account is priced by its provider (e.g. Shopify), so this override is not allowed.

action_no_longer_eligible

details.reason values of action_no_longer_eligible
ReasonMeaning
status_changedThe order status changed.
already_shippedThe order has shipped.
ownershipThe order does not belong to the shopper.
policyThe store's policy does not allow it.
window_closedThe time window has closed.

rate_limited

details.reason values of rate_limited
ReasonMeaning
auth_ipToo many sign-in attempts from this address.
auth_accountToo many sign-in attempts for this account.
auth_lockoutSign-in is temporarily locked after failed attempts.
visitor_conversationsToo many new conversations from this visitor.
live_streamsToo many open live streams.
test_conversationsToo many test conversations.
shopper_mailToo many emails to this shopper.
webhook_testToo many webhook test deliveries.

quota_exceeded

details.reason values of quota_exceeded
ReasonMeaning
test_daily_cap_reachedThe daily limit of test AI replies is reached.
free_cap_reachedThe Free plan's monthly conversation cap is reached.
trial_cap_reachedThe trial's conversation cap is reached.
overage_budget_reachedThe overage budget is used up.
subscription_inactiveThe subscription is not active.
managed_ai_not_includedManaged AI is not included in the plan.
byok_cap_reachedThe own-key conversation allowance is reached.
plan_cap_reachedThe plan's included conversations are used and overage is off.
store_over_plan_limitThe store is over the plan's store limit.

Retrying

Retry 429, 502 with details.retryable: true, 503 and network errors with exponential backoff, honouring Retry-After. Use an idempotency key on POST requests you retry.

Last updated on

On this page