API Errors — What Each Code Means and How to Fix It
FastOG returns machine-readable error codes when a request fails — a signed OG image render, or a call to one of the in-product admin surfaces. Every error response includes:
error— the legacy short token. Still present on every failure so an older client keeps working.code— the same stable, documented error code (table below), under the name the public API uses.message— a one-sentence description of what went wrong.hint— a short plain-language description of what went wrong and how to fix it.docs_url— a link to this page, anchored at the section for that code.request_id— correlates this HTTP failure to a row in the dashboard Render Logs table (also returned in theX-Request-IDresponse header). A surface with nothing to correlate answersnull, but the key is always present.
The in-product surfaces — the Shopify admin, the WooCommerce Studio, the Wix bridge and the demo — answer
with the same envelope for the codes below, so a failure means the same thing wherever you meet it. A
module surface may keep the HTTP status it has always returned for a code (for example render_failed
answers 503 on the cover export and 502 on the public API); the code, message, hint and docs link do not change.
Reading an error response
{
"error": "invalid_signature",
"code": "invalid_signature",
"message": "The signature does not match.",
"hint": "The signature did not match. Re-sign with your HMAC secret after every param change.",
"request_id": "5f2a9c1e-..."
}
If you get a response you don't understand, the fastest path is:
- Note the
code. - Check your URL builder — most failures are signing bugs, not account issues.
- Match the code below for the exact cause and fix.
- In the dashboard, open Render Logs and filter by the same
error_code— each row shows the requested params so you can reproduce (and confirmrequest_idmatches).
Signing & authentication
missing_signature
Your request is missing the key and/or s (signature) query parameters.
Fix: ensure your URL includes both key=<api-key> and s=<hmac-signature>. Use the SDK or the /docs/hmac-signature-guide walkthrough to build it.
invalid_signature
The s value did not match what your HMAC secret produces for this URL.
Fix: the signature covers every query param except s, with keys sorted. Changing any param — including reordering, URL-encoding differences, or adding whitespace — invalidates the signature. Re-sign after every change. Confirm your secret is the same one shown when the API key was created.
invalid_signature_format
The s value is not a 64-character hex string.
Fix: the signature must be raw SHA-256 hex (lowercase a-f0-9). If you're base64-encoding or truncating the output, use plain hex.
expired_timestamp
The t timestamp you supplied is more than 5 minutes old.
Fix: regenerate the timestamp each time you build a URL. This code applies to the legacy signed-URL flow; the current HMAC v2 flow has no timestamp.
invalid_api_key
The key you passed does not exist.
Fix: copy the full API key from the dashboard — it's the public identifier starting with sk_. It is public and safe in URLs; the secret (never in URLs) is what proves possession.
missing_hmac_secret
The API key has no HMAC secret configured.
Fix: create a new API key in the dashboard — the HMAC secret is generated and shown once at creation.
Parameter / input
invalid_image_url
A URL-bearing prop (image, brand_logo, logo, avatar, background_image, ...) is not a public http(s) URL.
Fix: pass a publicly fetchable https://... URL. Localhost, private IPs, and bare paths are rejected to prevent server-side request forgery.
Subscription
subscription_required (402)
The request hit the Dynamic API but your account has no active plan. API access is subscription-only: the plan is the gate, and it carries the same coverage + capability ladder the FastOG apps sell. Renders themselves are not metered — there is no monthly render quota and no overage billing.
Fix: choose a Dynamic API plan in the dashboard and create an API key. The response includes a top_up_url pointing at the plans page.
Render service
store_blocked (403)
Rendering for the store behind this key has been paused by FastOG (for example, abuse or runaway usage). Covers already cached at the edge may keep serving until they expire. Contact support to resolve it; nothing you can change in the request will fix this.
render_unreachable
The render service could not be reached (brief restart window).
Fix: retry in a few seconds. The render was not counted for this attempt.
render_failed
The render service returned an error for your request.
Fix: verify your template props — long/malformed values, unsupported fields, or an unreachable upstream image. The response includes the underlying status. The render was not counted.
Store admin surfaces
These codes answer from the Shopify admin and the WooCommerce Studio — the embedded editors a merchant
works in rather than the signed API. Several are shared with the public API (invalid_image_url,
render_failed, invalid_signature); those keep the entry documented above.
| Code | HTTP | What it means and what to do |
|---|---|---|
invalid_shop |
422 | The Shopify shop could not be identified. Reload the FastOG app from your Shopify admin so the embedded request carries the shop again, then retry. |
invalid_shop_or_page |
422 | The shop or the page type is unknown. Open the FastOG app from your Shopify admin and pick a cover page type from the editor. |
invalid_store |
422 | The WooCommerce store could not be identified. Reopen the Studio from your WordPress admin so the store token is presented again, then retry. |
invalid_store_or_page |
422 | The store or the page type is unknown. Reopen the Studio from your WordPress admin and pick a cover page type the editor offers. |
missing_api_key |
422 | The store has no signing key. Finish installing the plugin from your WordPress admin so FastOG can issue the store its signing key. |
store_ownership_unverified |
403 | The WordPress site could not be verified. It must be reachable over public HTTPS with its REST API enabled. |
community_is_free |
422 | The Community plan is free. It is the free default plan and is not purchasable; pick a paid tier to upgrade. |
not_installed |
404 | FastOG is not installed for this shop. Install the FastOG app from the Shopify App Store for this shop, then reopen it. |
oauth_required |
409 | The shop needs to authorise FastOG again. Run the FastOG OAuth install again from your Shopify admin; the stored grant was revoked or its scopes changed. |
reconnect_required |
409 | The Shopify connection needs to be re-established. Use the Reconnect button in the FastOG app so a fresh access token is issued. |
token_rejected |
409 | Shopify issued an access token and then refused it. Retry the reconnect once; if Shopify keeps refusing it, reinstall the app. |
unauthorized |
401 | The request carries no valid session for this surface. Reload the FastOG app from your platform admin so a fresh session token is attached, then retry. |
shop_not_found |
404 | The shop no longer exists in FastOG. Reinstall FastOG from your Shopify admin to recreate the shop record. |
invalid_product |
422 | The product reference is not valid. Reload the product page and reopen FastOG; the product id sent was missing or not numeric. |
invalid_product_cover |
422 | The product cover payload is malformed. Reload the editor and save again; props, style and signals must each be an object. |
product_not_found |
404 | The product could not be read from the store. Check the product still exists and is published, then reload the editor. |
product_customization_not_on_plan |
403 | Per-product cover customisation is not on this plan. Upgrade, or edit the shared product cover instead. |
no_product_handles |
422 | No products were found to refresh. Publish at least one product with a public handle, then try the share-preview refresh again. |
invalid_style |
422 | The style block is not usable. Reload the editor and re-pick the colours and fonts; one value could not be normalised. |
invalid_template |
422 | The requested template is not in this platform catalogue. Pick one of the layouts the editor offers. |
invalid_preset |
422 | The preset name is not one this platform offers. Pick a preset from the setup screen. |
invalid_set |
422 | The cover set payload is missing or malformed. Reload the setup screen and pick a set again. |
preset_not_applyable |
422 | The preset cannot be applied to every page type. Pick another preset; this one is missing a cover for at least one page type. |
template_not_available |
422 | The template is not in the renderable catalogue. Pick a layout the picker offers. |
template_not_available_on_shopify |
422 | The template is not available on Shopify stores. Pick a layout the Shopify editor offers. |
template_not_available_on_woocommerce |
422 | The template is not available on WooCommerce stores. Pick a layout the Studio offers. |
template_unavailable |
422 | The template is not available for this store. Pick a layout the editor offers; it is retired, unknown, or above what the store may draw. |
template_not_on_plan |
403 | The template needs a higher plan. Change plan, or pick a layout the current plan covers. The response names the plan in requires. |
template_requires_higher_plan |
403 | The template needs a higher plan. The response names the plan in requires. |
no_rule |
404 | There is no cover rule for this page type yet. Save a cover for this page type in the editor first. |
cover_not_configured |
404 | No product cover has been saved yet. Save a product cover before downloading or sharing it. |
schedule_only_product |
422 | Campaign scheduling only exists for product covers. Remove the revert date, or move the campaign to the product cover. |
not_dismissible |
422 | That announcement cannot be dismissed. Reload the page; it has already been retired or belongs to another shop. |
unsupported_locale |
422 | That UI language is not bundled for this app. Pick one of the languages the response lists in supported. |
no_setup_sets |
422 | No curated cover sets could be assembled. Retry the setup screen; if it stays empty, contact support. |
export_unavailable |
403 | Downloads are not on this plan. Upgrade to Pro or above to download cover files. |
cancellation_failed |
502 | The subscription cancellation was refused. Retry in a moment; if it keeps failing, cancel from the Shopify billing page or contact support. |
logo_override_on_plan |
403 | The logo override is not on this plan. Upgrade, or clear the logo override. |
invalid_logo |
422 | The logo file is not an accepted image. Upload a PNG, JPEG or WebP under the size cap shown in the editor. |
invalid_brand_image |
422 | The brand reference image is not usable. Upload a supported image under the size cap, or clear the reference and save again. |
brand_image_too_large |
422 | The brand reference image is too large. Shrink the file and upload it again. |
brand_colors_too_many |
422 | More than three brand colours were supplied. Send at most three hex colours. |
upload_failed |
500 | The uploaded file could not be stored. Retry; if it keeps failing, contact support — the asset store returned no public URL. |
attachment_upload_failed |
500 | The support attachment could not be stored. Send the message without the attachment, then email the file to support. |
invalid_webhook |
401 | The store webhook signature did not verify. Check the webhook secret in your WordPress FastOG settings matches the one FastOG issued. |
not_found |
404 | That endpoint no longer exists. Reopen the Studio from your WordPress admin. |
meta_refresh_unavailable |
503 | Share-preview refresh is not configured. Re-share the link from Facebook instead. |
theme_write_disabled |
409 | Theme editing is not enabled for this app. Use the theme app embed instead of the theme-file fix. |
scope_required |
403 | FastOG is missing a Shopify permission. Approve the requested scopes using the consent_url in the response, then retry the fix. |
Wix bridge
The Wix bridge is signed by the Wix app, not a merchant session, so its failures are addressed to the app
developer. Every response still carries code and request_id; the bridge request id is the one from the
signed envelope.
| Code | HTTP | What it means and what to do |
|---|---|---|
invalid_bridge_signature |
401 | The Wix bridge signature did not verify. Re-mint the request with the shared secret, the exact path and a timestamp under five minutes old. |
invalid_bridge_body |
400 | The bridge envelope body is malformed. Send body as a JSON object and encode every number inside it as a string, so the canonical signature matches. |
replayed_bridge_request |
401 | That bridge request was already used. Mint a new request_id for each mutating call. |
wix_site_not_installed |
403 | FastOG is not installed on this Wix site. Install the FastOG app on the site, then reopen it. |
wix_site_not_provisioned |
422 | The Wix site has no signing credentials yet. Reinstall the FastOG app so the site is provisioned with an API key. |
invalid_page_type |
422 | The page type is not one FastOG covers on Wix. Send one of the page types the Studio offers. |
rule_not_found |
404 | There is no rule with that id. Refresh the list; the rule was deleted or belongs to another site. |
invalid_target_id |
422 | The Wix target id is not valid for this page type. Send the id the Wix app supplies for that page type. |
invalid_preview |
422 | The preview payload is malformed. Read the details object for the failing field. |
invalid_rule |
422 | The cover rule payload is malformed. Read the details object; template is required and the optional blocks must be objects. |
invalid_sync |
422 | The sync payload is malformed. Read the details object; target_type and target_id must agree. |
invalid_regenerate_url |
422 | The URL to regenerate is missing. Send the page URL in url. |
invalid_regenerate_host |
422 | The URL does not belong to the FastOG host. Send a fastog.com cover URL. |
ai_presets_unsupported |
422 | AI-designed cover sets are no longer generated. Pick one of the curated looks instead. |
original_tags_required |
422 | The original metadata tags are required. Send original_tags (or current_tags) so an uninstall can restore the site metadata. |
invalid_restored |
422 | The restored-keys payload is malformed. Send restored as an array of metadata keys. |
invalid_seo_target |
422 | The SEO target type is unknown. Use site, pattern or item in the path. |
invalid_seo_payload |
422 | The SEO metadata payload is malformed. Send target_id, current_tags and fastog_url as an absolute http(s) URL. |
sync_failed |
500 | The metadata sync to Wix failed. Retry; if it keeps failing, check the site is reachable and the app is still installed. |
invalid_tier |
422 | That plan is not one FastOG sells on Wix. Send starter, pro or scale as the tier. |
Demo surface
The demo is the owner-only sales console, not a merchant endpoint.
| Code | HTTP | What it means and what to do |
|---|---|---|
url_required |
422 | No URL was sent. Paste the store or product link before reading the card. |
unreadable_url |
422 | That page could not be read. Check the link is public and complete; a page behind a login cannot be read. |
no_api_key |
422 | No API key is available to sign covers. Create an API key (or enter a valid one); the response links to the API keys page. |
no_presets |
500 | No cover presets are configured. Configure at least one preset on the server. |
Scoped-rule editor codes
The scoped-rule editors (Shopify admin and WooCommerce Studio) translate these tokens themselves, into the
merchant's own language, so their responses carry error and code but no hint — a second English
description would only drift from the localized one the merchant actually sees:
scope_already_defined, scoped_rule_limit_reached, scoped_rules_not_on_plan,
scope_value_required, scope_value_too_long, unknown_scope_type, base_rule_required,
scoped_rules_product_only, cannot_delete_base_rule.
Still stuck?
- Open the dashboard Render Logs page — every outcome (success + rejection) is listed with its
error_code, HTTP status, and the requested params. - Run
php artisan og:diagnoseon a signed URL to walk the whole pipeline and see which stage fails. - Check the docs in the sidebar for the framework you're using (Next.js, Express, SvelteKit, ...).