Home

STOQ API v2 (Beta)

v2.0.0-beta

Contact: support@stoqapp.com

Base URL
https://app.stoqapp.com/api/v2/externalProduction

STOQ's action-driven, AI-native external API. Every action is self-describing (description, aliases, notes, JSON request schema) and also reachable via the /help manifest, skill.md, llms.txt, and the MCP server. Public beta — actions and schemas may change before GA. All endpoints require the X-Auth-Token API key.

Authentication

ApiKeyAuthapiKey

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

API Key: X-Auth-Token in header

Account · Help Docs

Read

GET
https://app.stoqapp.com/api/v2/external/account/help_docs

Search the STOQ help centre, or read one help article in full. Use for how-to and explanation questions — how a feature works, how to set something up, what a setting means. Search first, then read the article that matches before relaying step-by-step instructions; the snippets are previews, not the whole answer.

Parameters

queryanyquery
urlanyquery
limitanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/account/help_docs'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/help_docs', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/account/help_docs')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Account · Integrations

Read

GET
https://app.stoqapp.com/api/v2/external/account/integrations

Connection state of Klaviyo, Postscript, Omnisend and Mailchimp, where new signups are synced (Klaviyo, Omnisend, Mailchimp, Shopify customers, with the customer tag), the Mailchimp audience, and the Meta Pixel, Shopify Flow trigger and SplitOrder switches. Returns connected / verified flags only, never keys or tokens.

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/account/integrations'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/integrations', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/account/integrations')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Update

PATCH
https://app.stoqapp.com/api/v2/external/account/integrations

Update the shop's integrations: sync signups to Klaviyo, Omnisend, Mailchimp or Shopify customers (with the customer tag), the Omnisend and Mailchimp API keys and Mailchimp audience, the Meta Pixel, Shopify Flow triggers and the SplitOrder app switch. API keys are write only; reads return connected flags.

Note: Deep partial. omnisend.api_key and mailchimp.api_key are never returned by any read; an empty string removes the saved key. A Mailchimp key is checked by fetching the account's audiences and is not saved when Mailchimp refuses it; mailchimp.list_id must be one of those audiences. Klaviyo connects with OAuth from the Integrations page; this action only turns its sync on or off. flow_triggers.triggers replaces the stored list.

Body

application/json
klaviyoany
omnisendany
mailchimpany
shopifyany
sync_customers_tagany
meta_pixelany
flow_triggersany
split_order_appany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Update
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/account/integrations' \
  -H 'Content-Type: application/json' \
  -d '{
    "klaviyo": "string",
    "omnisend": "string",
    "mailchimp": "string",
    "shopify": "string",
    "sync_customers_tag": "string",
    "meta_pixel": "string",
    "flow_triggers": "string",
    "split_order_app": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/integrations', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "klaviyo": "string",
      "omnisend": "string",
      "mailchimp": "string",
      "shopify": "string",
      "sync_customers_tag": "string",
      "meta_pixel": "string",
      "flow_triggers": "string",
      "split_order_app": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "klaviyo": "string",
  "omnisend": "string",
  "mailchimp": "string",
  "shopify": "string",
  "sync_customers_tag": "string",
  "meta_pixel": "string",
  "flow_triggers": "string",
  "split_order_app": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/account/integrations', json=payload)
data = response.json()
Request Body
{
  "klaviyo": "string",
  "omnisend": "string",
  "mailchimp": "string",
  "shopify": "string",
  "sync_customers_tag": "string",
  "meta_pixel": "string",
  "flow_triggers": "string",
  "split_order_app": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Account · Languages

Read

GET
https://app.stoqapp.com/api/v2/external/account/languages

The shop's languages: default_locale (the language alerts and the signup widget use), app_locale (the dashboard language), whether multi-language support and translated product titles are on, and, when multi-language is on, the locales published in Shopify.

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/account/languages'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/languages', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/account/languages')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Update

PATCH
https://app.stoqapp.com/api/v2/external/account/languages

Update the shop's language settings: the dashboard language (app_locale), multi-language alerts and widget, and translated product titles in alerts.

Note: app_locale only changes the merchant dashboard. multi_language_enabled false also turns product_translations_enabled off. product_translations_enabled true needs the read_translations access the Settings page asks for; the call fails until it is granted.

Body

application/json
app_localeany
multi_language_enabledany
product_translations_enabledany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Update
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/account/languages' \
  -H 'Content-Type: application/json' \
  -d '{
    "app_locale": "fr",
    "multi_language_enabled": true,
    "product_translations_enabled": true
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/languages', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "app_locale": "fr",
      "multi_language_enabled": true,
      "product_translations_enabled": true
    }),
});

const data = await response.json();
import requests

payload = {
  "app_locale": "fr",
  "multi_language_enabled": True,
  "product_translations_enabled": True
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/account/languages', json=payload)
data = response.json()
Request Body
{
  "app_locale": "fr",
  "multi_language_enabled": true,
  "product_translations_enabled": true
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Account · Locations

Read

GET
https://app.stoqapp.com/api/v2/external/account/locations

The store's Shopify locations: id, name, and whether each is active. Use it to name the location ids in back-in-stock delivery settings and in markets.

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/account/locations'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/locations', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/account/locations')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Account · Markets

Read

GET
https://app.stoqapp.com/api/v2/external/account/markets

The store's Shopify Markets (international selling) configuration: active markets, whether the store sells to multiple markets, each market's countries, and which Shopify locations the merchant has linked to each market (location_ids). Distinct from an offer's market availability or restock-alert locations. Only active markets are returned by default.

Parameters

include_draftsanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/account/markets'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/markets', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/account/markets')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Account · Plan Usage

Read

GET
https://app.stoqapp.com/api/v2/external/account/plan_usage

The shop's current STOQ plan and a billing month's usage vs included limits, with the usage-based charges STOQ has metered.

Parameters

periodanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/account/plan_usage'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/plan_usage', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/account/plan_usage')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Account · Products

Read

GET
https://app.stoqapp.com/api/v2/external/account/products

List product variants with their preorder offer link (if any) and back-in-stock waitlist count, sorted by waitlist size (most demand first). search matches product name, variant title, SKU, a storefront/admin product URL, or a numeric/GID product or variant id.

Parameters

filteranyallpreorderback_in_stockquery
searchanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/account/products'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/products', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/account/products')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Account · Sending

Read

GET
https://app.stoqapp.com/api/v2/external/account/sending

Who sends the shop's customer notifications: the email provider (stoq, klaviyo, flow) and SMS provider, the sender address, sender name and reply-to, the custom sending domain and its DKIM check, whether SMS sending is approved, and whose account sends: email_account and sms_account are "stoq" (STOQ's own email or SMS service, including sms_provider "twilio") or "merchant" (their Klaviyo, Postscript or Shopify Flow with saved credentials); email_sender_domain is "merchant" when mail comes from their verified address.

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/account/sending'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/sending', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/account/sending')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Update

PATCH
https://app.stoqapp.com/api/v2/external/account/sending

Update who sends the shop's customer notifications: email and SMS provider, sender name, the merchant's own sending address, store domain in SMS links, Klaviyo marketing consent and the Postscript API key (write only).

Note: Applies to back-in-stock and preorder notifications. use_custom_email_address true needs email_reply_to_address on a domain that is not a free mail provider, and DKIM set up for it before mail goes out from it. postscript_api_key is never returned by any read; it is checked with Postscript and not saved when Postscript refuses it; "" removes it.

Body

application/json
email_providerany
sms_providerany
email_from_nameany
use_custom_email_addressany
email_reply_to_addressany
sms_custom_domain_enabledany
klaviyo_skip_auto_subscribeany
postscript_api_keyany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Update
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/account/sending' \
  -H 'Content-Type: application/json' \
  -d '{
    "email_provider": "string",
    "sms_provider": "string",
    "email_from_name": "Summer Sneaker Drop",
    "use_custom_email_address": "string",
    "email_reply_to_address": "string",
    "sms_custom_domain_enabled": true,
    "klaviyo_skip_auto_subscribe": "string",
    "postscript_api_key": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/sending', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "email_provider": "string",
      "sms_provider": "string",
      "email_from_name": "Summer Sneaker Drop",
      "use_custom_email_address": "string",
      "email_reply_to_address": "string",
      "sms_custom_domain_enabled": true,
      "klaviyo_skip_auto_subscribe": "string",
      "postscript_api_key": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "email_provider": "string",
  "sms_provider": "string",
  "email_from_name": "Summer Sneaker Drop",
  "use_custom_email_address": "string",
  "email_reply_to_address": "string",
  "sms_custom_domain_enabled": True,
  "klaviyo_skip_auto_subscribe": "string",
  "postscript_api_key": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/account/sending', json=payload)
data = response.json()
Request Body
{
  "email_provider": "string",
  "sms_provider": "string",
  "email_from_name": "Summer Sneaker Drop",
  "use_custom_email_address": "string",
  "email_reply_to_address": "string",
  "sms_custom_domain_enabled": true,
  "klaviyo_skip_auto_subscribe": "string",
  "postscript_api_key": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Account · Settings

Read

GET
https://app.stoqapp.com/api/v2/external/account/settings/{section_id}

One settings section: label, description, settings (the output of the read actions behind it, keyed by block, e.g. settings.widget is GET /back_in_stock/settings/widget), columns (field path => model column) and raw (field path => stored value). Sections: delivery_settings, signup_widget, notification_channels, notification_templates, preorder_notifications, integrations, languages.

Parameters

section_idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/account/settings/{section_id}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/settings/{section_id}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/account/settings/{section_id}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Account · Templates

Translations

GET
https://app.stoqapp.com/api/v2/external/account/templates/{campaign_type}/translations

Read every translation override on a notification template, plus the full enumeration of translatable field paths, each field's default-locale source text, and every locale the shop has actually published.

Parameters

campaign_typestringrequiredpath
positionanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Translations
curl -X GET 'https://app.stoqapp.com/api/v2/external/account/templates/{campaign_type}/translations'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/templates/{campaign_type}/translations', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/account/templates/{campaign_type}/translations')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Account · Translations

Read

GET
https://app.stoqapp.com/api/v2/external/account/translations

Read every translation override on the shop's notify-me button, signup form, and preorder button/modal text, plus the full enumeration of translatable field paths, each field's default-locale source text, and every locale the shop has actually published.

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/account/translations'
const response = await fetch('https://app.stoqapp.com/api/v2/external/account/translations', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/account/translations')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Back In Stock · Copilot

Settings

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/settings

Read all back-in-stock settings for a Copilot preview.

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Settings
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/settings'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/settings', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/settings')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Settings

PATCH
https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/settings

Patch back-in-stock channels, delivery, compliance, tagging, or alerts settings. delivery.batching.mode "multiplier" sends restocked-quantity x multiplier per batch; "fixed" sends batch_size per batch. delivery.stock_threshold must be >= 1. delivery.locations.location_ids and delivery.any_variant.product_ids REPLACE the stored list wholesale; any_variant.all_products true ignores product_ids. Enabling SMS for the first time puts sends on a verification hold until the shop is approved.

Body

application/json
channelsany
deliveryany
complianceany
taggingany
alertsany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Settings
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/settings' \
  -H 'Content-Type: application/json' \
  -d '{
    "channels": "string",
    "delivery": "string",
    "compliance": "string",
    "tagging": "string",
    "alerts": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/settings', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "channels": "string",
      "delivery": "string",
      "compliance": "string",
      "tagging": "string",
      "alerts": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "channels": "string",
  "delivery": "string",
  "compliance": "string",
  "tagging": "string",
  "alerts": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/settings', json=payload)
data = response.json()
Request Body
{
  "channels": "string",
  "delivery": "string",
  "compliance": "string",
  "tagging": "string",
  "alerts": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Signups

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}

Read one back-in-stock signup for a Copilot preview.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Signups
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Signups Create

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/create

Create one back-in-stock signup for the selected variant. channel must be "email" or "sms"; pass email for the email channel or phone for sms.

Body

application/json
channelanyrequired
quantityinteger
emailany
phoneany
nameany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Signups Create
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/create' \
  -H 'Content-Type: application/json' \
  -d '{
    "channel": "string",
    "quantity": 5,
    "email": "shopper@example.com",
    "phone": "+15551234567",
    "name": "Summer Sneaker Drop"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/create', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "channel": "string",
      "quantity": 5,
      "email": "shopper@example.com",
      "phone": "+15551234567",
      "name": "Summer Sneaker Drop"
    }),
});

const data = await response.json();
import requests

payload = {
  "channel": "string",
  "quantity": 5,
  "email": "shopper@example.com",
  "phone": "+15551234567",
  "name": "Summer Sneaker Drop"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/create', json=payload)
data = response.json()
Request Body
{
  "channel": "string",
  "quantity": 5,
  "email": "shopper@example.com",
  "phone": "+15551234567",
  "name": "Summer Sneaker Drop"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Signups Delete

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/delete

Delete one pending back-in-stock signup.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Signups Delete
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/delete'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/delete', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/delete')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Signups Notify

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/notify

Queue a notification for one back-in-stock signup.

Body

application/json
allow_resendany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Signups Notify
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/notify' \
  -H 'Content-Type: application/json' \
  -d '{
    "allow_resend": true
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/notify', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "allow_resend": true
    }),
});

const data = await response.json();
import requests

payload = {
  "allow_resend": True
}

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/notify', json=payload)
data = response.json()
Request Body
{
  "allow_resend": true
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Signups Transfer

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/transfer

Transfer one pending back-in-stock signup to another variant. to_shopify_variant_id is the target Shopify variant ID (obtainable from get_offer_variants).

Body

application/json
to_shopify_variant_idanyrequired
to_shopify_product_idany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Signups Transfer
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/transfer' \
  -H 'Content-Type: application/json' \
  -d '{
    "to_shopify_variant_id": "45000000001",
    "to_shopify_product_id": "78000000001"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/transfer', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "to_shopify_variant_id": "45000000001",
      "to_shopify_product_id": "78000000001"
    }),
});

const data = await response.json();
import requests

payload = {
  "to_shopify_variant_id": "45000000001",
  "to_shopify_product_id": "78000000001"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/copilot/signups/{id}/transfer', json=payload)
data = response.json()
Request Body
{
  "to_shopify_variant_id": "45000000001",
  "to_shopify_product_id": "78000000001"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Back In Stock · Notifications

List

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/notifications

List back-in-stock notifications (the send log) in this shop, paginated.

Note: status=blocked surfaces sends stopped by plan limits (with blocked_reason).

Parameters

channelanyemailsmspushquery
statusanysentblockedquery
variant_idanyquery
product_idanyquery
fromanyquery
toanyquery
pageanyquery
per_pageanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

List
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/notifications'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/notifications', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/notifications')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Read

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/notifications/{id}

Read one back-in-stock notification (a single send-log entry).

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/notifications/{id}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/notifications/{id}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/notifications/{id}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Back In Stock · Orders

List

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/orders

List orders placed after a back-in-stock alert, paginated. search matches order number/name, customer name, or email.

Parameters

pageanyquery
per_pageanyquery
searchanyquery
customer_idanyquery
fromanyquery
toanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

List
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/orders'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/orders', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/orders')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Back In Stock · Products

Read

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/products

Read per-product back-in-stock configuration: notify-me button visibility (always_show / when_out_of_stock / never_show), restock message and assigned template for each variant, plus whether the shop-level per-product customization toggle is on. Filter with shopify_product_id, shopify_variant_id, or overrides_only=true.

Parameters

shopify_product_idanyquery
shopify_variant_idanyquery
overrides_onlyanyquery
limitanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/products'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/products', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/products')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Update

PATCH
https://app.stoqapp.com/api/v2/external/back_in_stock/products

Update per-product back-in-stock configuration for one or more products or variants (the "Back in stock alerts -> Products" tab). targets is a list; a target with shopify_variant_id changes just that VARIANT, a target with only shopify_product_id changes EVERY variant of that product. The same field values are applied to every target, so send one call per distinct set of values. button_visibility is one of "always_show" (notify-me button shown even while the item is IN stock -- WARNING: this also DISABLES automatic back-in-stock alerts for that variant, so the merchant has to notify signups manually), "when_out_of_stock" (the default: button appears only when out of stock and alerts send automatically) or "never_show" (button hidden on the storefront). restock_message is the free-text note shown under the button (e.g. "Back in stock March 15"); send an empty string to clear it. template is a back-in-stock template name or id, or "default" to fall back to the global widget design. automatic_alerts_enabled (true/false) directly sets whether this variant receives an automatic back-in-stock alert on restock -- the same control as the variant's own "Enable/Disable alerts" button, independent of button_visibility. Use this to fix a variant showing "Disabled" for automatic alerts in get_bis_products (get_bis_products.automatic_alerts_enabled), not button_visibility. If both button_visibility: "always_show" and automatic_alerts_enabled are sent in the same call, automatic_alerts_enabled wins. Per-product visibility/message/template values only take effect while the shop-level toggle configure_notify_me_enabled is on; when it is off this action refuses rather than store values that would not apply, unless enable_customization: true is passed, which turns the toggle on as part of this change (a no-op when already on). automatic_alerts_enabled is NOT gated by configure_notify_me_enabled -- it applies regardless. per_product_customization_enabled (true/false), sent on its own with no targets, turns that shop-level toggle on or off (off = the tab's "Disable per-product overrides").

Note: Bulk-safe: a single call may address up to 100 targets and writes them in one transaction with the Shopify metafield syncs fired once for the whole batch. Targets that STOQ has no product_variants row for are reported in unmatched rather than created. Deleting a back-in-stock template clears it from every product/variant it was assigned to (they fall back to the global design); template CRUD lives on the templates capability.

Body

application/json
targetsany
button_visibilityany
restock_messageany
templateany
enable_customizationany
automatic_alerts_enabledany
per_product_customization_enabledany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Update
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/back_in_stock/products' \
  -H 'Content-Type: application/json' \
  -d '{
    "targets": "string",
    "button_visibility": "string",
    "restock_message": "string",
    "template": "string",
    "enable_customization": "string",
    "automatic_alerts_enabled": true,
    "per_product_customization_enabled": true
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/products', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "targets": "string",
      "button_visibility": "string",
      "restock_message": "string",
      "template": "string",
      "enable_customization": "string",
      "automatic_alerts_enabled": true,
      "per_product_customization_enabled": true
    }),
});

const data = await response.json();
import requests

payload = {
  "targets": "string",
  "button_visibility": "string",
  "restock_message": "string",
  "template": "string",
  "enable_customization": "string",
  "automatic_alerts_enabled": True,
  "per_product_customization_enabled": True
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/back_in_stock/products', json=payload)
data = response.json()
Request Body
{
  "targets": "string",
  "button_visibility": "string",
  "restock_message": "string",
  "template": "string",
  "enable_customization": "string",
  "automatic_alerts_enabled": true,
  "per_product_customization_enabled": true
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Notification Status

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/products/{variant_id}/notification_status

Notification/waitlist status for one product variant: pending signups, total alerts sent, the 5 most recent send batches (each with what triggered it), and the shop's delivery settings -- the usual reason a restock produced no send yet.

Parameters

variant_idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Notification Status
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/products/{variant_id}/notification_status'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/products/{variant_id}/notification_status', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/products/{variant_id}/notification_status')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Back In Stock · Reports

List

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/reports

List every available back-in-stock report (name, description, aliases, url).

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

List
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/reports')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Conversions

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/reports/conversions

Time-series of orders attributed to back-in-stock alerts and the revenue recovered.

Parameters

fromanyquery
toanyquery
variant_idanyquery
product_idanyquery
channelanyquery
market_idanyquery
granularityanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Conversions
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/conversions'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/conversions', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/conversions')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Conversions Export

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/reports/conversions/export

Async CSV export of the back-in-stock conversions time series.

Body

application/json
fromany
toany
variant_idany
product_idany
channelany
granularityany
sort_byany
directionany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Conversions Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/conversions/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "variant_id": "45000000001",
    "product_id": "78000000001",
    "channel": "string",
    "granularity": "string",
    "sort_by": "string",
    "direction": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/conversions/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "variant_id": "45000000001",
      "product_id": "78000000001",
      "channel": "string",
      "granularity": "string",
      "sort_by": "string",
      "direction": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "variant_id": "45000000001",
  "product_id": "78000000001",
  "channel": "string",
  "granularity": "string",
  "sort_by": "string",
  "direction": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/conversions/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "variant_id": "45000000001",
  "product_id": "78000000001",
  "channel": "string",
  "granularity": "string",
  "sort_by": "string",
  "direction": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Engagement

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/reports/engagement

Back-in-stock "Notify me" button engagement/funnel analytics: impressions, clicks, click rate, signups, and signup rate — the same numbers on the merchant's back-in-stock Engagement dashboard. Rates use unique shoppers. This is button engagement, not conversion — for orders placed by notified customers use /back_in_stock/reports/summary.

Parameters

fromanyquery
toanyquery
market_idanyquery
variant_idsanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Engagement
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/engagement'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/engagement', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/engagement')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Exports

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/reports/exports/{job_id}

Check the status of an async report export and get the download URL when ready.

Parameters

job_idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Exports
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/exports/{job_id}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/exports/{job_id}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/exports/{job_id}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Notifications

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/reports/notifications

Time-series of back-in-stock notifications sent, split by channel (email/sms/push).

Parameters

fromanyquery
toanyquery
variant_idanyquery
product_idanyquery
channelanyquery
granularityanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Notifications
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/notifications'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/notifications', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/notifications')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Notifications Export

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/reports/notifications/export

Async CSV export of the back-in-stock notifications time series.

Body

application/json
fromany
toany
variant_idany
product_idany
channelany
granularityany
sort_byany
directionany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Notifications Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/notifications/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "variant_id": "45000000001",
    "product_id": "78000000001",
    "channel": "string",
    "granularity": "string",
    "sort_by": "string",
    "direction": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/notifications/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "variant_id": "45000000001",
      "product_id": "78000000001",
      "channel": "string",
      "granularity": "string",
      "sort_by": "string",
      "direction": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "variant_id": "45000000001",
  "product_id": "78000000001",
  "channel": "string",
  "granularity": "string",
  "sort_by": "string",
  "direction": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/notifications/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "variant_id": "45000000001",
  "product_id": "78000000001",
  "channel": "string",
  "granularity": "string",
  "sort_by": "string",
  "direction": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products In Demand

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand

Ranked variants by back-in-stock demand (pending/total signups, last requested).

Parameters

fromanyquery
toanyquery
variant_idanyquery
product_idanyquery
channelanyquery
market_idanyquery
sort_byanyquery
directionanyquery
pageanyquery
per_pageanyquery

Response

200OKobject

Success — example response shown.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products In Demand
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand')
data = response.json()
{
  "window": {
    "from": "2026-05-26T00:00:00Z",
    "to": "2026-06-25T23:59:59Z"
  },
  "sort_by": "pending",
  "direction": "desc",
  "rows": [
    {
      "shopify_variant_id": 47284734423096,
      "shopify_product_id": 8784906035384,
      "variant_title": "Blue / Medium",
      "product_title": "Classic Sneaker",
      "pending": 47,
      "total": 89,
      "last_requested_at": "2026-06-25T11:30:00Z"
    },
    {
      "shopify_variant_id": 47284734455864,
      "shopify_product_id": 8784906035384,
      "variant_title": "Red / Large",
      "product_title": "Classic Sneaker",
      "pending": 23,
      "total": 56,
      "last_requested_at": "2026-06-25T09:15:00Z"
    }
  ],
  "meta": {
    "total_count": 287,
    "page": 1,
    "per_page": 50,
    "total_pages": 6
  }
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products In Demand Export

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand/export

Async CSV export of the back-in-stock products-in-demand report.

Body

application/json
fromany
toany
variant_idany
product_idany
channelany
granularityany
sort_byany
directionany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products In Demand Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "variant_id": "45000000001",
    "product_id": "78000000001",
    "channel": "string",
    "granularity": "string",
    "sort_by": "string",
    "direction": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "variant_id": "45000000001",
      "product_id": "78000000001",
      "channel": "string",
      "granularity": "string",
      "sort_by": "string",
      "direction": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "variant_id": "45000000001",
  "product_id": "78000000001",
  "channel": "string",
  "granularity": "string",
  "sort_by": "string",
  "direction": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "variant_id": "45000000001",
  "product_id": "78000000001",
  "channel": "string",
  "granularity": "string",
  "sort_by": "string",
  "direction": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Signups

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/reports/signups

Time-series of back-in-stock signups created (day/week/month).

Parameters

fromanyquery
toanyquery
variant_idanyquery
product_idanyquery
channelanyquery
market_idanyquery
granularityanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Signups
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/signups'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/signups', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/signups')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Signups Export

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/reports/signups/export

Async CSV export of the back-in-stock signups time series.

Body

application/json
fromany
toany
variant_idany
product_idany
channelany
granularityany
sort_byany
directionany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Signups Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/signups/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "variant_id": "45000000001",
    "product_id": "78000000001",
    "channel": "string",
    "granularity": "string",
    "sort_by": "string",
    "direction": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/signups/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "variant_id": "45000000001",
      "product_id": "78000000001",
      "channel": "string",
      "granularity": "string",
      "sort_by": "string",
      "direction": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "variant_id": "45000000001",
  "product_id": "78000000001",
  "channel": "string",
  "granularity": "string",
  "sort_by": "string",
  "direction": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/signups/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "variant_id": "45000000001",
  "product_id": "78000000001",
  "channel": "string",
  "granularity": "string",
  "sort_by": "string",
  "direction": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Summary

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/reports/summary

High-level overview of back-in-stock activity over a date window.

Parameters

fromanyquery
toanyquery
variant_idanyquery
product_idanyquery
channelanyquery
market_idanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Summary
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/summary'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/summary', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/summary')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Summary Export

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/reports/summary/export

Async CSV export of the back-in-stock summary report.

Body

application/json
fromany
toany
variant_idany
product_idany
channelany
granularityany
sort_byany
directionany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Summary Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/summary/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "variant_id": "45000000001",
    "product_id": "78000000001",
    "channel": "string",
    "granularity": "string",
    "sort_by": "string",
    "direction": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/summary/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "variant_id": "45000000001",
      "product_id": "78000000001",
      "channel": "string",
      "granularity": "string",
      "sort_by": "string",
      "direction": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "variant_id": "45000000001",
  "product_id": "78000000001",
  "channel": "string",
  "granularity": "string",
  "sort_by": "string",
  "direction": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/summary/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "variant_id": "45000000001",
  "product_id": "78000000001",
  "channel": "string",
  "granularity": "string",
  "sort_by": "string",
  "direction": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Wait Duration

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/reports/wait_duration

How long back-in-stock shoppers have been waiting: median wait days, the longest wait, and a binned wait-time histogram (paid plans only). Also returns total_waiting, the current pending/opted-in signup count.

Parameters

variant_idanyquery
product_idanyquery
market_idanyquery
fromanyquery
toanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Wait Duration
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/wait_duration'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/wait_duration', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/reports/wait_duration')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Back In Stock · Settings

Read

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/settings

Read all back-in-stock settings for the shop.

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/settings')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Update

PATCH
https://app.stoqapp.com/api/v2/external/back_in_stock/settings

Update back-in-stock settings for the shop.

Note: Accepts any combination of capability blobs: channels, delivery, compliance, tagging, alerts, widget — deep partial, delegated to the capability PATCHes, errors accumulated. Boolean toggles are set via this PATCH (or the capability PATCH): channels.email.enabled, channels.sms.enabled, channels.push.enabled, delivery.batching.enabled, delivery.locations.filter_enabled, delivery.any_variant.enabled, compliance.optin_required, tagging.order_tags.enabled, alerts.signups_threshold.notify, alerts.scheduled_reports.daily, alerts.scheduled_reports.weekly, alerts.scheduled_reports.monthly, widget.placement.enabled — e.g. { channels: { sms: { enabled: true } } }.

Body

application/json
channelsany
deliveryany
complianceany
taggingany
alertsany
widgetany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Update
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings' \
  -H 'Content-Type: application/json' \
  -d '{
    "channels": "string",
    "delivery": "string",
    "compliance": "string",
    "tagging": "string",
    "alerts": "string",
    "widget": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "channels": "string",
      "delivery": "string",
      "compliance": "string",
      "tagging": "string",
      "alerts": "string",
      "widget": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "channels": "string",
  "delivery": "string",
  "compliance": "string",
  "tagging": "string",
  "alerts": "string",
  "widget": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings', json=payload)
data = response.json()
Request Body
{
  "channels": "string",
  "delivery": "string",
  "compliance": "string",
  "tagging": "string",
  "alerts": "string",
  "widget": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Alerts

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/settings/alerts

Read back-in-stock merchant alert and scheduled report settings.

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Alerts
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings/alerts'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/alerts', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/alerts')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Alerts

PATCH
https://app.stoqapp.com/api/v2/external/back_in_stock/settings/alerts

Update back-in-stock merchant alert and scheduled report settings.

Note: Toggles set via this PATCH: signups_threshold.notify, signup_alerts.enabled, scheduled_reports.daily, scheduled_reports.weekly, scheduled_reports.monthly, notify_on_alert_sent — e.g. { scheduled_reports: { weekly: true } }. signups_threshold.count is the per-variant signup count that triggers the high-demand merchant alert email. signup_alerts.enabled turns on an immediate email to the merchant for every individual signup, sent to signup_alerts.email. scheduled_reports.email is the address that receives the daily/weekly/monthly summary reports. notify_on_alert_sent emails the merchant whenever back-in-stock alerts are sent to customers. merchant_emails.product_updates and merchant_emails.theme_published turn STOQ's own emails to the merchant on or off.

Body

application/json
signups_thresholdany
signup_alertsany
scheduled_reportsany
notify_on_alert_sentany
merchant_emailsany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Alerts
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings/alerts' \
  -H 'Content-Type: application/json' \
  -d '{
    "signups_threshold": "string",
    "signup_alerts": "string",
    "scheduled_reports": "string",
    "notify_on_alert_sent": "string",
    "merchant_emails": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/alerts', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "signups_threshold": "string",
      "signup_alerts": "string",
      "scheduled_reports": "string",
      "notify_on_alert_sent": "string",
      "merchant_emails": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "signups_threshold": "string",
  "signup_alerts": "string",
  "scheduled_reports": "string",
  "notify_on_alert_sent": "string",
  "merchant_emails": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/alerts', json=payload)
data = response.json()
Request Body
{
  "signups_threshold": "string",
  "signup_alerts": "string",
  "scheduled_reports": "string",
  "notify_on_alert_sent": "string",
  "merchant_emails": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Channels

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/settings/channels

Read back-in-stock notification channel settings.

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Channels
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings/channels'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/channels', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/channels')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Channels

PATCH
https://app.stoqapp.com/api/v2/external/back_in_stock/settings/channels

Update back-in-stock notification channel toggles.

Note: Channel toggles are set via this PATCH: email.enabled, sms.enabled, push.enabled — e.g. { sms: { enabled: true } }. Enabling SMS for the first time triggers a restricted-content verification check; sends may be held until the shop is verified.

Body

application/json
emailany
smsany
pushany

Response

200OKobject

Success — example response shown.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Channels
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings/channels' \
  -H 'Content-Type: application/json' \
  -d '{
    "channels": {
      "email": {
        "enabled": true
      },
      "sms": {
        "enabled": true
      },
      "push": {
        "enabled": false
      }
    }
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/channels', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "channels": {
        "email": {
          "enabled": true
        },
        "sms": {
          "enabled": true
        },
        "push": {
          "enabled": false
        }
      }
    }),
});

const data = await response.json();
import requests

payload = {
  "channels": {
    "email": {
      "enabled": True
    },
    "sms": {
      "enabled": True
    },
    "push": {
      "enabled": False
    }
  }
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/channels', json=payload)
data = response.json()
Request Body
{
  "channels": {
    "email": {
      "enabled": true
    },
    "sms": {
      "enabled": true
    },
    "push": {
      "enabled": false
    }
  }
}
{
  "channels": {
    "email": {
      "enabled": true
    },
    "sms": {
      "enabled": true
    },
    "push": {
      "enabled": false
    }
  },
  "delivery": {
    "batching": {
      "enabled": false
    },
    "stock_threshold": 1,
    "locations": {
      "filter_enabled": false,
      "location_ids": []
    }
  },
  "compliance": {
    "optin_required": false,
    "optin_method": "single"
  },
  "tagging": {
    "order_tags": {
      "enabled": false,
      "tags": []
    }
  },
  "alerts": {
    "scheduled_reports": {
      "weekly": true,
      "email": "merchant@example.com"
    }
  }
}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Compliance

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/settings/compliance

Read back-in-stock compliance settings (double opt-in).

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Compliance
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings/compliance'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/compliance', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/compliance')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Compliance

PATCH
https://app.stoqapp.com/api/v2/external/back_in_stock/settings/compliance

Update back-in-stock compliance settings (double opt-in).

Note: The double-opt-in toggle is set via this PATCH: optin_required — e.g. { optin_required: true }. When enabled, signups must confirm via email before they are eligible for notifications (GDPR double opt-in).

Body

application/json
optin_requiredany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Compliance
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings/compliance' \
  -H 'Content-Type: application/json' \
  -d '{
    "optin_required": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/compliance', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "optin_required": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "optin_required": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/compliance', json=payload)
data = response.json()
Request Body
{
  "optin_required": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Delivery

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/settings/delivery

Read back-in-stock delivery settings (batching, stock threshold, locations, any-variant).

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Delivery
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings/delivery'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/delivery', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/delivery')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Delivery

PATCH
https://app.stoqapp.com/api/v2/external/back_in_stock/settings/delivery

Update back-in-stock delivery settings (batching, stock threshold, locations, any-variant, password-protected sending, market setup, market-based alerts, alerts on publish).

Note: Deep partial. Toggles set via this PATCH: batching.enabled, locations.filter_enabled, any_variant.enabled — e.g. { batching: { enabled: true } }. batching.mode is an enum: 'multiplier' (batch size = restocked quantity x batching.multiplier) or 'fixed' (batch size = batching.batch_size); batching.wait_hours is the wait between batches. stock_threshold is the minimum restocked quantity before notifications send (>= 1). any_variant.all_products is a boolean: when true, any-variant alerts apply to every product and any_variant.product_ids is ignored; when false, only the listed products qualify. locations.location_ids and any_variant.product_ids are arrays of Shopify numeric ids and are replaced wholesale when present. send_while_password_protected is a boolean: false (default) holds back-in-stock alerts while the storefront password is on (signups stay pending for the next restock); true sends anyway. market_setup is "single_market" or "multiple_markets"; market_locations_enabled turns on market-based alerts; alert_on_publish also alerts when a product is published.

Body

application/json
batchingany
stock_thresholdany
locationsany
any_variantany
send_while_password_protectedany
market_setupany
market_locations_enabledany
alert_on_publishany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Delivery
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings/delivery' \
  -H 'Content-Type: application/json' \
  -d '{
    "batching": "string",
    "stock_threshold": "string",
    "locations": "string",
    "any_variant": "string",
    "send_while_password_protected": "string",
    "market_setup": "gid://shopify/Market/12345",
    "market_locations_enabled": "gid://shopify/Market/12345",
    "alert_on_publish": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/delivery', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "batching": "string",
      "stock_threshold": "string",
      "locations": "string",
      "any_variant": "string",
      "send_while_password_protected": "string",
      "market_setup": "gid://shopify/Market/12345",
      "market_locations_enabled": "gid://shopify/Market/12345",
      "alert_on_publish": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "batching": "string",
  "stock_threshold": "string",
  "locations": "string",
  "any_variant": "string",
  "send_while_password_protected": "string",
  "market_setup": "gid://shopify/Market/12345",
  "market_locations_enabled": "gid://shopify/Market/12345",
  "alert_on_publish": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/delivery', json=payload)
data = response.json()
Request Body
{
  "batching": "string",
  "stock_threshold": "string",
  "locations": "string",
  "any_variant": "string",
  "send_while_password_protected": "string",
  "market_setup": "gid://shopify/Market/12345",
  "market_locations_enabled": "gid://shopify/Market/12345",
  "alert_on_publish": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Tagging

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/settings/tagging

Read back-in-stock order tagging settings.

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Tagging
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings/tagging'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/tagging', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/tagging')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Tagging

PATCH
https://app.stoqapp.com/api/v2/external/back_in_stock/settings/tagging

Update back-in-stock order tagging settings.

Note: The toggle is set via this PATCH: order_tags.enabled — e.g. { order_tags: { enabled: true } }. order_tags.tag is the single tag applied to Shopify orders attributed to a back-in-stock notification (default 'STOQ-back-in-stock').

Body

application/json
order_tagsany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Tagging
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings/tagging' \
  -H 'Content-Type: application/json' \
  -d '{
    "order_tags": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/tagging', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "order_tags": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "order_tags": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/tagging', json=payload)
data = response.json()
Request Body
{
  "order_tags": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Widget

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/settings/widget

Read the storefront back-in-stock signup widget configuration: the notify-me button, where it appears, and the signup form's copy, styling and inputs.

Parameters

localeanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Widget
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings/widget'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/widget', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/widget')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Widget

PATCH
https://app.stoqapp.com/api/v2/external/back_in_stock/settings/widget

Update the storefront back-in-stock signup widget: the notify-me button (text, colors, corner radius, font, position), where the button appears (product, collection, home, search, preorder pages, and whether the whole widget is enabled), and the signup form's copy, success/error messages, colors, which inputs are collected and the double opt-in email text. button.position is "auto" (in-flow, directly below the sold-out add-to-cart button), "float-right" or "float-left" (a floating tab pinned to that edge of the page) or "specific" (after the element placement.selectors.product finds). placement.selectors holds the CSS selectors that place the button on product, collection, home and search pages; placement.hide_by_tag limits the widget by product tag; form.inline shows the form on the page instead of a popup; custom.css and custom.javascript run on every storefront page. form.fields.sms_first is a boolean: true shows the SMS field before email. form.fields.sms_default_country is a lowercase ISO 3166-1 alpha-2 code (e.g. "us", "gb", "ca", "au"). form.fields.sms_allowed_countries takes { add: [...], remove: [...] } of those same codes and edits the stored list in place — it never replaces it, so one country can be added or dropped without resending the rest; an empty allowed list means every country is allowed. Colors must be hex (#RRGGBB); radii are integers in pixels. Pass an optional top-level locale (e.g. "fr") to write the text fields for that language only.

Note: Deep partial. Groups: button, placement (with selectors and hide_by_tag), form.copy, form.messages, form.style, form.fields, form.inline, optin, branding, custom. Selectors, the on-page form, custom CSS/JavaScript and the app proxy path change what every shopper sees; a wrong value can hide the widget. Channel enables (email/sms/push), optin_required and the merchant signup alert live on the other settings capabilities.

Body

application/json
localeany
buttonany
placementany
formany
optinany
brandingany
customany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Widget
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/back_in_stock/settings/widget' \
  -H 'Content-Type: application/json' \
  -d '{
    "locale": "fr",
    "button": "string",
    "placement": "string",
    "form": "string",
    "optin": "string",
    "branding": "string",
    "custom": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/widget', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "locale": "fr",
      "button": "string",
      "placement": "string",
      "form": "string",
      "optin": "string",
      "branding": "string",
      "custom": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "locale": "fr",
  "button": "string",
  "placement": "string",
  "form": "string",
  "optin": "string",
  "branding": "string",
  "custom": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/back_in_stock/settings/widget', json=payload)
data = response.json()
Request Body
{
  "locale": "fr",
  "button": "string",
  "placement": "string",
  "form": "string",
  "optin": "string",
  "branding": "string",
  "custom": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Back In Stock · Signups

List

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/signups

List back-in-stock signups (the waitlist) in this shop, paginated.

Note: status compiles notified_at / unsubscribed_at / blocked_at into one lifecycle value; email and phone filters match partial values on the signup or its customer; query matches the customer's name, email or phone with one term (use email/phone instead to match only one).

Parameters

channelanyemailsmspushquery
statusanypendingnotifiedunsubscribedquery
variant_idanyquery
product_idanyquery
queryanyquery
emailanyquery
phoneanyquery
fromanyquery
toanyquery
pageanyquery
per_pageanyquery

Response

200OKobject

Success — example response shown.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

List
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/signups'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/signups', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/signups')
data = response.json()
{
  "signups": [
    {
      "id": 5847392,
      "status": "pending",
      "channel": "email",
      "contact": "john@example.com",
      "quantity": 2,
      "variant": {
        "shopify_variant_id": 47284734423096,
        "shopify_product_id": 8784906035384,
        "title": "Blue / Medium"
      },
      "customer": {
        "id": 9284756,
        "email": "john@example.com",
        "name": "John Doe"
      },
      "notifications_sent": 0,
      "last_notified_at": null,
      "created_at": "2026-06-25T13:45:30Z"
    },
    {
      "id": 5847393,
      "status": "notified",
      "channel": "sms",
      "contact": "+14155552671",
      "quantity": 1,
      "variant": {
        "shopify_variant_id": 47284734455864,
        "shopify_product_id": 8784906035384,
        "title": "Red / Large"
      },
      "customer": {
        "id": 9284757,
        "email": "jane@example.com",
        "name": "Jane Smith"
      },
      "notifications_sent": 1,
      "last_notified_at": "2026-06-24T10:30:00Z",
      "created_at": "2026-06-20T15:20:15Z"
    }
  ],
  "meta": {
    "total_count": 147,
    "page": 1,
    "per_page": 50,
    "total_pages": 3
  }
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Create

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/signups

Create a back-in-stock signup (add a customer to the waitlist for a variant).

Note: email is required for the email channel, phone for sms. shopify_product_id is resolved from the variant when omitted. Returns 409 when a pending signup already exists for the same contact + variant + channel.

Body

application/json
channelanyemailsmsrequired
shopify_variant_idanyrequired
quantityinteger
shopify_product_idany
emailany
phoneany
nameany

Response

200OKobject

Success — example response shown.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Create
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/signups' \
  -H 'Content-Type: application/json' \
  -d '{
    "channel": "email",
    "shopify_variant_id": 47284734423096,
    "shopify_product_id": 8784906035384,
    "email": "john@example.com",
    "quantity": 2,
    "name": "John Doe"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/signups', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "channel": "email",
      "shopify_variant_id": 47284734423096,
      "shopify_product_id": 8784906035384,
      "email": "john@example.com",
      "quantity": 2,
      "name": "John Doe"
    }),
});

const data = await response.json();
import requests

payload = {
  "channel": "email",
  "shopify_variant_id": 47284734423096,
  "shopify_product_id": 8784906035384,
  "email": "john@example.com",
  "quantity": 2,
  "name": "John Doe"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/signups', json=payload)
data = response.json()
Request Body
{
  "channel": "email",
  "shopify_variant_id": 47284734423096,
  "shopify_product_id": 8784906035384,
  "email": "john@example.com",
  "quantity": 2,
  "name": "John Doe"
}
{
  "id": 5847392,
  "status": "pending",
  "channel": "email",
  "contact": "john@example.com",
  "quantity": 2,
  "variant": {
    "shopify_variant_id": 47284734423096,
    "shopify_product_id": 8784906035384,
    "title": "Blue / Medium"
  },
  "customer": {
    "id": 9284756,
    "email": "john@example.com",
    "name": "John Doe"
  },
  "optin": {
    "required": false,
    "confirmed": null
  },
  "notifications_sent": 0,
  "last_notified_at": null,
  "created_at": "2026-06-25T13:45:30Z"
}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Read

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/signups/{id}

Read one back-in-stock signup's full representation.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/signups/{id}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/signups/{id}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/signups/{id}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Delete

DELETE
https://app.stoqapp.com/api/v2/external/back_in_stock/signups/{id}

Delete a pending back-in-stock signup (remove the customer from the waitlist).

Note: Pending signups only; deleting an already-notified signup returns 409.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Delete
curl -X DELETE 'https://app.stoqapp.com/api/v2/external/back_in_stock/signups/{id}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/signups/{id}', {
  method: 'DELETE',
});

const data = await response.json();
import requests

response = requests.delete('https://app.stoqapp.com/api/v2/external/back_in_stock/signups/{id}')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Notify

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/signups/{id}/notify

Send the back-in-stock notification for one signup now, regardless of stock state.

Note: 409 when the signup was already notified and allow_resend is not set.

Body

application/json
allow_resendany

Parameters

idstringrequiredpath

Response

200OKobject

Success — example response shown.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Notify
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/signups/{id}/notify' \
  -H 'Content-Type: application/json' \
  -d '{
    "allow_resend": false
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/signups/{id}/notify', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "allow_resend": false
    }),
});

const data = await response.json();
import requests

payload = {
  "allow_resend": False
}

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/signups/{id}/notify', json=payload)
data = response.json()
Request Body
{
  "allow_resend": false
}
{
  "signup_id": 5847392,
  "queued": true
}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Bulk Delete

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/signups/bulk_delete

Delete up to 1000 pending back-in-stock signups in one request.

Note: Pending-only: 422 listing the offending ids when any signup was already notified.

Body

application/json
signup_idsArray<string>required

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Bulk Delete
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/signups/bulk_delete' \
  -H 'Content-Type: application/json' \
  -d '{
    "signup_ids": [
      "sgn_a1b2c3"
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/signups/bulk_delete', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "signup_ids": [
        "sgn_a1b2c3"
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "signup_ids": [
    "sgn_a1b2c3"
  ]
}

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/signups/bulk_delete', json=payload)
data = response.json()
Request Body
{
  "signup_ids": [
    "sgn_a1b2c3"
  ]
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Bulk Notify

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/signups/bulk_notify

Send back-in-stock notifications for up to 1000 signups in one request.

Note: Responds 200 when all succeed, 207 with { success, failed } on partial failure. Already-notified signups fail unless allow_resend is set.

Body

application/json
signup_idsArray<string>required
allow_resendany

Response

200OKobject

Success — example response shown.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Bulk Notify
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/signups/bulk_notify' \
  -H 'Content-Type: application/json' \
  -d '{
    "signup_ids": [
      "5847392",
      "5847393",
      "5847394"
    ],
    "allow_resend": false
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/signups/bulk_notify', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "signup_ids": [
        "5847392",
        "5847393",
        "5847394"
      ],
      "allow_resend": false
    }),
});

const data = await response.json();
import requests

payload = {
  "signup_ids": [
    "5847392",
    "5847393",
    "5847394"
  ],
  "allow_resend": False
}

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/signups/bulk_notify', json=payload)
data = response.json()
Request Body
{
  "signup_ids": [
    "5847392",
    "5847393",
    "5847394"
  ],
  "allow_resend": false
}
{
  "success": [
    5847392,
    5847393
  ],
  "failed": [
    {
      "signup_id": "5847394",
      "error": "Already notified — pass allow_resend to send again"
    }
  ]
}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Transfer

POST
https://app.stoqapp.com/api/v2/external/back_in_stock/signups/transfer

Move back-in-stock signups from one variant to another (variant merges or replacements).

Note: scope picks which signups move: pending (default), notified, or all. Signups that would duplicate a pending signup on the target variant are dropped. from_shopify_product_id is resolved from the source variant when omitted.

Body

application/json
from_shopify_variant_idanyrequired
to_shopify_variant_idanyrequired
to_shopify_product_idanyrequired
scopeanypendingnotifiedall
from_shopify_product_idany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Transfer
curl -X POST 'https://app.stoqapp.com/api/v2/external/back_in_stock/signups/transfer' \
  -H 'Content-Type: application/json' \
  -d '{
    "from_shopify_variant_id": "45000000001",
    "to_shopify_variant_id": "45000000001",
    "to_shopify_product_id": "78000000001",
    "scope": "pending",
    "from_shopify_product_id": "78000000001"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/signups/transfer', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from_shopify_variant_id": "45000000001",
      "to_shopify_variant_id": "45000000001",
      "to_shopify_product_id": "78000000001",
      "scope": "pending",
      "from_shopify_product_id": "78000000001"
    }),
});

const data = await response.json();
import requests

payload = {
  "from_shopify_variant_id": "45000000001",
  "to_shopify_variant_id": "45000000001",
  "to_shopify_product_id": "78000000001",
  "scope": "pending",
  "from_shopify_product_id": "78000000001"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/back_in_stock/signups/transfer', json=payload)
data = response.json()
Request Body
{
  "from_shopify_variant_id": "45000000001",
  "to_shopify_variant_id": "45000000001",
  "to_shopify_product_id": "78000000001",
  "scope": "pending",
  "from_shopify_product_id": "78000000001"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Back In Stock · Templates

Read

GET
https://app.stoqapp.com/api/v2/external/back_in_stock/templates/{stage}/{locale}

Read a localized back-in-stock notification template. stage is "initial" (the back-in-stock alert), "reminder" (the follow-up reminder) or "signup_thank_you" (the email/SMS sent right after a customer signs up). The numbers 0 and 1 are accepted as aliases for initial and reminder. Includes enabled, the stage's on/off switch.

Parameters

stagestringrequiredpath
localestringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/back_in_stock/templates/{stage}/{locale}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/templates/{stage}/{locale}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/back_in_stock/templates/{stage}/{locale}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Update

PATCH
https://app.stoqapp.com/api/v2/external/back_in_stock/templates/{stage}/{locale}

Update a localized back-in-stock notification template. stage is "initial" (the back-in-stock alert), "reminder" (the follow-up reminder) or "signup_thank_you" (the email/SMS sent right after a customer signs up); 0 and 1 are aliases for initial and reminder. enabled (true/false) turns the reminder or the signup thank-you on or off; the initial alert cannot be disabled here. email_button_destination and sms_link_destination each accept only "checkout" or "product". Social links (email_facebook_link, email_instagram_link, email_pinterest_link, email_twitter_link, email_tiktok_link, email_whatsapp_link, email_youtube_link) take the profile URL without https:// and show as icons in the email; they are the ONLY place for social links — never put links in the footer. Colours (email_background_color, email_text_color, email_button_background_color, email_button_text_color) are flat hex fields — there is no nested style object. email_template_enabled (true/false) is the "Use HTML template" switch: false goes back to the standard STOQ email, true uses the custom HTML email template (email_template). Colours, corner radii and the Judge.me reviews block are shared by every stage of the alert; social links, the social icon colour and email_unsubscribe_text by every template of the shop.

Note: Deep partial over the template fields plus the stage's enabled switch. Rejects HTML except in email_template and email_css_config, and runs Template validations and callbacks. email_button_destination and sms_link_destination each accept only "checkout" or "product" (product page).

Body

application/json
enabledboolean
email_template_enabledboolean
email_reviews_enabledboolean
email_button_textstring
email_button_destinationstring
email_descriptionstring
email_footerstring
email_preheaderstring
email_headerstring
email_subjectstring
push_bodystring
push_button_textstring
push_titlestring
sms_bodystring
sms_link_destinationstring
klaviyo_flow_namestring
klaviyo_sms_flow_namestring
email_background_colorstring
email_text_colorstring
email_button_background_colorstring
email_button_text_colorstring
email_facebook_linkstring
email_instagram_linkstring
email_pinterest_linkstring
email_twitter_linkstring
email_tiktok_linkstring
email_whatsapp_linkstring
email_youtube_linkstring
email_social_icon_colorstring
email_section_colorstring
email_border_radiusany
email_button_border_radiusany
email_unsubscribe_textstring
email_reviews_titlestring
email_reviews_countany
email_reviews_min_ratingany
email_css_configstring
email_templatestring

Parameters

stagestringrequiredpath
localestringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Update
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/back_in_stock/templates/{stage}/{locale}' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true,
    "email_template_enabled": true,
    "email_reviews_enabled": true,
    "email_button_text": "Preorder now",
    "email_button_destination": "string",
    "email_description": "string",
    "email_footer": "string",
    "email_preheader": "string",
    "email_header": "string",
    "email_subject": "string",
    "push_body": "string",
    "push_button_text": "Preorder now",
    "push_title": "string",
    "sms_body": "string",
    "sms_link_destination": "string",
    "klaviyo_flow_name": "Summer Sneaker Drop",
    "klaviyo_sms_flow_name": "Summer Sneaker Drop",
    "email_background_color": "#1A1A1A",
    "email_text_color": "#1A1A1A",
    "email_button_background_color": "#1A1A1A",
    "email_button_text_color": "#1A1A1A",
    "email_facebook_link": "string",
    "email_instagram_link": "string",
    "email_pinterest_link": "string",
    "email_twitter_link": "string",
    "email_tiktok_link": "string",
    "email_whatsapp_link": "string",
    "email_youtube_link": "string",
    "email_social_icon_color": "#1A1A1A",
    "email_section_color": "#1A1A1A",
    "email_border_radius": "string",
    "email_button_border_radius": "string",
    "email_unsubscribe_text": "Preorder now",
    "email_reviews_title": "string",
    "email_reviews_count": 5,
    "email_reviews_min_rating": "string",
    "email_css_config": "string",
    "email_template": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/back_in_stock/templates/{stage}/{locale}', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true,
      "email_template_enabled": true,
      "email_reviews_enabled": true,
      "email_button_text": "Preorder now",
      "email_button_destination": "string",
      "email_description": "string",
      "email_footer": "string",
      "email_preheader": "string",
      "email_header": "string",
      "email_subject": "string",
      "push_body": "string",
      "push_button_text": "Preorder now",
      "push_title": "string",
      "sms_body": "string",
      "sms_link_destination": "string",
      "klaviyo_flow_name": "Summer Sneaker Drop",
      "klaviyo_sms_flow_name": "Summer Sneaker Drop",
      "email_background_color": "#1A1A1A",
      "email_text_color": "#1A1A1A",
      "email_button_background_color": "#1A1A1A",
      "email_button_text_color": "#1A1A1A",
      "email_facebook_link": "string",
      "email_instagram_link": "string",
      "email_pinterest_link": "string",
      "email_twitter_link": "string",
      "email_tiktok_link": "string",
      "email_whatsapp_link": "string",
      "email_youtube_link": "string",
      "email_social_icon_color": "#1A1A1A",
      "email_section_color": "#1A1A1A",
      "email_border_radius": "string",
      "email_button_border_radius": "string",
      "email_unsubscribe_text": "Preorder now",
      "email_reviews_title": "string",
      "email_reviews_count": 5,
      "email_reviews_min_rating": "string",
      "email_css_config": "string",
      "email_template": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True,
  "email_template_enabled": True,
  "email_reviews_enabled": True,
  "email_button_text": "Preorder now",
  "email_button_destination": "string",
  "email_description": "string",
  "email_footer": "string",
  "email_preheader": "string",
  "email_header": "string",
  "email_subject": "string",
  "push_body": "string",
  "push_button_text": "Preorder now",
  "push_title": "string",
  "sms_body": "string",
  "sms_link_destination": "string",
  "klaviyo_flow_name": "Summer Sneaker Drop",
  "klaviyo_sms_flow_name": "Summer Sneaker Drop",
  "email_background_color": "#1A1A1A",
  "email_text_color": "#1A1A1A",
  "email_button_background_color": "#1A1A1A",
  "email_button_text_color": "#1A1A1A",
  "email_facebook_link": "string",
  "email_instagram_link": "string",
  "email_pinterest_link": "string",
  "email_twitter_link": "string",
  "email_tiktok_link": "string",
  "email_whatsapp_link": "string",
  "email_youtube_link": "string",
  "email_social_icon_color": "#1A1A1A",
  "email_section_color": "#1A1A1A",
  "email_border_radius": "string",
  "email_button_border_radius": "string",
  "email_unsubscribe_text": "Preorder now",
  "email_reviews_title": "string",
  "email_reviews_count": 5,
  "email_reviews_min_rating": "string",
  "email_css_config": "string",
  "email_template": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/back_in_stock/templates/{stage}/{locale}', json=payload)
data = response.json()
Request Body
{
  "enabled": true,
  "email_template_enabled": true,
  "email_reviews_enabled": true,
  "email_button_text": "Preorder now",
  "email_button_destination": "string",
  "email_description": "string",
  "email_footer": "string",
  "email_preheader": "string",
  "email_header": "string",
  "email_subject": "string",
  "push_body": "string",
  "push_button_text": "Preorder now",
  "push_title": "string",
  "sms_body": "string",
  "sms_link_destination": "string",
  "klaviyo_flow_name": "Summer Sneaker Drop",
  "klaviyo_sms_flow_name": "Summer Sneaker Drop",
  "email_background_color": "#1A1A1A",
  "email_text_color": "#1A1A1A",
  "email_button_background_color": "#1A1A1A",
  "email_button_text_color": "#1A1A1A",
  "email_facebook_link": "string",
  "email_instagram_link": "string",
  "email_pinterest_link": "string",
  "email_twitter_link": "string",
  "email_tiktok_link": "string",
  "email_whatsapp_link": "string",
  "email_youtube_link": "string",
  "email_social_icon_color": "#1A1A1A",
  "email_section_color": "#1A1A1A",
  "email_border_radius": "string",
  "email_button_border_radius": "string",
  "email_unsubscribe_text": "Preorder now",
  "email_reviews_title": "string",
  "email_reviews_count": 5,
  "email_reviews_min_rating": "string",
  "email_css_config": "string",
  "email_template": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Preorders · Developer Settings

Read

GET
https://app.stoqapp.com/api/v2/external/preorders/developer_settings

The preorder Developer settings: whether dev mode is on, and the custom CSS selectors that place the Preorder button and each preorder element on product pages. Shop-wide, not per offer. The selectors are used only while dev_mode_enabled is true.

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/developer_settings'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/developer_settings', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/developer_settings')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Preorders · Notifications

Read

GET
https://app.stoqapp.com/api/v2/external/preorders/notifications/{locale}

Read shop-level preorder notification settings for a locale. email_account and sms_account say whose account sends: "stoq" or "merchant" (see GET /account/sending).

Parameters

localestringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/notifications/{locale}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/notifications/{locale}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/notifications/{locale}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Update

PATCH
https://app.stoqapp.com/api/v2/external/preorders/notifications/{locale}

Update shop-level preorder notification settings for a locale. This edits shop-level toggles, provider (email_provider/sms_provider), sender name, and shipping-update / payment-collection copy — NOT the confirmation email body (use update_preorder_template for that). email_provider and sms_provider accept only the shop's enabled provider keys.

Note: Deep partial. Validates booleans, provider enums, locale, length, and plain-text content; then runs Setting validations and provider/SMS verification callbacks.

Body

application/json
preorder_email_enabledboolean
preorder_sms_enabledboolean
preorder_cancellation_enabledboolean
notify_payment_collection_enabledboolean
email_provideranystoqklaviyoflow
sms_provideranytwiliotelnyxinfobipklaviyopostscript
email_from_namestring
shipping_update_subjectstring
shipping_update_headerstring
shipping_update_descriptionstring
payment_collection_email_subjectstring
payment_collection_email_headerstring
payment_collection_email_descriptionstring
payment_collection_email_button_textstring
klaviyo_shipping_update_flow_namestring
klaviyo_payment_failed_flow_namestring

Parameters

localestringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Update
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/notifications/{locale}' \
  -H 'Content-Type: application/json' \
  -d '{
    "preorder_email_enabled": true,
    "preorder_sms_enabled": true,
    "preorder_cancellation_enabled": true,
    "notify_payment_collection_enabled": true,
    "email_provider": "stoq",
    "sms_provider": "twilio",
    "email_from_name": "Summer Sneaker Drop",
    "shipping_update_subject": "2026-07-01T00:00:00Z",
    "shipping_update_header": "2026-07-01T00:00:00Z",
    "shipping_update_description": "2026-07-01T00:00:00Z",
    "payment_collection_email_subject": "string",
    "payment_collection_email_header": "string",
    "payment_collection_email_description": "string",
    "payment_collection_email_button_text": "Preorder now",
    "klaviyo_shipping_update_flow_name": "Summer Sneaker Drop",
    "klaviyo_payment_failed_flow_name": "Summer Sneaker Drop"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/notifications/{locale}', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "preorder_email_enabled": true,
      "preorder_sms_enabled": true,
      "preorder_cancellation_enabled": true,
      "notify_payment_collection_enabled": true,
      "email_provider": "stoq",
      "sms_provider": "twilio",
      "email_from_name": "Summer Sneaker Drop",
      "shipping_update_subject": "2026-07-01T00:00:00Z",
      "shipping_update_header": "2026-07-01T00:00:00Z",
      "shipping_update_description": "2026-07-01T00:00:00Z",
      "payment_collection_email_subject": "string",
      "payment_collection_email_header": "string",
      "payment_collection_email_description": "string",
      "payment_collection_email_button_text": "Preorder now",
      "klaviyo_shipping_update_flow_name": "Summer Sneaker Drop",
      "klaviyo_payment_failed_flow_name": "Summer Sneaker Drop"
    }),
});

const data = await response.json();
import requests

payload = {
  "preorder_email_enabled": True,
  "preorder_sms_enabled": True,
  "preorder_cancellation_enabled": True,
  "notify_payment_collection_enabled": True,
  "email_provider": "stoq",
  "sms_provider": "twilio",
  "email_from_name": "Summer Sneaker Drop",
  "shipping_update_subject": "2026-07-01T00:00:00Z",
  "shipping_update_header": "2026-07-01T00:00:00Z",
  "shipping_update_description": "2026-07-01T00:00:00Z",
  "payment_collection_email_subject": "string",
  "payment_collection_email_header": "string",
  "payment_collection_email_description": "string",
  "payment_collection_email_button_text": "Preorder now",
  "klaviyo_shipping_update_flow_name": "Summer Sneaker Drop",
  "klaviyo_payment_failed_flow_name": "Summer Sneaker Drop"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/notifications/{locale}', json=payload)
data = response.json()
Request Body
{
  "preorder_email_enabled": true,
  "preorder_sms_enabled": true,
  "preorder_cancellation_enabled": true,
  "notify_payment_collection_enabled": true,
  "email_provider": "stoq",
  "sms_provider": "twilio",
  "email_from_name": "Summer Sneaker Drop",
  "shipping_update_subject": "2026-07-01T00:00:00Z",
  "shipping_update_header": "2026-07-01T00:00:00Z",
  "shipping_update_description": "2026-07-01T00:00:00Z",
  "payment_collection_email_subject": "string",
  "payment_collection_email_header": "string",
  "payment_collection_email_description": "string",
  "payment_collection_email_button_text": "Preorder now",
  "klaviyo_shipping_update_flow_name": "Summer Sneaker Drop",
  "klaviyo_payment_failed_flow_name": "Summer Sneaker Drop"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Preorders · Offer Lookup

Find

GET
https://app.stoqapp.com/api/v2/external/preorders/offer_lookup

Resolve one preorder offer from an exact id or a fuzzy name match. Returns the full offer (same shape as GET /preorders/offers/:id) on a unique match. If name matches more than one offer, returns {ambiguous: true, candidates: [...]} instead of guessing -- re-call with the chosen id. Omit both id and name for the most recently created offer.

Parameters

idanyquery
nameanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Find
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offer_lookup'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offer_lookup', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offer_lookup')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Preorders · Offers

List

GET
https://app.stoqapp.com/api/v2/external/preorders/offers

List preorder offers in this shop, paginated. search matches offer name, internal name, or an attached product's title. status filters by enabled/disabled/scheduled. market_ids narrows to offers restricted to those Shopify markets. sort orders by created date, name, or revenue.

Parameters

statusanyallenableddisabledscheduledquery
sortanycreated_at desccreated_at ascinternal_name ascinternal_name descpreorder_revenue descpreorder_revenue ascquery
pageanyquery
per_pageanyquery
searchanyquery
market_idsanyquery

Response

200OKobject

Success — example response shown.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

List
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers')
data = response.json()
{
  "offers": [
    {
      "id": "gid://shopify/SellingPlan/1",
      "name": "Summer Sneaker Drop",
      "internal_name": "summer-2026",
      "status": "draft",
      "created_at": "2026-06-25T10:30:45Z",
      "updated_at": "2026-06-25T10:30:45Z"
    },
    {
      "id": "gid://shopify/SellingPlan/2",
      "name": "Winter Collection",
      "internal_name": "winter-2026",
      "status": "active",
      "created_at": "2026-06-20T14:15:30Z",
      "updated_at": "2026-06-22T09:45:12Z"
    }
  ],
  "meta": {
    "total_count": 2,
    "page": 1,
    "per_page": 50,
    "total_pages": 1
  }
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Create

POST
https://app.stoqapp.com/api/v2/external/preorders/offers

Create a new preorder offer.

Body

application/json
nameany
internal_nameany

Response

200OKobject

Success — example response shown.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Create
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Summer Sneaker Drop",
    "internal_name": "summer-2026"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "name": "Summer Sneaker Drop",
      "internal_name": "summer-2026"
    }),
});

const data = await response.json();
import requests

payload = {
  "name": "Summer Sneaker Drop",
  "internal_name": "summer-2026"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers', json=payload)
data = response.json()
Request Body
{
  "name": "Summer Sneaker Drop",
  "internal_name": "summer-2026"
}
{
  "id": "gid://shopify/SellingPlan/1",
  "name": "Summer Sneaker Drop",
  "internal_name": "summer-2026",
  "status": "draft",
  "created_at": "2026-06-25T10:30:45Z",
  "updated_at": "2026-06-25T10:30:45Z",
  "variants": {
    "count": 0,
    "url": "/api/v2/external/preorders/offers/1/products/variants"
  }
}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Read

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}

Read a preorder offer's full representation.

Parameters

idstringrequiredpath

Response

200OKobject

Success — example response shown.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}')
data = response.json()
{
  "id": "gid://shopify/SellingPlan/1",
  "name": "Summer Sneaker Drop",
  "internal_name": "summer-2026",
  "status": "active",
  "created_at": "2026-06-25T10:30:45Z",
  "updated_at": "2026-06-25T11:45:30Z",
  "variants": {
    "count": 3,
    "url": "/api/v2/external/preorders/offers/1/products/variants"
  },
  "products": {
    "source": "custom",
    "custom": {
      "variant_ids_sample": [
        47284734423096,
        47284734455864,
        47284734488632
      ]
    }
  },
  "widget": {
    "button": {
      "text": "Preorder Now",
      "colors": {
        "enabled": true,
        "text_color": "#FFFFFF",
        "background_color": "#1a1a1a"
      }
    },
    "disclaimer": {
      "enabled": true,
      "text": "Expected to ship by August 2026",
      "text_color": "#666666",
      "background_color": "#F5F5F5",
      "border_radius": "4px"
    },
    "badge": {
      "enabled": true,
      "text": "Pre-Order",
      "text_color": "#FFFFFF",
      "background_color": "#FF6B35"
    }
  },
  "shipping": {
    "delivery": {
      "applies_to_all_products": true,
      "type": "on_date",
      "days": null,
      "date": "2026-08-15T00:00:00Z"
    },
    "display": {
      "show_details": true,
      "shipping_text": "Ships in August 2026",
      "shipping_line_item_property_enabled": true
    }
  },
  "payments": {
    "mode": "full",
    "discount": {
      "type": null,
      "value": null
    },
    "options": [
      {
        "type": "full",
        "deposit_percent": null
      }
    ]
  },
  "limits": {
    "per_order": {
      "min": 1,
      "max": 5
    },
    "per_customer": {
      "max": 2
    },
    "total": {
      "max": 500,
      "current_count": null
    },
    "display": {
      "show_remaining": true,
      "quantity_limit_text": "Only 500 available"
    }
  },
  "checkout": {
    "terms": {
      "enabled": true,
      "text": "I understand this is a pre-order and will ship in August",
      "disable_button_until_acknowledged": true
    },
    "mixed_cart": {
      "allowed": false,
      "error_message": "Pre-orders cannot be mixed with regular items"
    },
    "order_tags": {
      "tags": [
        "preorder",
        "summer-2026"
      ]
    }
  },
  "inventory": {
    "provider": "stoq",
    "reservation": {
      "timing": "on_sale"
    },
    "continue_selling": {
      "enabled": true,
      "auto_apply_to_new_variants": true
    }
  },
  "markets": {
    "enabled": false,
    "applies_to_all_markets": false,
    "market_ids": []
  },
  "countdown": {
    "enabled": true,
    "mode": "to_schedule_end",
    "format": "d:h:m:s",
    "text": "Offer ends in"
  },
  "integrations": {
    "pos": {
      "enabled": true,
      "skip_inventory_check": false
    },
    "b2b": {
      "enabled": false
    }
  },
  "translations": {
    "default_locale": "en",
    "locales": [
      "en",
      "fr"
    ],
    "fields": [
      "widget.button.text"
    ],
    "translations": {
      "fr": {
        "widget.button.text": "Pré-commander"
      }
    }
  },
  "advanced": {
    "use_shopify_selling_plan": false,
    "custom_css": ".preorder-badge { font-weight: bold; }"
  }
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Update

PATCH
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}

Update top-level fields of a preorder offer.

Body

application/json
nameany
internal_nameany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Update
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Summer Sneaker Drop",
    "internal_name": "summer-2026"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "name": "Summer Sneaker Drop",
      "internal_name": "summer-2026"
    }),
});

const data = await response.json();
import requests

payload = {
  "name": "Summer Sneaker Drop",
  "internal_name": "summer-2026"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}', json=payload)
data = response.json()
Request Body
{
  "name": "Summer Sneaker Drop",
  "internal_name": "summer-2026"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Advanced

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced

Read power-user settings for a preorder offer (line item properties, button text overrides, Shopify selling plan attachment).

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Advanced
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Advanced

PATCH
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced

Update advanced (power-user) settings on a preorder offer.

Note: Deep partial. Toggles and clears are done via this PATCH: the line-item-property toggles are line_item_properties.include_shipping_text, .include_payment_breakdown, and .include_acknowledgement (true/false each). button_text_overrides is deep-partial per state — send null to clear an override for one state, e.g. { "button_text_overrides": { "out_of_stock": null } } removes that override (the read shape still emits all three states, with null for unset). sending an empty string or null.

Body

application/json
line_item_propertiesany
button_text_overridesany
use_shopify_selling_planany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Advanced
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced' \
  -H 'Content-Type: application/json' \
  -d '{
    "line_item_properties": "string",
    "button_text_overrides": "Preorder now",
    "use_shopify_selling_plan": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "line_item_properties": "string",
      "button_text_overrides": "Preorder now",
      "use_shopify_selling_plan": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "line_item_properties": "string",
  "button_text_overrides": "Preorder now",
  "use_shopify_selling_plan": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced', json=payload)
data = response.json()
Request Body
{
  "line_item_properties": "string",
  "button_text_overrides": "Preorder now",
  "use_shopify_selling_plan": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Advanced Attach To Shopify Selling Plan

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/attach_to_shopify_selling_plan

Re-attach the offer to a Shopify selling plan group (resume syncing).

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Advanced Attach To Shopify Selling Plan
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/attach_to_shopify_selling_plan'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/attach_to_shopify_selling_plan', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/attach_to_shopify_selling_plan')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Advanced Detach From Shopify Selling Plan

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/detach_from_shopify_selling_plan

Detach the offer from Shopify selling plan groups; Stoq continues to manage it via the storefront integration.

Note: Strongly discouraged for most merchants. Breaks Shopify-native integrations like checkout selling plan display and third-party subscription apps. Does not delete the existing Shopify selling plan group — it just stops syncing.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Advanced Detach From Shopify Selling Plan
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/detach_from_shopify_selling_plan'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/detach_from_shopify_selling_plan', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/detach_from_shopify_selling_plan')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Advanced Set Button Text Override

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/set_button_text_override

Override the widget button text for one state (before_launch, after_launch, or out_of_stock).

Body

application/json
stateanybefore_launchafter_launchout_of_stockrequired
textanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Advanced Set Button Text Override
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/set_button_text_override' \
  -H 'Content-Type: application/json' \
  -d '{
    "state": "before_launch",
    "text": "Preorder now"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/set_button_text_override', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "state": "before_launch",
      "text": "Preorder now"
    }),
});

const data = await response.json();
import requests

payload = {
  "state": "before_launch",
  "text": "Preorder now"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/set_button_text_override', json=payload)
data = response.json()
Request Body
{
  "state": "before_launch",
  "text": "Preorder now"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Advanced Set Custom Line Item Property

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/set_custom_line_item_property

Set a free-text custom line item property added to every preorder cart line.

Body

application/json
textany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Advanced Set Custom Line Item Property
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/set_custom_line_item_property' \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "Preorder now"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/set_custom_line_item_property', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "text": "Preorder now"
    }),
});

const data = await response.json();
import requests

payload = {
  "text": "Preorder now"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/advanced/set_custom_line_item_property', json=payload)
data = response.json()
Request Body
{
  "text": "Preorder now"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Checkout

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout

Read checkout settings for a preorder offer.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Checkout
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Checkout

PATCH
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout

Update checkout settings on a preorder offer.

Note: Boolean toggles are set via this PATCH: terms.enabled, terms.disable_button_until_acknowledged, terms.include_in_line_item_properties, mixed_cart.allowed — this PATCH is how you turn these on/off, e.g. { terms: { enabled: true } } or { mixed_cart: { allowed: false } }.

Body

application/json
termsany
mixed_cartany
order_tagsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Checkout
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout' \
  -H 'Content-Type: application/json' \
  -d '{
    "terms": "string",
    "mixed_cart": "string",
    "order_tags": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "terms": "string",
      "mixed_cart": "string",
      "order_tags": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "terms": "string",
  "mixed_cart": "string",
  "order_tags": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout', json=payload)
data = response.json()
Request Body
{
  "terms": "string",
  "mixed_cart": "string",
  "order_tags": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Checkout Add Order Tag

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/add_order_tag

Add a tag to the set applied to orders containing this offer.

Body

application/json
taganyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Checkout Add Order Tag
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/add_order_tag' \
  -H 'Content-Type: application/json' \
  -d '{
    "tag": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/add_order_tag', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "tag": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "tag": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/add_order_tag', json=payload)
data = response.json()
Request Body
{
  "tag": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Checkout Remove Order Tag

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/remove_order_tag

Remove a tag from the set applied to orders containing this offer.

Body

application/json
taganyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Checkout Remove Order Tag
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/remove_order_tag' \
  -H 'Content-Type: application/json' \
  -d '{
    "tag": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/remove_order_tag', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "tag": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "tag": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/remove_order_tag', json=payload)
data = response.json()
Request Body
{
  "tag": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Checkout Set Mixed Cart Allowed

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_mixed_cart_allowed

Allow or block carts that mix preorder and regular items.

Body

application/json
allowedbooleanrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Checkout Set Mixed Cart Allowed
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_mixed_cart_allowed' \
  -H 'Content-Type: application/json' \
  -d '{
    "allowed": true
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_mixed_cart_allowed', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "allowed": true
    }),
});

const data = await response.json();
import requests

payload = {
  "allowed": True
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_mixed_cart_allowed', json=payload)
data = response.json()
Request Body
{
  "allowed": true
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Checkout Set Mixed Cart Error Message

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_mixed_cart_error_message

Set the error message shown when a blocked mixed cart reaches checkout.

Body

application/json
messageanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Checkout Set Mixed Cart Error Message
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_mixed_cart_error_message' \
  -H 'Content-Type: application/json' \
  -d '{
    "message": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_mixed_cart_error_message', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "message": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "message": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_mixed_cart_error_message', json=payload)
data = response.json()
Request Body
{
  "message": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Checkout Set Order Tags

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_order_tags

Replace the set of tags applied to orders containing this offer.

Body

application/json
tagsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Checkout Set Order Tags
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_order_tags' \
  -H 'Content-Type: application/json' \
  -d '{
    "tags": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_order_tags', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "tags": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "tags": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_order_tags', json=payload)
data = response.json()
Request Body
{
  "tags": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Checkout Set Terms Settings

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_terms_settings

Require (or stop requiring) customers to accept preorder terms, with optional button-lock and acceptance-timestamp recording.

Body

application/json
enabledbooleanrequired
disable_button_untilany
record_timestampany
timestamp_labelany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Checkout Set Terms Settings
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_terms_settings' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true,
    "disable_button_until": "string",
    "record_timestamp": "string",
    "timestamp_label": "Preorder now"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_terms_settings', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true,
      "disable_button_until": "string",
      "record_timestamp": "string",
      "timestamp_label": "Preorder now"
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True,
  "disable_button_until": "string",
  "record_timestamp": "string",
  "timestamp_label": "Preorder now"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_terms_settings', json=payload)
data = response.json()
Request Body
{
  "enabled": true,
  "disable_button_until": "string",
  "record_timestamp": "string",
  "timestamp_label": "Preorder now"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Checkout Set Terms Text

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_terms_text

Set the terms-acceptance text shown next to the checkbox.

Body

application/json
textanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Checkout Set Terms Text
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_terms_text' \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "Preorder now"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_terms_text', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "text": "Preorder now"
    }),
});

const data = await response.json();
import requests

payload = {
  "text": "Preorder now"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/checkout/set_terms_text', json=payload)
data = response.json()
Request Body
{
  "text": "Preorder now"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Countdown

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown

Read the countdown timer configuration for a preorder offer.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Countdown
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Countdown

PATCH
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown

Update countdown timer settings on a preorder offer.

Note: Deep partial. countdown.enabled is toggled via this PATCH (enabled true/false); text is an alias for ends_text — both write the same column, and an explicit ends_text wins when both are sent.

Body

application/json
enabledany
modeany
custom_end_dateany
custom_start_dateany
formatany
textany
starts_textany
ends_textany
unit_labelsany
styleany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Countdown
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true,
    "mode": "string",
    "custom_end_date": "2026-07-01T00:00:00Z",
    "custom_start_date": "2026-07-01T00:00:00Z",
    "format": "string",
    "text": "Preorder now",
    "starts_text": "Preorder now",
    "ends_text": "Preorder now",
    "unit_labels": "Preorder now",
    "style": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true,
      "mode": "string",
      "custom_end_date": "2026-07-01T00:00:00Z",
      "custom_start_date": "2026-07-01T00:00:00Z",
      "format": "string",
      "text": "Preorder now",
      "starts_text": "Preorder now",
      "ends_text": "Preorder now",
      "unit_labels": "Preorder now",
      "style": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True,
  "mode": "string",
  "custom_end_date": "2026-07-01T00:00:00Z",
  "custom_start_date": "2026-07-01T00:00:00Z",
  "format": "string",
  "text": "Preorder now",
  "starts_text": "Preorder now",
  "ends_text": "Preorder now",
  "unit_labels": "Preorder now",
  "style": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown', json=payload)
data = response.json()
Request Body
{
  "enabled": true,
  "mode": "string",
  "custom_end_date": "2026-07-01T00:00:00Z",
  "custom_start_date": "2026-07-01T00:00:00Z",
  "format": "string",
  "text": "Preorder now",
  "starts_text": "Preorder now",
  "ends_text": "Preorder now",
  "unit_labels": "Preorder now",
  "style": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Countdown Set Custom End Date

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_custom_end_date

Set the custom end date for the countdown timer.

Note: Has no visible effect unless mode is to_custom_date.

Body

application/json
dateanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Countdown Set Custom End Date
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_custom_end_date' \
  -H 'Content-Type: application/json' \
  -d '{
    "date": "2026-07-01T00:00:00Z"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_custom_end_date', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "date": "2026-07-01T00:00:00Z"
    }),
});

const data = await response.json();
import requests

payload = {
  "date": "2026-07-01T00:00:00Z"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_custom_end_date', json=payload)
data = response.json()
Request Body
{
  "date": "2026-07-01T00:00:00Z"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Countdown Set Ends Text

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_ends_text

Set the text shown next to the countdown timer when the offer is closing.

Body

application/json
textanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Countdown Set Ends Text
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_ends_text' \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "Preorder now"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_ends_text', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "text": "Preorder now"
    }),
});

const data = await response.json();
import requests

payload = {
  "text": "Preorder now"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_ends_text', json=payload)
data = response.json()
Request Body
{
  "text": "Preorder now"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Countdown Set Mode

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_mode

Set the countdown source: 'to_schedule_end' (count down to the offer's scheduled end) or 'to_custom_date' (count down to a fixed date set via set_custom_end_date).

Body

application/json
modeanyto_schedule_endto_custom_daterequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Countdown Set Mode
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_mode' \
  -H 'Content-Type: application/json' \
  -d '{
    "mode": "to_schedule_end"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_mode', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "mode": "to_schedule_end"
    }),
});

const data = await response.json();
import requests

payload = {
  "mode": "to_schedule_end"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_mode', json=payload)
data = response.json()
Request Body
{
  "mode": "to_schedule_end"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Countdown Set Starts Text

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_starts_text

Set the text shown before the countdown timer when the offer hasn't started yet.

Body

application/json
textanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Countdown Set Starts Text
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_starts_text' \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "Preorder now"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_starts_text', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "text": "Preorder now"
    }),
});

const data = await response.json();
import requests

payload = {
  "text": "Preorder now"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_starts_text', json=payload)
data = response.json()
Request Body
{
  "text": "Preorder now"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Countdown Set Style

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_style

Set the countdown timer's visual style (type, colors, border radius).

Body

application/json
typeany
text_colorany
background_colorany
border_radiusany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Countdown Set Style
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_style' \
  -H 'Content-Type: application/json' \
  -d '{
    "type": "string",
    "text_color": "#1A1A1A",
    "background_color": "#1A1A1A",
    "border_radius": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_style', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "type": "string",
      "text_color": "#1A1A1A",
      "background_color": "#1A1A1A",
      "border_radius": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "type": "string",
  "text_color": "#1A1A1A",
  "background_color": "#1A1A1A",
  "border_radius": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_style', json=payload)
data = response.json()
Request Body
{
  "type": "string",
  "text_color": "#1A1A1A",
  "background_color": "#1A1A1A",
  "border_radius": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Countdown Set Unit Labels

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_unit_labels

Set the countdown timer unit labels (days, hours, minutes, seconds).

Body

application/json
daysany
hoursany
minutesany
secondsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Countdown Set Unit Labels
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_unit_labels' \
  -H 'Content-Type: application/json' \
  -d '{
    "days": "string",
    "hours": "string",
    "minutes": "string",
    "seconds": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_unit_labels', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "days": "string",
      "hours": "string",
      "minutes": "string",
      "seconds": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "days": "string",
  "hours": "string",
  "minutes": "string",
  "seconds": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/countdown/set_unit_labels', json=payload)
data = response.json()
Request Body
{
  "days": "string",
  "hours": "string",
  "minutes": "string",
  "seconds": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Disable

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/disable

Disable (pause) a preorder offer. Optionally flip attached variants' inventory policy back to DENY.

Note: Variants are left at their existing inventory policy unless update_inventory_policy: true is passed.

Body

application/json
update_inventory_policyany
variant_idsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — example response shown.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

409ConflictError

Invalid lifecycle transition — read the message; don't retry blindly.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Disable
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/disable' \
  -H 'Content-Type: application/json' \
  -d '{
    "update_inventory_policy": true
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/disable', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "update_inventory_policy": true
    }),
});

const data = await response.json();
import requests

payload = {
  "update_inventory_policy": True
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/disable', json=payload)
data = response.json()
Request Body
{
  "update_inventory_policy": true
}
{
  "id": "gid://shopify/SellingPlan/1",
  "name": "Summer Sneaker Drop",
  "internal_name": "summer-2026",
  "status": "paused",
  "updated_at": "2026-06-25T12:15:20Z",
  "variants": {
    "count": 3,
    "url": "/api/v2/external/preorders/offers/1/products/variants"
  }
}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "Offer is already disabled"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Discard

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/discard

Discard (soft-delete) a preorder offer.

Note: Recoverable via restore indefinitely. Discarded offers are never hard-deleted.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

409ConflictError

Invalid lifecycle transition — read the message; don't retry blindly.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Discard
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/discard'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/discard', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/discard')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "Offer is already disabled"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Enable

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/enable

Enable a preorder offer. On a scheduled offer this starts it now instead of on its start date (the start date is cleared; an end date is kept), as the dashboard does. Optionally flip attached variants' inventory policy to CONTINUE.

Note: Variants are left at their existing inventory policy unless update_inventory_policy: true is passed. On a scheduled offer (start date in the future) enable starts the offer now: schedule.start is cleared, schedule.end is kept, and with no end date the schedule is removed. To keep the start date, do not call enable; the offer starts on its own.

Body

application/json
update_inventory_policyany
variant_idsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — example response shown.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

409ConflictError

Invalid lifecycle transition — read the message; don't retry blindly.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Enable
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/enable' \
  -H 'Content-Type: application/json' \
  -d '{
    "update_inventory_policy": true
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/enable', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "update_inventory_policy": true
    }),
});

const data = await response.json();
import requests

payload = {
  "update_inventory_policy": True
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/enable', json=payload)
data = response.json()
Request Body
{
  "update_inventory_policy": true
}
{
  "id": "gid://shopify/SellingPlan/1",
  "name": "Summer Sneaker Drop",
  "internal_name": "summer-2026",
  "status": "active",
  "updated_at": "2026-06-25T11:45:30Z",
  "variants": {
    "count": 3,
    "url": "/api/v2/external/preorders/offers/1/products/variants"
  }
}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "Offer is already disabled"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Integrations

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations

Read integration settings for a preorder offer (POS, B2B).

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Integrations
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Integrations

PATCH
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations

Update integration settings on a preorder offer.

Note: Boolean toggles are set via this PATCH: pos.enabled, pos.skip_inventory_check, b2b.enabled — e.g. { pos: { enabled: false } } or { b2b: { enabled: true } }.

Body

application/json
posany
b2bany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Integrations
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations' \
  -H 'Content-Type: application/json' \
  -d '{
    "pos": "string",
    "b2b": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "pos": "string",
      "b2b": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "pos": "string",
  "b2b": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations', json=payload)
data = response.json()
Request Body
{
  "pos": "string",
  "b2b": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Integrations Set B2b Enabled

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations/set_b2b_enabled

Allow or disallow B2B customers to place preorders on this offer.

Body

application/json
enabledbooleanrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Integrations Set B2b Enabled
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations/set_b2b_enabled' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations/set_b2b_enabled', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations/set_b2b_enabled', json=payload)
data = response.json()
Request Body
{
  "enabled": true
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Integrations Set Pos Enabled

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations/set_pos_enabled

Enable or disable selling preorders on Shopify POS, with optional inventory-check skipping.

Body

application/json
enabledbooleanrequired
skip_inventory_checkany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Integrations Set Pos Enabled
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations/set_pos_enabled' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true,
    "skip_inventory_check": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations/set_pos_enabled', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true,
      "skip_inventory_check": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True,
  "skip_inventory_check": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/integrations/set_pos_enabled', json=payload)
data = response.json()
Request Body
{
  "enabled": true,
  "skip_inventory_check": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Inventory

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory

Read the inventory configuration for a preorder offer.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Inventory
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Inventory

PATCH
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory

Update inventory settings on a preorder offer.

Note: Deep partial. provider 'stoq' = the offer shows the Preorder button only when the product is OUT OF STOCK (the 'Show Preorder when product is out of stock' mode; needs Shopify's 'Continue selling when out of stock' on the variants). provider 'shopify' = the button shows for IN-STOCK products (the 'Show Preorder for in-stock products' mode). Setting provider to 'shopify' will force product_variants_source to 'custom' via the model callback. Continue-selling is toggled via this PATCH: continue_selling.enabled and continue_selling.auto_apply_to_new_variants BOTH map to the single underlying inventory_policy_auto_enable flag — the auto-flip-on-attach intent (newly-attached variants get their Shopify inventory_policy flipped to CONTINUE). When both fields are present, auto_apply_to_new_variants wins. Neither field flips EXISTING variants — to flip variants that are already attached, use POST .../products/bulk_toggle_inventory_policy, or pass the update_inventory_policy flag to the offer lifecycle enable/disable actions.

Body

application/json
provideranystoqshopify
reservationobject
Show child attributes
timinganyon_saleon_fulfillment
continue_sellingobject
Show child attributes
enabledboolean
auto_apply_to_new_variantsboolean

Parameters

idstringrequiredpath

Response

200OKobject

Success — example response shown.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Inventory
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory' \
  -H 'Content-Type: application/json' \
  -d '{
    "continue_selling": {
      "enabled": true,
      "auto_apply_to_new_variants": true
    }
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "continue_selling": {
        "enabled": true,
        "auto_apply_to_new_variants": true
      }
    }),
});

const data = await response.json();
import requests

payload = {
  "continue_selling": {
    "enabled": True,
    "auto_apply_to_new_variants": True
  }
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory', json=payload)
data = response.json()
Request Body
{
  "continue_selling": {
    "enabled": true,
    "auto_apply_to_new_variants": true
  }
}
{
  "provider": "stoq",
  "reservation": {
    "timing": "on_sale"
  },
  "continue_selling": {
    "enabled": true,
    "auto_apply_to_new_variants": true
  }
}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Inventory Set Provider

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory/set_provider

Set the inventory provider for a preorder offer (stoq or shopify).

Body

application/json
provideranystoqshopifyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Inventory Set Provider
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory/set_provider' \
  -H 'Content-Type: application/json' \
  -d '{
    "provider": "stoq"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory/set_provider', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "provider": "stoq"
    }),
});

const data = await response.json();
import requests

payload = {
  "provider": "stoq"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory/set_provider', json=payload)
data = response.json()
Request Body
{
  "provider": "stoq"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Inventory Set Reservation Timing

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory/set_reservation_timing

Set when inventory is reserved: on_sale (held at order time) or on_fulfillment.

Body

application/json
timinganyon_saleon_fulfillmentrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Inventory Set Reservation Timing
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory/set_reservation_timing' \
  -H 'Content-Type: application/json' \
  -d '{
    "timing": "on_sale"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory/set_reservation_timing', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "timing": "on_sale"
    }),
});

const data = await response.json();
import requests

payload = {
  "timing": "on_sale"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/inventory/set_reservation_timing', json=payload)
data = response.json()
Request Body
{
  "timing": "on_sale"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Limits

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits

Read order quantity limits for a preorder offer.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Limits
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Limits

PATCH
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits

Update quantity limits on a preorder offer.

Note: Deep partial. Toggles and clears are done via this PATCH: clear a limit by sending null — per_order.max: null removes the per-order cap; display.show_remaining (true/false) toggles the remaining-units display on the storefront. Order tags, the terms-acceptance requirement, and mixed-cart behavior live on the checkout capability instead (PATCH .../checkout), not here.

Body

application/json
per_orderany
displayany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Limits
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits' \
  -H 'Content-Type: application/json' \
  -d '{
    "per_order": "string",
    "display": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "per_order": "string",
      "display": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "per_order": "string",
  "display": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits', json=payload)
data = response.json()
Request Body
{
  "per_order": "string",
  "display": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Limits Set Icons Enabled

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_icons_enabled

Show or hide icons next to the quantity and shipping details on the widget.

Body

application/json
enabledbooleanrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Limits Set Icons Enabled
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_icons_enabled' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_icons_enabled', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_icons_enabled', json=payload)
data = response.json()
Request Body
{
  "enabled": true
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Limits Set Max Per Order

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_max_per_order

Set the maximum quantity a customer can preorder per order.

Body

application/json
maxany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Limits Set Max Per Order
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_max_per_order' \
  -H 'Content-Type: application/json' \
  -d '{
    "max": 5
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_max_per_order', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "max": 5
    }),
});

const data = await response.json();
import requests

payload = {
  "max": 5
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_max_per_order', json=payload)
data = response.json()
Request Body
{
  "max": 5
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Limits Set Min Per Order

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_min_per_order

Set the minimum quantity a customer must preorder per order.

Body

application/json
minany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Limits Set Min Per Order
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_min_per_order' \
  -H 'Content-Type: application/json' \
  -d '{
    "min": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_min_per_order', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "min": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "min": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_min_per_order', json=payload)
data = response.json()
Request Body
{
  "min": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Limits Set Progress Bar

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_progress_bar

Show or hide the preorder limit as a progress bar / counter on the widget, with optional text and colors.

Note: Enabling switches the limit display to the bar (disclaimer display off, like the editor radio). Colors are hex strings; show_percentage adds the percent label.

Body

application/json
enabledbooleanrequired
textany
show_percentageany
fill_colorany
background_colorany
box_background_colorany
text_colorany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Limits Set Progress Bar
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_progress_bar' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true,
    "text": "Preorder now",
    "show_percentage": 25,
    "fill_color": "#1A1A1A",
    "background_color": "#1A1A1A",
    "box_background_color": "#1A1A1A",
    "text_color": "#1A1A1A"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_progress_bar', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true,
      "text": "Preorder now",
      "show_percentage": 25,
      "fill_color": "#1A1A1A",
      "background_color": "#1A1A1A",
      "box_background_color": "#1A1A1A",
      "text_color": "#1A1A1A"
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True,
  "text": "Preorder now",
  "show_percentage": 25,
  "fill_color": "#1A1A1A",
  "background_color": "#1A1A1A",
  "box_background_color": "#1A1A1A",
  "text_color": "#1A1A1A"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_progress_bar', json=payload)
data = response.json()
Request Body
{
  "enabled": true,
  "text": "Preorder now",
  "show_percentage": 25,
  "fill_color": "#1A1A1A",
  "background_color": "#1A1A1A",
  "box_background_color": "#1A1A1A",
  "text_color": "#1A1A1A"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Limits Set Quantity Limit Text

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_quantity_limit_text

Set the text shown with the preorder quantity limit on the widget.

Body

application/json
textanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Limits Set Quantity Limit Text
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_quantity_limit_text' \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "Preorder now"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_quantity_limit_text', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "text": "Preorder now"
    }),
});

const data = await response.json();
import requests

payload = {
  "text": "Preorder now"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/limits/set_quantity_limit_text', json=payload)
data = response.json()
Request Body
{
  "text": "Preorder now"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Markets

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets

Read market scoping for a preorder offer.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Markets
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Markets

PATCH
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets

Update market scoping on a preorder offer.

Note: Deep partial. Scoping is toggled via this PATCH: enabled (true/false). The offer applies to ALL markets when scoping is off ({ "enabled": false }) or when scoping is on with an empty market list — the serializer compiles applies_to_all_markets from exactly that state. PATCH bodies: all markets → { "enabled": true, "market_ids": [] } (or { "enabled": true, "applies_to_all_markets": true }, which also clears the list); specific markets → { "enabled": true, "market_ids": ["gid://shopify/Market/1", ...] } (GIDs or numeric IDs). For incremental edits keep using add_market / remove_market / set_markets.

Body

application/json
enabledany
applies_to_all_marketsany
market_idsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Markets
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true,
    "applies_to_all_markets": "gid://shopify/Market/12345",
    "market_ids": [
      "gid://shopify/Market/12345"
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true,
      "applies_to_all_markets": "gid://shopify/Market/12345",
      "market_ids": [
        "gid://shopify/Market/12345"
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True,
  "applies_to_all_markets": "gid://shopify/Market/12345",
  "market_ids": [
    "gid://shopify/Market/12345"
  ]
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets', json=payload)
data = response.json()
Request Body
{
  "enabled": true,
  "applies_to_all_markets": "gid://shopify/Market/12345",
  "market_ids": [
    "gid://shopify/Market/12345"
  ]
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Markets Add Market

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets/add_market

Add a market to the preorder offer's scope.

Body

application/json
market_idanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Markets Add Market
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets/add_market' \
  -H 'Content-Type: application/json' \
  -d '{
    "market_id": "gid://shopify/Market/12345"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets/add_market', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "market_id": "gid://shopify/Market/12345"
    }),
});

const data = await response.json();
import requests

payload = {
  "market_id": "gid://shopify/Market/12345"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets/add_market', json=payload)
data = response.json()
Request Body
{
  "market_id": "gid://shopify/Market/12345"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Markets Remove Market

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets/remove_market

Remove a market from the preorder offer's scope.

Body

application/json
market_idanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Markets Remove Market
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets/remove_market' \
  -H 'Content-Type: application/json' \
  -d '{
    "market_id": "gid://shopify/Market/12345"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets/remove_market', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "market_id": "gid://shopify/Market/12345"
    }),
});

const data = await response.json();
import requests

payload = {
  "market_id": "gid://shopify/Market/12345"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets/remove_market', json=payload)
data = response.json()
Request Body
{
  "market_id": "gid://shopify/Market/12345"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Markets Set Markets

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets/set_markets

Replace the set of markets a preorder offer applies to.

Body

application/json
market_idsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Markets Set Markets
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets/set_markets' \
  -H 'Content-Type: application/json' \
  -d '{
    "market_ids": [
      "gid://shopify/Market/12345"
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets/set_markets', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "market_ids": [
        "gid://shopify/Market/12345"
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "market_ids": [
    "gid://shopify/Market/12345"
  ]
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/markets/set_markets', json=payload)
data = response.json()
Request Body
{
  "market_ids": [
    "gid://shopify/Market/12345"
  ]
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments

Read the payment configuration for a preorder offer.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments

PATCH
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments

Update payment settings on a preorder offer.

Note: Use SetOptionCopy / EnableOption / DisableOption to edit individual payment options. Boolean toggles are set via this PATCH: remaining_balance.auto_collect, remaining_balance.auto_collect_on_fulfillment — mutually exclusive, e.g. { remaining_balance: { auto_collect: false } }. Clear the discount via { discount: { type: "no_discount" } } (the stored value is nulled automatically).

Body

application/json
discountany
remaining_balanceany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments' \
  -H 'Content-Type: application/json' \
  -d '{
    "discount": 5,
    "remaining_balance": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "discount": 5,
      "remaining_balance": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "discount": 5,
  "remaining_balance": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments', json=payload)
data = response.json()
Request Body
{
  "discount": 5,
  "remaining_balance": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Disable Option

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/disable_option

Remove a payment option (full or partial) from the offer.

Note: Only valid on full_and_partial offers — an offer must keep at least one payment option. Use set_mode to switch a single-mode offer.

Body

application/json
option_typeanyfullpartialrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Disable Option
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/disable_option' \
  -H 'Content-Type: application/json' \
  -d '{
    "option_type": "full"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/disable_option', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "option_type": "full"
    }),
});

const data = await response.json();
import requests

payload = {
  "option_type": "full"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/disable_option', json=payload)
data = response.json()
Request Body
{
  "option_type": "full"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Enable Option

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/enable_option

Add a payment option (full or partial) to the offer.

Note: Idempotent. Newly added options start from the dashboard defaults — use set_deposit_percent / set_option_copy to fine-tune. Disable with disable_option.

Body

application/json
option_typeanyfullpartialrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Enable Option
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/enable_option' \
  -H 'Content-Type: application/json' \
  -d '{
    "option_type": "full"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/enable_option', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "option_type": "full"
    }),
});

const data = await response.json();
import requests

payload = {
  "option_type": "full"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/enable_option', json=payload)
data = response.json()
Request Body
{
  "option_type": "full"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Set Balance Due Days

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_balance_due_days

Charge the remaining preorder balance a number of days after checkout.

Note: Switches the offer to the 'time after checkout' remaining-balance mode and charges the balance days days after checkout. days must be a whole number >= 1. Use set_payment_date instead to charge on a specific calendar date, or the payments PATCH to toggle auto-collect.

Body

application/json
daysinteger>= 1required

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Set Balance Due Days
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_balance_due_days' \
  -H 'Content-Type: application/json' \
  -d '{
    "days": 1
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_balance_due_days', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "days": 1
    }),
});

const data = await response.json();
import requests

payload = {
  "days": 1
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_balance_due_days', json=payload)
data = response.json()
Request Body
{
  "days": 1
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Set Billing Widget

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_billing_widget

Show or hide the payment & discount savings widget in the purchase flow.

Note: Toggles the storefront widget that shows the customer their payment schedule and discount savings at every step of the purchase flow. enabled must be true or false.

Body

application/json
enabledbooleanrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Set Billing Widget
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_billing_widget' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_billing_widget', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_billing_widget', json=payload)
data = response.json()
Request Body
{
  "enabled": true
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Set Deposit Amount

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_deposit_amount

Set a fixed deposit amount charged at checkout on the partial payment option.

Note: Requires a partial payment option (mode partial or full_and_partial) -- use set_mode first. amount is in the store currency and must be more than 0. For a percent deposit use set_deposit_percent.

Body

application/json
amountnumberrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Set Deposit Amount
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_deposit_amount' \
  -H 'Content-Type: application/json' \
  -d '{
    "amount": 1
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_deposit_amount', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "amount": 1
    }),
});

const data = await response.json();
import requests

payload = {
  "amount": 1
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_deposit_amount', json=payload)
data = response.json()
Request Body
{
  "amount": 1
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Set Deposit Percent

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_deposit_percent

Set the deposit percentage charged at checkout on the partial payment option.

Note: Requires a partial payment option (mode partial or full_and_partial) — use set_mode first. Percent must be between 1 and 99; 100% upfront is the full payment mode.

Body

application/json
percentinteger[1, 99]required

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Set Deposit Percent
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_deposit_percent' \
  -H 'Content-Type: application/json' \
  -d '{
    "percent": 25
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_deposit_percent', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "percent": 25
    }),
});

const data = await response.json();
import requests

payload = {
  "percent": 25
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_deposit_percent', json=payload)
data = response.json()
Request Body
{
  "percent": 25
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Set Discount

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_discount

Set the preorder discount. type is one of: percentage, price, fixed_amount, no_discount; value is the amount (omit for no_discount).

Body

application/json
typeanypercentagepricefixed_amountno_discountrequired
valueany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Set Discount
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_discount' \
  -H 'Content-Type: application/json' \
  -d '{
    "type": "percentage",
    "value": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_discount', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "type": "percentage",
      "value": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "type": "percentage",
  "value": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_discount', json=payload)
data = response.json()
Request Body
{
  "type": "percentage",
  "value": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Set Discount Text

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_discount_text

Set the discount blurb shown on the offer's payment options. option_type (optional) must be either full or partial.

Note: Pass option_type (full | partial) to target one payment option; omit it to apply the text to every option. Supports the {{ discount }} placeholder.

Body

application/json
textanyrequired
option_typeanyfullpartial

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Set Discount Text
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_discount_text' \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "Preorder now",
    "option_type": "full"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_discount_text', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "text": "Preorder now",
      "option_type": "full"
    }),
});

const data = await response.json();
import requests

payload = {
  "text": "Preorder now",
  "option_type": "full"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_discount_text', json=payload)
data = response.json()
Request Body
{
  "text": "Preorder now",
  "option_type": "full"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Set Mode

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_mode

Switch the offer's payment mode. mode must be exactly one of: full, partial, full_and_partial.

Note: Idempotent. Collapsing from full_and_partial keeps the surviving option's copy; newly enabled modes start from the dashboard defaults. Use set_deposit_percent and set_option_copy afterwards to fine-tune.

Body

application/json
modeanyfullpartialfull_and_partialrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Set Mode
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_mode' \
  -H 'Content-Type: application/json' \
  -d '{
    "mode": "full"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_mode', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "mode": "full"
    }),
});

const data = await response.json();
import requests

payload = {
  "mode": "full"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_mode', json=payload)
data = response.json()
Request Body
{
  "mode": "full"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Set Option Copy

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_option_copy

Set the merchant-facing copy on a payment option (title, description, discount text). option_type must be either full or partial.

Body

application/json
option_typeanyfullpartialrequired
billing_titleany
billing_descriptionany
discount_textany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Set Option Copy
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_option_copy' \
  -H 'Content-Type: application/json' \
  -d '{
    "option_type": "full",
    "billing_title": "string",
    "billing_description": "string",
    "discount_text": "Preorder now"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_option_copy', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "option_type": "full",
      "billing_title": "string",
      "billing_description": "string",
      "discount_text": "Preorder now"
    }),
});

const data = await response.json();
import requests

payload = {
  "option_type": "full",
  "billing_title": "string",
  "billing_description": "string",
  "discount_text": "Preorder now"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_option_copy', json=payload)
data = response.json()
Request Body
{
  "option_type": "full",
  "billing_title": "string",
  "billing_description": "string",
  "discount_text": "Preorder now"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Set Payment Date

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_payment_date

Set the exact date the remaining preorder balance is charged.

Body

application/json
dateanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Set Payment Date
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_payment_date' \
  -H 'Content-Type: application/json' \
  -d '{
    "date": "2026-07-01T00:00:00Z"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_payment_date', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "date": "2026-07-01T00:00:00Z"
    }),
});

const data = await response.json();
import requests

payload = {
  "date": "2026-07-01T00:00:00Z"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_payment_date', json=payload)
data = response.json()
Request Body
{
  "date": "2026-07-01T00:00:00Z"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Set Show Discounted Price

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_show_discounted_price

Show or hide the discounted preorder price on the widget.

Body

application/json
enabledbooleanrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Set Show Discounted Price
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_show_discounted_price' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_show_discounted_price', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/payments/set_show_discounted_price', json=payload)
data = response.json()
Request Body
{
  "enabled": true
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products

Read the products configuration for a preorder offer (source rule + variant summary).

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products

PATCH
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products

Update the product selection on a preorder offer — set the source rule plus its matching sub-block. source must be exactly one of: all, collection, custom.

Note: Delegates to the set_source_to_* actions; switching source resets the variant set. source 'all' requires confirm: true. Only the sub-block matching source may be provided.

Body

application/json
sourceanyallcollectioncustomrequired
customobject | null
collectionobject | null
allobject | null
confirmany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products' \
  -H 'Content-Type: application/json' \
  -d '{
    "source": "all",
    "custom": "string",
    "collection": "string",
    "all": "string",
    "confirm": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "source": "all",
      "custom": "string",
      "collection": "string",
      "all": "string",
      "confirm": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "source": "all",
  "custom": "string",
  "collection": "string",
  "all": "string",
  "confirm": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products', json=payload)
data = response.json()
Request Body
{
  "source": "all",
  "custom": "string",
  "collection": "string",
  "all": "string",
  "confirm": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products Add Variants

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/add_variants

Attach variants to a custom-source preorder offer.

Note: Custom source only. Idempotent: already-attached variants are skipped and reported under already_present. Runs through BulkVariantAdditionService (async).

Body

application/json
variant_idsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — example response shown.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products Add Variants
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/add_variants' \
  -H 'Content-Type: application/json' \
  -d '{
    "variant_ids": [
      47284734423096,
      47284734455864,
      47284734488632
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/add_variants', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "variant_ids": [
        47284734423096,
        47284734455864,
        47284734488632
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "variant_ids": [
    47284734423096,
    47284734455864,
    47284734488632
  ]
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/add_variants', json=payload)
data = response.json()
Request Body
{
  "variant_ids": [
    47284734423096,
    47284734455864,
    47284734488632
  ]
}
{
  "source": "custom",
  "variants": {
    "count": 6,
    "url": "/api/v2/external/preorders/offers/1/products/variants"
  },
  "custom": {
    "variant_ids_sample": [
      47284734423096,
      47284734455864,
      47284734488632,
      47284734521400,
      47284734554168,
      47284734586936
    ]
  }
}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products Bulk Toggle Inventory Policy

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/bulk_toggle_inventory_policy

Flip the Shopify inventory policy on variants attached to a preorder offer (CONTINUE or DENY). Pass the explicit variant_ids for a partial change; omitting variant_ids applies the policy to EVERY attached variant, so only omit it when the merchant asked for all of them.

Note: Async via SellingPlans::BulkInventoryPolicyUpdateJob. Omit variant_ids to apply to all attached variants.

Body

application/json
policyanyCONTINUEDENYrequired
variant_idsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products Bulk Toggle Inventory Policy
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/bulk_toggle_inventory_policy' \
  -H 'Content-Type: application/json' \
  -d '{
    "policy": "CONTINUE",
    "variant_ids": [
      "45000000001"
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/bulk_toggle_inventory_policy', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "policy": "CONTINUE",
      "variant_ids": [
        "45000000001"
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "policy": "CONTINUE",
  "variant_ids": [
    "45000000001"
  ]
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/bulk_toggle_inventory_policy', json=payload)
data = response.json()
Request Body
{
  "policy": "CONTINUE",
  "variant_ids": [
    "45000000001"
  ]
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products Remove Variants

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/remove_variants

Remove variants from a custom-source preorder offer.

Note: Custom source only. Resets per-variant metafields on Shopify.

Body

application/json
variant_idsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products Remove Variants
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/remove_variants' \
  -H 'Content-Type: application/json' \
  -d '{
    "variant_ids": [
      "45000000001"
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/remove_variants', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "variant_ids": [
        "45000000001"
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "variant_ids": [
    "45000000001"
  ]
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/remove_variants', json=payload)
data = response.json()
Request Body
{
  "variant_ids": [
    "45000000001"
  ]
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products Set Collection

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_collection

Change the collection driving a collection-sourced preorder offer.

Note: Collection-sourced offers only — returns 409 Conflict otherwise. Use set_source_to_collection to switch a non-collection offer to collection source.

Body

application/json
collection_idanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products Set Collection
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_collection' \
  -H 'Content-Type: application/json' \
  -d '{
    "collection_id": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_collection', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "collection_id": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "collection_id": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_collection', json=payload)
data = response.json()
Request Body
{
  "collection_id": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products Set Excluded Variants

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_excluded_variants

Replace the explicit excluded-variant list for an all-source preorder offer.

Note: All-source offers only.

Body

application/json
variant_idsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products Set Excluded Variants
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_excluded_variants' \
  -H 'Content-Type: application/json' \
  -d '{
    "variant_ids": [
      "45000000001"
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_excluded_variants', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "variant_ids": [
        "45000000001"
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "variant_ids": [
    "45000000001"
  ]
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_excluded_variants', json=payload)
data = response.json()
Request Body
{
  "variant_ids": [
    "45000000001"
  ]
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products Set Exclusion Tag

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_exclusion_tag

Set the exclusion tag for an all-source preorder offer (variants with this tag are excluded).

Note: All-source offers only.

Body

application/json
tagany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products Set Exclusion Tag
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_exclusion_tag' \
  -H 'Content-Type: application/json' \
  -d '{
    "tag": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_exclusion_tag', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "tag": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "tag": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_exclusion_tag', json=payload)
data = response.json()
Request Body
{
  "tag": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products Set Source To All

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_source_to_all

Switch the offer to apply to every variant in the shop, minus exclusions. Requires confirm: true.

Note: Requires confirm: true in the body. Resolution runs async over the entire catalog.

Body

application/json
confirmany
exclusion_tagany
excluded_variant_idsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products Set Source To All
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_source_to_all' \
  -H 'Content-Type: application/json' \
  -d '{
    "confirm": "string",
    "exclusion_tag": "string",
    "excluded_variant_ids": [
      "string"
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_source_to_all', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "confirm": "string",
      "exclusion_tag": "string",
      "excluded_variant_ids": [
        "string"
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "confirm": "string",
  "exclusion_tag": "string",
  "excluded_variant_ids": [
    "string"
  ]
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_source_to_all', json=payload)
data = response.json()
Request Body
{
  "confirm": "string",
  "exclusion_tag": "string",
  "excluded_variant_ids": [
    "string"
  ]
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products Set Source To Collection

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_source_to_collection

Switch the offer to a collection-driven variant source.

Note: Resolution runs asynchronously. New variants added to the collection in Shopify are NOT auto-picked-up — call this action again to refresh.

Body

application/json
collection_idanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products Set Source To Collection
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_source_to_collection' \
  -H 'Content-Type: application/json' \
  -d '{
    "collection_id": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_source_to_collection', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "collection_id": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "collection_id": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_source_to_collection', json=payload)
data = response.json()
Request Body
{
  "collection_id": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products Set Source To Custom

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_source_to_custom

Switch the offer to a custom variant list. Optionally seed it with variant IDs.

Note: Variant attachment runs through BulkVariantAdditionService and is async (202 + job_id).

Body

application/json
variant_idsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products Set Source To Custom
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_source_to_custom' \
  -H 'Content-Type: application/json' \
  -d '{
    "variant_ids": [
      "45000000001"
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_source_to_custom', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "variant_ids": [
        "45000000001"
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "variant_ids": [
    "45000000001"
  ]
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/set_source_to_custom', json=payload)
data = response.json()
Request Body
{
  "variant_ids": [
    "45000000001"
  ]
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products Variants

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants

List the variants attached to a preorder offer with their per-variant settings, paginated.

Parameters

idstringrequiredpath
pageanyquery
per_pageanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products Variants
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products Variants

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants/{variant_id}

Read the per-offer settings of a single variant attached to a preorder offer.

Parameters

idstringrequiredpath
variant_idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products Variants
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants/{variant_id}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants/{variant_id}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants/{variant_id}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products Variants

PATCH
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants/{variant_id}

Set per-offer overrides on an attached variant — shipping text and max preorder count.

Note: null clears an override; the variant falls back to the offer-level value. market_overrides is no longer accepted; set per-market values on the offer instead.

Body

application/json
shipping_textstring | null
max_countinteger | null

Parameters

idstringrequiredpath
variant_idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products Variants
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants/{variant_id}' \
  -H 'Content-Type: application/json' \
  -d '{
    "shipping_text": "Preorder now",
    "max_count": 5
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants/{variant_id}', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "shipping_text": "Preorder now",
      "max_count": 5
    }),
});

const data = await response.json();
import requests

payload = {
  "shipping_text": "Preorder now",
  "max_count": 5
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants/{variant_id}', json=payload)
data = response.json()
Request Body
{
  "shipping_text": "Preorder now",
  "max_count": 5
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Products Variants Toggle Inventory Policy

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants/{variant_id}/toggle_inventory_policy

Set whether Shopify continues selling one attached preorder variant when it is out of stock (CONTINUE or DENY).

Note: Delegates asynchronously to BulkToggleInventoryPolicy with this single variant ID.

Body

application/json
policyanyCONTINUEDENYrequired

Parameters

idstringrequiredpath
variant_idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Products Variants Toggle Inventory Policy
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants/{variant_id}/toggle_inventory_policy' \
  -H 'Content-Type: application/json' \
  -d '{
    "policy": "CONTINUE"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants/{variant_id}/toggle_inventory_policy', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "policy": "CONTINUE"
    }),
});

const data = await response.json();
import requests

payload = {
  "policy": "CONTINUE"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/products/variants/{variant_id}/toggle_inventory_policy', json=payload)
data = response.json()
Request Body
{
  "policy": "CONTINUE"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Rename

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/rename

Rename a preorder offer (customer-facing name and/or internal label).

Body

application/json
nameany
internal_nameany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Rename
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/rename' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Summer Sneaker Drop",
    "internal_name": "summer-2026"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/rename', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "name": "Summer Sneaker Drop",
      "internal_name": "summer-2026"
    }),
});

const data = await response.json();
import requests

payload = {
  "name": "Summer Sneaker Drop",
  "internal_name": "summer-2026"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/rename', json=payload)
data = response.json()
Request Body
{
  "name": "Summer Sneaker Drop",
  "internal_name": "summer-2026"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Restore

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/restore

Restore a discarded preorder offer.

Note: Variant attachments and metafields are not auto-restored. Re-attach via the products capability.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

409ConflictError

Invalid lifecycle transition — read the message; don't retry blindly.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Restore
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/restore'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/restore', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/restore')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "Offer is already disabled"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Schedule

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/schedule

Set the schedule window for a preorder offer.

Note: Does not auto-enable. Storefront reads the schedule live.

Body

application/json
startany
endany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

409ConflictError

Invalid lifecycle transition — read the message; don't retry blindly.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Schedule
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/schedule' \
  -H 'Content-Type: application/json' \
  -d '{
    "start": "2026-07-01T00:00:00Z",
    "end": "2026-07-01T00:00:00Z"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/schedule', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "start": "2026-07-01T00:00:00Z",
      "end": "2026-07-01T00:00:00Z"
    }),
});

const data = await response.json();
import requests

payload = {
  "start": "2026-07-01T00:00:00Z",
  "end": "2026-07-01T00:00:00Z"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/schedule', json=payload)
data = response.json()
Request Body
{
  "start": "2026-07-01T00:00:00Z",
  "end": "2026-07-01T00:00:00Z"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "Offer is already disabled"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Shipping

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping

Read shipping settings for a preorder offer.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Shipping
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Shipping

PATCH
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping

Update shipping settings on a preorder offer.

Note: Deep partial. Prefer the intent-bearing actions (set_delivery_*, set_shipping_text, set_split_order_tag, set_split_order_suffix, set_split_transaction_gateway) for narrow edits. Toggles are done via this PATCH: fulfillment.hold (true/false) holds/releases fulfillment orders containing preorder items -- mutually exclusive with fulfillment.split, cannot both be on; fulfillment.split.type ('fulfillments' or 'orders') picks which split behavior is on -- these are two distinct settings, not one, and mutually exclusive with fulfillment.hold; 'fulfillments' also requires delivery.type to be (or become, in the same request) 'asap'; fulfillment.split.enabled (true/false) is a legacy toggle: true requires type to also be set, false clears both; fulfillment.split.hold_fulfillments (true/false) holds the split order's fulfillments; fulfillment.split.sequential_number (true/false) gives split orders a sequential order name.

Body

application/json
deliveryany
displayany
fulfillmentany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Shipping
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping' \
  -H 'Content-Type: application/json' \
  -d '{
    "delivery": "string",
    "display": "string",
    "fulfillment": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "delivery": "string",
      "display": "string",
      "fulfillment": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "delivery": "string",
  "display": "string",
  "fulfillment": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping', json=payload)
data = response.json()
Request Body
{
  "delivery": "string",
  "display": "string",
  "fulfillment": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Shipping Set Auto Release Holds

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_auto_release_holds

Enable or disable automatic release of fulfillment holds, with an optional release date and pay-first requirement.

Note: date sets when holds release; require_payment: true waits for the balance to be collected first. Disabling clears the stored release date.

Body

application/json
enabledbooleanrequired
dateany
require_paymentany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Shipping Set Auto Release Holds
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_auto_release_holds' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true,
    "date": "2026-07-01T00:00:00Z",
    "require_payment": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_auto_release_holds', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true,
      "date": "2026-07-01T00:00:00Z",
      "require_payment": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True,
  "date": "2026-07-01T00:00:00Z",
  "require_payment": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_auto_release_holds', json=payload)
data = response.json()
Request Body
{
  "enabled": true,
  "date": "2026-07-01T00:00:00Z",
  "require_payment": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Shipping Set Delivery Asap

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_delivery_asap

Set delivery to 'as soon as possible' (no specific date or window).

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Shipping Set Delivery Asap
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_delivery_asap'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_delivery_asap', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_delivery_asap')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Shipping Set Delivery Date

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_delivery_date

Set an exact delivery date for the preorder.

Body

application/json
dateanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Shipping Set Delivery Date
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_delivery_date' \
  -H 'Content-Type: application/json' \
  -d '{
    "date": "2026-07-01T00:00:00Z"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_delivery_date', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "date": "2026-07-01T00:00:00Z"
    }),
});

const data = await response.json();
import requests

payload = {
  "date": "2026-07-01T00:00:00Z"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_delivery_date', json=payload)
data = response.json()
Request Body
{
  "date": "2026-07-01T00:00:00Z"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Shipping Set Delivery Window

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_delivery_window

Set a delivery window in days from checkout (e.g. 'ships within 14 days').

Body

application/json
daysany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Shipping Set Delivery Window
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_delivery_window' \
  -H 'Content-Type: application/json' \
  -d '{
    "days": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_delivery_window', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "days": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "days": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_delivery_window', json=payload)
data = response.json()
Request Body
{
  "days": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Shipping Set Hold Fulfillments

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_hold_fulfillments

Hold (or release) all fulfillments for preorders on this offer, with an optional reason note.

Body

application/json
enabledbooleanrequired
reason_noteany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Shipping Set Hold Fulfillments
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_hold_fulfillments' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true,
    "reason_note": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_hold_fulfillments', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true,
      "reason_note": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True,
  "reason_note": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_hold_fulfillments', json=payload)
data = response.json()
Request Body
{
  "enabled": true,
  "reason_note": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Shipping Set Shipping Text

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_shipping_text

Set the customer-facing shipping text shown on the PDP.

Body

application/json
textanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Shipping Set Shipping Text
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_shipping_text' \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "Preorder now"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_shipping_text', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "text": "Preorder now"
    }),
});

const data = await response.json();
import requests

payload = {
  "text": "Preorder now"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_shipping_text', json=payload)
data = response.json()
Request Body
{
  "text": "Preorder now"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Shipping Set Split Order Suffix

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_split_order_suffix

Set the suffix appended to the original order name for split orders (e.g. #1001-SPLIT).

Body

application/json
suffixanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Shipping Set Split Order Suffix
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_split_order_suffix' \
  -H 'Content-Type: application/json' \
  -d '{
    "suffix": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_split_order_suffix', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "suffix": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "suffix": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_split_order_suffix', json=payload)
data = response.json()
Request Body
{
  "suffix": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Shipping Set Split Order Tag

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_split_order_tag

Set the tag applied to split orders on Shopify.

Body

application/json
taganyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Shipping Set Split Order Tag
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_split_order_tag' \
  -H 'Content-Type: application/json' \
  -d '{
    "tag": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_split_order_tag', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "tag": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "tag": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_split_order_tag', json=payload)
data = response.json()
Request Body
{
  "tag": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Shipping Set Split Transaction Gateway

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_split_transaction_gateway

Set the payment gateway used for the split order transaction (e.g. 'Prepaid').

Body

application/json
gatewayanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Shipping Set Split Transaction Gateway
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_split_transaction_gateway' \
  -H 'Content-Type: application/json' \
  -d '{
    "gateway": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_split_transaction_gateway', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "gateway": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "gateway": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/shipping/set_split_transaction_gateway', json=payload)
data = response.json()
Request Body
{
  "gateway": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Translations

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations

Read every translation override on a preorder offer, plus the full enumeration of translatable field paths, each field's default-locale source text, and every locale the shop has actually published (not just ones with an override already).

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Translations
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Translations Clear Locale

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/clear_locale

Remove all translation overrides for one locale on a preorder offer.

Body

application/json
localeanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Translations Clear Locale
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/clear_locale' \
  -H 'Content-Type: application/json' \
  -d '{
    "locale": "fr"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/clear_locale', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "locale": "fr"
    }),
});

const data = await response.json();
import requests

payload = {
  "locale": "fr"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/clear_locale', json=payload)
data = response.json()
Request Body
{
  "locale": "fr"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Translations Set

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/set

Set a single translation override (one locale, one field) on a preorder offer.

Body

application/json
localeanyrequired
fieldanyrequired
valueany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Translations Set
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/set' \
  -H 'Content-Type: application/json' \
  -d '{
    "locale": "fr",
    "field": "string",
    "value": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/set', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "locale": "fr",
      "field": "string",
      "value": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "locale": "fr",
  "field": "string",
  "value": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/set', json=payload)
data = response.json()
Request Body
{
  "locale": "fr",
  "field": "string",
  "value": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Translations Set Many

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/set_many

Set many translation overrides for one locale on a preorder offer, atomically.

Note: All-or-nothing. Pre-validates every field path before writing.

Body

application/json
localeanyrequired
translationsanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Translations Set Many
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/set_many' \
  -H 'Content-Type: application/json' \
  -d '{
    "locale": "fr",
    "translations": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/set_many', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "locale": "fr",
      "translations": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "locale": "fr",
  "translations": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/set_many', json=payload)
data = response.json()
Request Body
{
  "locale": "fr",
  "translations": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Translations Unset

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/unset

Remove a translation override (one locale, one field) from a preorder offer.

Body

application/json
localeanyrequired
fieldanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Translations Unset
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/unset' \
  -H 'Content-Type: application/json' \
  -d '{
    "locale": "fr",
    "field": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/unset', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "locale": "fr",
      "field": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "locale": "fr",
  "field": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/translations/unset', json=payload)
data = response.json()
Request Body
{
  "locale": "fr",
  "field": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Unschedule

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/unschedule

Clear the schedule window on a preorder offer.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

409ConflictError

Invalid lifecycle transition — read the message; don't retry blindly.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Unschedule
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/unschedule'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/unschedule', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/unschedule')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "Offer is already disabled"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Widget

GET
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget

Read the widget configuration for a preorder offer.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Widget
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Widget

PATCH
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget

Update any subset of the widget configuration on a preorder offer.

Note: Deep partial. Use the intent-bearing widget actions for narrow edits. Boolean toggles are set via this PATCH: badge.enabled, disclaimer.enabled, button.colors.enabled, billing_widget.enabled — e.g. { badge: { enabled: false } }. Clearing a value: send null.

Body

application/json
buttonany
disclaimerany
badgeany
billing_widgetany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Widget
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget' \
  -H 'Content-Type: application/json' \
  -d '{
    "button": "string",
    "disclaimer": "string",
    "badge": "string",
    "billing_widget": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "button": "string",
      "disclaimer": "string",
      "badge": "string",
      "billing_widget": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "button": "string",
  "disclaimer": "string",
  "badge": "string",
  "billing_widget": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget', json=payload)
data = response.json()
Request Body
{
  "button": "string",
  "disclaimer": "string",
  "badge": "string",
  "billing_widget": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Widget Set Badge Colors

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_badge_colors

Set the preorder badge's text and background colors.

Body

application/json
text_colorany
background_colorany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Widget Set Badge Colors
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_badge_colors' \
  -H 'Content-Type: application/json' \
  -d '{
    "text_color": "#1A1A1A",
    "background_color": "#1A1A1A"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_badge_colors', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "text_color": "#1A1A1A",
      "background_color": "#1A1A1A"
    }),
});

const data = await response.json();
import requests

payload = {
  "text_color": "#1A1A1A",
  "background_color": "#1A1A1A"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_badge_colors', json=payload)
data = response.json()
Request Body
{
  "text_color": "#1A1A1A",
  "background_color": "#1A1A1A"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Widget Set Badge Enabled

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_badge_enabled

Show or hide the preorder badge on the widget.

Body

application/json
enabledbooleanrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Widget Set Badge Enabled
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_badge_enabled' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_badge_enabled', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_badge_enabled', json=payload)
data = response.json()
Request Body
{
  "enabled": true
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Widget Set Badge Text

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_badge_text

Set the preorder badge text.

Note: Use set_badge_enabled to control visibility.

Body

application/json
textanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Widget Set Badge Text
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_badge_text' \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "Preorder now"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_badge_text', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "text": "Preorder now"
    }),
});

const data = await response.json();
import requests

payload = {
  "text": "Preorder now"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_badge_text', json=payload)
data = response.json()
Request Body
{
  "text": "Preorder now"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Widget Set Billing Widget Text

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_billing_widget_text

Set the billing widget's title and description (the PDP payment-breakdown block).

Note: These fields are shared with the first payment option's copy (see payments/set_option_copy). Use enable_billing_widget / disable_billing_widget to control visibility.

Body

application/json
titleany
descriptionany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Widget Set Billing Widget Text
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_billing_widget_text' \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "string",
    "description": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_billing_widget_text', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "title": "string",
      "description": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "title": "string",
  "description": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_billing_widget_text', json=payload)
data = response.json()
Request Body
{
  "title": "string",
  "description": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Widget Set Button Colors

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_button_colors

Set the preorder button's text and background colors (implicitly enables custom colors).

Note: Setting either color implicitly enables custom colors. Use disable_button_colors to revert to the theme's defaults.

Body

application/json
text_colorany
background_colorany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Widget Set Button Colors
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_button_colors' \
  -H 'Content-Type: application/json' \
  -d '{
    "text_color": "#1A1A1A",
    "background_color": "#1A1A1A"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_button_colors', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "text_color": "#1A1A1A",
      "background_color": "#1A1A1A"
    }),
});

const data = await response.json();
import requests

payload = {
  "text_color": "#1A1A1A",
  "background_color": "#1A1A1A"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_button_colors', json=payload)
data = response.json()
Request Body
{
  "text_color": "#1A1A1A",
  "background_color": "#1A1A1A"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Widget Set Button Text

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_button_text

Set the preorder button's call-to-action label.

Body

application/json
textanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — example response shown.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Widget Set Button Text
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_button_text' \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "Reserve Now"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_button_text', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "text": "Reserve Now"
    }),
});

const data = await response.json();
import requests

payload = {
  "text": "Reserve Now"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_button_text', json=payload)
data = response.json()
Request Body
{
  "text": "Reserve Now"
}
{
  "button": {
    "text": "Reserve Now",
    "colors": {
      "enabled": true,
      "text_color": "#FFFFFF",
      "background_color": "#1a1a1a"
    }
  },
  "disclaimer": {
    "enabled": true,
    "text": "Expected to ship by August 2026"
  },
  "badge": {
    "enabled": true,
    "text": "Pre-Order"
  }
}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Widget Set Disclaimer Enabled

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_disclaimer_enabled

Show or hide the disclaimer line under the preorder button.

Body

application/json
enabledbooleanrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Widget Set Disclaimer Enabled
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_disclaimer_enabled' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_disclaimer_enabled', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true
    }),
});

const data = await response.json();
import requests

payload = {
  "enabled": True
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_disclaimer_enabled', json=payload)
data = response.json()
Request Body
{
  "enabled": true
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Widget Set Disclaimer Style

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_disclaimer_style

Set the disclaimer banner's colors and border radius.

Body

application/json
text_colorany
background_colorany
border_radiusinteger>= 0

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Widget Set Disclaimer Style
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_disclaimer_style' \
  -H 'Content-Type: application/json' \
  -d '{
    "text_color": "#1A1A1A",
    "background_color": "#1A1A1A",
    "border_radius": 0
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_disclaimer_style', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "text_color": "#1A1A1A",
      "background_color": "#1A1A1A",
      "border_radius": 0
    }),
});

const data = await response.json();
import requests

payload = {
  "text_color": "#1A1A1A",
  "background_color": "#1A1A1A",
  "border_radius": 0
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_disclaimer_style', json=payload)
data = response.json()
Request Body
{
  "text_color": "#1A1A1A",
  "background_color": "#1A1A1A",
  "border_radius": 0
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Widget Set Disclaimer Text

POST
https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_disclaimer_text

Set the disclaimer banner text shown under the preorder button.

Note: Use enable_disclaimer / disable_disclaimer to control visibility.

Body

application/json
textanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Widget Set Disclaimer Text
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_disclaimer_text' \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "Preorder now"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_disclaimer_text', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "text": "Preorder now"
    }),
});

const data = await response.json();
import requests

payload = {
  "text": "Preorder now"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/offers/{id}/widget/set_disclaimer_text', json=payload)
data = response.json()
Request Body
{
  "text": "Preorder now"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Preorders · Orders

List

GET
https://app.stoqapp.com/api/v2/external/preorders/orders

List preorder orders in this shop, paginated. search matches order number/name, customer name, or email.

Parameters

pageanyquery
per_pageanyquery
searchanyquery
stateanyquery
offer_idanyquery
variant_idanyquery
customer_idanyquery
fromanyquery
toanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

List
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/orders'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/orders')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Read

GET
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}

Read a preorder order's full representation.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Cancel

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/cancel

Cancel a preorder. Optionally refund deposit / balance and notify the customer.

Note: Does not cancel the Shopify order; sets cancelled_at on the preorder attribution. Use the refund flags for refunds.

Body

application/json
refund_depositany
refund_balanceany
notify_customerany
reasonany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

409ConflictError

Invalid lifecycle transition — read the message; don't retry blindly.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Cancel
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/cancel' \
  -H 'Content-Type: application/json' \
  -d '{
    "refund_deposit": "string",
    "refund_balance": "string",
    "notify_customer": "string",
    "reason": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/cancel', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "refund_deposit": "string",
      "refund_balance": "string",
      "notify_customer": "string",
      "reason": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "refund_deposit": "string",
  "refund_balance": "string",
  "notify_customer": "string",
  "reason": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/cancel', json=payload)
data = response.json()
Request Body
{
  "refund_deposit": "string",
  "refund_balance": "string",
  "notify_customer": "string",
  "reason": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "Offer is already disabled"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Collect Payment

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/collect_payment

Collect the order's outstanding balance now by charging the customer's saved payment method.

Note: Matches the merchant dashboard action Collect payment. Charges the customer immediately; may fail when there is no saved payment method or the charge is declined — check the response. Set send_notifications false to suppress the customer email sent when a charge fails.

Body

application/json
send_notificationsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Collect Payment
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/collect_payment' \
  -H 'Content-Type: application/json' \
  -d '{
    "send_notifications": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/collect_payment', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "send_notifications": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "send_notifications": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/collect_payment', json=payload)
data = response.json()
Request Body
{
  "send_notifications": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Fulfillment

GET
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment

Read the fulfillment hold state and fulfillment-order summary of a preorder order.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Fulfillment
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Fulfillment

PATCH
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment

Update fulfillment attributes on a preorder order. Only hold_reason_note is writable.

Note: Hold state changes go through release_holds / apply_holds. all_held, any_held, and fulfillment_orders are read-only. Delegates to SetHoldReason; existing holds on Shopify aren't re-written.

Body

application/json
hold_reason_notestring | null

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Fulfillment
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment' \
  -H 'Content-Type: application/json' \
  -d '{
    "hold_reason_note": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "hold_reason_note": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "hold_reason_note": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment', json=payload)
data = response.json()
Request Body
{
  "hold_reason_note": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Fulfillment Apply Holds

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment/apply_holds

Apply fulfillment holds on the order's fulfillment orders. Idempotent.

Body

application/json
reason_notestring | null

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Fulfillment Apply Holds
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment/apply_holds' \
  -H 'Content-Type: application/json' \
  -d '{
    "reason_note": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment/apply_holds', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "reason_note": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "reason_note": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment/apply_holds', json=payload)
data = response.json()
Request Body
{
  "reason_note": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Fulfillment Release Holds

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment/release_holds

Release fulfillment holds on the order without applying offer-configured tags.

Note: Use the top-level release action when you want tags applied too.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Fulfillment Release Holds
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment/release_holds'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment/release_holds', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment/release_holds')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Fulfillment Set Hold Reason

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment/set_hold_reason

Set the hold-reason note that will be used the next time the order is held.

Note: Updates the note on the first attributed preorder offer. Existing holds on Shopify aren't re-written.

Body

application/json
reason_noteanyrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Fulfillment Set Hold Reason
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment/set_hold_reason' \
  -H 'Content-Type: application/json' \
  -d '{
    "reason_note": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment/set_hold_reason', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "reason_note": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "reason_note": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/fulfillment/set_hold_reason', json=payload)
data = response.json()
Request Body
{
  "reason_note": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Hold Fulfillments

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/hold_fulfillments

Apply fulfillment holds on the preorder order's fulfillment orders.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Hold Fulfillments
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/hold_fulfillments'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/hold_fulfillments', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/hold_fulfillments')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Open Scheduled Fulfillments

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/open_scheduled_fulfillments

Open the order's scheduled fulfillment orders for immediate fulfillment.

Note: Matches the merchant dashboard action Open scheduled fulfillments.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Open Scheduled Fulfillments
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/open_scheduled_fulfillments'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/open_scheduled_fulfillments', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/open_scheduled_fulfillments')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments

GET
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments

Read the deposit, remaining balance, and refund state of a preorder order.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Charge Balance

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/charge_balance

Charge the remaining balance. auto uses the customer's saved payment method; manual just marks balance collected.

Note: auto may fail if no saved payment method or declined; check the response or poll status.

Body

application/json
modeany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Charge Balance
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/charge_balance' \
  -H 'Content-Type: application/json' \
  -d '{
    "mode": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/charge_balance', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "mode": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "mode": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/charge_balance', json=payload)
data = response.json()
Request Body
{
  "mode": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Refund

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/refund

Refund the entire preorder (deposit + balance).

Body

application/json
notify_customerany
noteany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Refund
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/refund' \
  -H 'Content-Type: application/json' \
  -d '{
    "notify_customer": "string",
    "note": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/refund', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "notify_customer": "string",
      "note": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "notify_customer": "string",
  "note": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/refund', json=payload)
data = response.json()
Request Body
{
  "notify_customer": "string",
  "note": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Refund Balance

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/refund_balance

Refund the remaining-balance portion of a preorder (only valid after the balance was collected).

Body

application/json
notify_customerany
noteany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Refund Balance
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/refund_balance' \
  -H 'Content-Type: application/json' \
  -d '{
    "notify_customer": "string",
    "note": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/refund_balance', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "notify_customer": "string",
      "note": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "notify_customer": "string",
  "note": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/refund_balance', json=payload)
data = response.json()
Request Body
{
  "notify_customer": "string",
  "note": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Refund Deposit

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/refund_deposit

Refund the deposit portion of a preorder.

Body

application/json
notify_customerany
noteany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Refund Deposit
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/refund_deposit' \
  -H 'Content-Type: application/json' \
  -d '{
    "notify_customer": "string",
    "note": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/refund_deposit', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "notify_customer": "string",
      "note": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "notify_customer": "string",
  "note": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/refund_deposit', json=payload)
data = response.json()
Request Body
{
  "notify_customer": "string",
  "note": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Payments Send Collection Url

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/send_collection_url

Send the remaining-balance payment-collection URL to the customer.

Note: Idempotent — calling twice resends the email with a fresh URL.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Payments Send Collection Url
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/send_collection_url'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/send_collection_url', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/payments/send_collection_url')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Release

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/release

Release the order's fulfillment holds without applying offer-configured order tags.

Note: Matches the merchant dashboard action Release "On hold" fulfillments.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

409ConflictError

Invalid lifecycle transition — read the message; don't retry blindly.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Release
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/release'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/release', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/release')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "Offer is already disabled"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Reschedule Fulfillment

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/reschedule_fulfillment

Change the fulfillment date for the order's scheduled fulfillment orders.

Note: Accepts the same ISO 8601 timestamp as the merchant dashboard.

Body

application/json
fulfill_atstringrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Reschedule Fulfillment
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/reschedule_fulfillment' \
  -H 'Content-Type: application/json' \
  -d '{
    "fulfill_at": "2026-07-01T00:00:00Z"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/reschedule_fulfillment', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "fulfill_at": "2026-07-01T00:00:00Z"
    }),
});

const data = await response.json();
import requests

payload = {
  "fulfill_at": "2026-07-01T00:00:00Z"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/reschedule_fulfillment', json=payload)
data = response.json()
Request Body
{
  "fulfill_at": "2026-07-01T00:00:00Z"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Reschedule Payment

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/reschedule_payment

Change the due date for the order's remaining-balance payment schedule.

Note: Accepts a calendar date (YYYY-MM-DD) and changes the payment schedule only; it does not charge or refund money.

Body

application/json
due_atstringrequired

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Reschedule Payment
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/reschedule_payment' \
  -H 'Content-Type: application/json' \
  -d '{
    "due_at": "2026-07-01T00:00:00Z"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/reschedule_payment', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "due_at": "2026-07-01T00:00:00Z"
    }),
});

const data = await response.json();
import requests

payload = {
  "due_at": "2026-07-01T00:00:00Z"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/reschedule_payment', json=payload)
data = response.json()
Request Body
{
  "due_at": "2026-07-01T00:00:00Z"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Split Fulfillment Orders

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/split_fulfillment_orders

Split the order's fulfillment orders so preorder items ship separately from regular items.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Split Fulfillment Orders
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/split_fulfillment_orders'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/split_fulfillment_orders', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/split_fulfillment_orders')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Tags

GET
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags

Read the order tags applied by Stoq.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Tags
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Tags

PATCH
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags

Replace the order's tag set. PATCH form of tags/set.

Note: tags is replaced wholesale (delegates to tags/set). applied_by_stoq and applied_by_merchant are read-only.

Body

application/json
tagsarray | null

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Tags
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags' \
  -H 'Content-Type: application/json' \
  -d '{
    "tags": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "tags": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "tags": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags', json=payload)
data = response.json()
Request Body
{
  "tags": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Tags Add

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags/add

Add one or more tags to the Shopify order.

Body

application/json
tagsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Tags Add
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags/add' \
  -H 'Content-Type: application/json' \
  -d '{
    "tags": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags/add', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "tags": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "tags": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags/add', json=payload)
data = response.json()
Request Body
{
  "tags": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Tags Remove

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags/remove

Remove one or more tags from the Shopify order.

Body

application/json
tagsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Tags Remove
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags/remove' \
  -H 'Content-Type: application/json' \
  -d '{
    "tags": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags/remove', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "tags": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "tags": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags/remove', json=payload)
data = response.json()
Request Body
{
  "tags": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Tags Set

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags/set

Replace every tag on the Shopify order with the supplied list.

Note: Pass an empty list to clear all tags. Implemented as fetch-current + remove stale + add new on the Shopify side.

Body

application/json
tagsany

Parameters

idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Tags Set
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags/set' \
  -H 'Content-Type: application/json' \
  -d '{
    "tags": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags/set', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "tags": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "tags": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/tags/set', json=payload)
data = response.json()
Request Body
{
  "tags": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Timeline

GET
https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/timeline

Order history / activity log for a preorder order: every notification sent, payment attempt, fulfillment hold, and order split, in order, with timestamps.

Parameters

idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Timeline
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/timeline'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/timeline', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/orders/{id}/timeline')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Bulk Cancel

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_cancel

Cancel many preorder orders (max 1000), with optional refund flags.

Body

application/json
order_idsany
refund_depositany
refund_balanceany
notify_customerany
reasonany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Bulk Cancel
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_cancel' \
  -H 'Content-Type: application/json' \
  -d '{
    "order_ids": [
      "string"
    ],
    "refund_deposit": "string",
    "refund_balance": "string",
    "notify_customer": "string",
    "reason": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_cancel', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "order_ids": [
        "string"
      ],
      "refund_deposit": "string",
      "refund_balance": "string",
      "notify_customer": "string",
      "reason": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "order_ids": [
    "string"
  ],
  "refund_deposit": "string",
  "refund_balance": "string",
  "notify_customer": "string",
  "reason": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_cancel', json=payload)
data = response.json()
Request Body
{
  "order_ids": [
    "string"
  ],
  "refund_deposit": "string",
  "refund_balance": "string",
  "notify_customer": "string",
  "reason": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Bulk Release

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_release

Release fulfillments on many preorder orders (max 1000).

Body

application/json
order_idsany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Bulk Release
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_release' \
  -H 'Content-Type: application/json' \
  -d '{
    "order_ids": [
      "string"
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_release', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "order_ids": [
        "string"
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "order_ids": [
    "string"
  ]
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_release', json=payload)
data = response.json()
Request Body
{
  "order_ids": [
    "string"
  ]
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Bulk Send Payment Collection Url

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_send_payment_collection_url

Send payment-collection URLs to many preorder customers (max 1000).

Body

application/json
order_idsany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Bulk Send Payment Collection Url
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_send_payment_collection_url' \
  -H 'Content-Type: application/json' \
  -d '{
    "order_ids": [
      "string"
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_send_payment_collection_url', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "order_ids": [
        "string"
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "order_ids": [
    "string"
  ]
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_send_payment_collection_url', json=payload)
data = response.json()
Request Body
{
  "order_ids": [
    "string"
  ]
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Bulk Set Tags

POST
https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_set_tags

Apply tags to many preorder orders in one job (max 1000).

Note: mode is one of add | remove | replace (default add). replace overwrites each order's full tag set.

Body

application/json
order_idsany
tagsany
modestring | null

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Bulk Set Tags
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_set_tags' \
  -H 'Content-Type: application/json' \
  -d '{
    "order_ids": [
      "string"
    ],
    "tags": "string",
    "mode": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_set_tags', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "order_ids": [
        "string"
      ],
      "tags": "string",
      "mode": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "order_ids": [
    "string"
  ],
  "tags": "string",
  "mode": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/orders/bulk_set_tags', json=payload)
data = response.json()
Request Body
{
  "order_ids": [
    "string"
  ],
  "tags": "string",
  "mode": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Jobs

GET
https://app.stoqapp.com/api/v2/external/preorders/orders/jobs/{job_id}

Check the status of a bulk-order job.

Parameters

job_idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Jobs
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/orders/jobs/{job_id}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/orders/jobs/{job_id}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/orders/jobs/{job_id}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Preorders · Product Variants

List

GET
https://app.stoqapp.com/api/v2/external/preorders/product_variants

List Shopify variants attached to any preorder offer in this shop.

Parameters

pageanyquery
per_pageanyquery
offer_idanyquery
product_idanyquery
variant_idsanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

List
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/product_variants'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/product_variants', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/product_variants')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Read

GET
https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}

Read a Shopify variant's preorder context: every offer it's in, aggregate counts, and current metafield state.

Parameters

variant_idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Detach From All Offers

POST
https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/detach_from_all_offers

Remove a variant from every preorder offer it's attached to. Customer orders are unaffected.

Note: Destructive. Same effect as calling Offer::Products::RemoveVariants against every offer the variant is in.

Parameters

variant_idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Detach From All Offers
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/detach_from_all_offers'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/detach_from_all_offers', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/detach_from_all_offers')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Offers

GET
https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/offers

List the preorder offers a Shopify variant is attached to.

Parameters

variant_idstringrequiredpath
stateanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Offers
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/offers'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/offers', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/offers')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Recalculate Preorder Count

POST
https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/recalculate_preorder_count

Recompute preorder_count for a variant from active order line items, then push to Shopify.

Parameters

variant_idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Recalculate Preorder Count
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/recalculate_preorder_count'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/recalculate_preorder_count', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/recalculate_preorder_count')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Reset Metafields

POST
https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/reset_metafields

Clear a variant's preorder count metafields and rebuild its shipping text and limit metafields from its live offers. Keeps the variant attached to its offers.

Note: Doesn't detach. Shipping text and limit are cleared only where no live offer sets them.

Parameters

variant_idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Reset Metafields
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/reset_metafields'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/reset_metafields', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/reset_metafields')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Reset Preorder Count

POST
https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/reset_preorder_count

Hard-reset the preorder_count metafield + DB columns on a variant to zero.

Note: Use recalculate_preorder_count for a recompute from real orders; this is a destructive zero.

Parameters

variant_idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Reset Preorder Count
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/reset_preorder_count'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/reset_preorder_count', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/reset_preorder_count')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Sync Metafields

POST
https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/sync_metafields

Force-resync every preorder metafield for a variant from local DB state to Shopify.

Note: Idempotent. Useful when a previous metafield write failed.

Parameters

variant_idstringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Sync Metafields
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/sync_metafields'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/sync_metafields', {
  method: 'POST',
});

const data = await response.json();
import requests

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/product_variants/{variant_id}/sync_metafields')
data = response.json()
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Bulk Recalculate Preorder Counts

POST
https://app.stoqapp.com/api/v2/external/preorders/product_variants/bulk_recalculate_preorder_counts

Recompute preorder_count for many variants in one job (max 5000).

Body

application/json
variant_idsany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Bulk Recalculate Preorder Counts
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/product_variants/bulk_recalculate_preorder_counts' \
  -H 'Content-Type: application/json' \
  -d '{
    "variant_ids": [
      "45000000001"
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/product_variants/bulk_recalculate_preorder_counts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "variant_ids": [
        "45000000001"
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "variant_ids": [
    "45000000001"
  ]
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/product_variants/bulk_recalculate_preorder_counts', json=payload)
data = response.json()
Request Body
{
  "variant_ids": [
    "45000000001"
  ]
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Bulk Reset Metafields

POST
https://app.stoqapp.com/api/v2/external/preorders/product_variants/bulk_reset_metafields

Reset preorder metafields for many variants in one job (max 5000).

Body

application/json
variant_idsany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Bulk Reset Metafields
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/product_variants/bulk_reset_metafields' \
  -H 'Content-Type: application/json' \
  -d '{
    "variant_ids": [
      "45000000001"
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/product_variants/bulk_reset_metafields', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "variant_ids": [
        "45000000001"
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "variant_ids": [
    "45000000001"
  ]
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/product_variants/bulk_reset_metafields', json=payload)
data = response.json()
Request Body
{
  "variant_ids": [
    "45000000001"
  ]
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Bulk Sync Metafields

POST
https://app.stoqapp.com/api/v2/external/preorders/product_variants/bulk_sync_metafields

Force-resync preorder metafields for many variants in one job (max 5000).

Body

application/json
variant_idsany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Bulk Sync Metafields
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/product_variants/bulk_sync_metafields' \
  -H 'Content-Type: application/json' \
  -d '{
    "variant_ids": [
      "45000000001"
    ]
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/product_variants/bulk_sync_metafields', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "variant_ids": [
        "45000000001"
      ]
    }),
});

const data = await response.json();
import requests

payload = {
  "variant_ids": [
    "45000000001"
  ]
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/product_variants/bulk_sync_metafields', json=payload)
data = response.json()
Request Body
{
  "variant_ids": [
    "45000000001"
  ]
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Jobs

GET
https://app.stoqapp.com/api/v2/external/preorders/product_variants/jobs/{job_id}

Check the status of a bulk variant-admin job.

Parameters

job_idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Jobs
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/product_variants/jobs/{job_id}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/product_variants/jobs/{job_id}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/product_variants/jobs/{job_id}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Preorders · Products

Inventory Status

GET
https://app.stoqapp.com/api/v2/external/preorders/products/inventory_status

Live Shopify inventory for a set of variants, plus a per-attached-offer diagnosis of whether the preorder button is eligible to show. Makes a live Shopify API call and may be slow.

Parameters

variant_idsanyrequiredquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Inventory Status
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/products/inventory_status'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/products/inventory_status', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/products/inventory_status')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Preorders · Reports

List

GET
https://app.stoqapp.com/api/v2/external/preorders/reports

List every available preorder report (name, description, aliases, url).

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

List
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/reports'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/reports')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Balance Collection

GET
https://app.stoqapp.com/api/v2/external/preorders/reports/balance_collection

Outstanding preorder balances and balance-collection performance metrics.

Parameters

fromanyquery
toanyquery
offer_idanyquery
offer_idsanyquery
currencyanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Balance Collection
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/reports/balance_collection'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/balance_collection', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/reports/balance_collection')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Balance Collection Export

POST
https://app.stoqapp.com/api/v2/external/preorders/reports/balance_collection/export

Async CSV export of the balance-collection report.

Body

application/json
fromany
toany
offer_idany
offer_idsany
product_idany
variant_idany
market_idany
currencyany
granularityany
metricsany
include_depositsany
include_balancesany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Balance Collection Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/reports/balance_collection/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "offer_id": "string",
    "offer_ids": [
      "string"
    ],
    "product_id": "78000000001",
    "variant_id": "45000000001",
    "market_id": "gid://shopify/Market/12345",
    "currency": "string",
    "granularity": "string",
    "metrics": "string",
    "include_deposits": "string",
    "include_balances": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/balance_collection/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "offer_id": "string",
      "offer_ids": [
        "string"
      ],
      "product_id": "78000000001",
      "variant_id": "45000000001",
      "market_id": "gid://shopify/Market/12345",
      "currency": "string",
      "granularity": "string",
      "metrics": "string",
      "include_deposits": "string",
      "include_balances": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/reports/balance_collection/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

By Date

GET
https://app.stoqapp.com/api/v2/external/preorders/reports/by_date

Time-series of all preorder metrics at the chosen granularity (day/week/month).

Parameters

fromanyquery
toanyquery
offer_idanyquery
offer_idsanyquery
product_idanyquery
variant_idanyquery
market_idanyquery
currencyanyquery
granularityanyquery
metricsanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

By Date
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/reports/by_date'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/by_date', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/reports/by_date')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

By Date Export

POST
https://app.stoqapp.com/api/v2/external/preorders/reports/by_date/export

Async CSV export of the time-series preorder report.

Body

application/json
fromany
toany
offer_idany
offer_idsany
product_idany
variant_idany
market_idany
currencyany
granularityany
metricsany
include_depositsany
include_balancesany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

By Date Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/reports/by_date/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "offer_id": "string",
    "offer_ids": [
      "string"
    ],
    "product_id": "78000000001",
    "variant_id": "45000000001",
    "market_id": "gid://shopify/Market/12345",
    "currency": "string",
    "granularity": "string",
    "metrics": "string",
    "include_deposits": "string",
    "include_balances": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/by_date/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "offer_id": "string",
      "offer_ids": [
        "string"
      ],
      "product_id": "78000000001",
      "variant_id": "45000000001",
      "market_id": "gid://shopify/Market/12345",
      "currency": "string",
      "granularity": "string",
      "metrics": "string",
      "include_deposits": "string",
      "include_balances": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/reports/by_date/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

By Offer

GET
https://app.stoqapp.com/api/v2/external/preorders/reports/by_offer

Per-offer breakdown of preorder activity (orders, units, revenue, customers).

Parameters

fromanyquery
toanyquery
offer_idsanyquery
market_idanyquery
currencyanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

By Offer
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/reports/by_offer'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/by_offer', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/reports/by_offer')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

By Offer Export

POST
https://app.stoqapp.com/api/v2/external/preorders/reports/by_offer/export

Async CSV export of the per-offer preorder report.

Body

application/json
fromany
toany
offer_idany
offer_idsany
product_idany
variant_idany
market_idany
currencyany
granularityany
metricsany
include_depositsany
include_balancesany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

By Offer Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/reports/by_offer/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "offer_id": "string",
    "offer_ids": [
      "string"
    ],
    "product_id": "78000000001",
    "variant_id": "45000000001",
    "market_id": "gid://shopify/Market/12345",
    "currency": "string",
    "granularity": "string",
    "metrics": "string",
    "include_deposits": "string",
    "include_balances": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/by_offer/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "offer_id": "string",
      "offer_ids": [
        "string"
      ],
      "product_id": "78000000001",
      "variant_id": "45000000001",
      "market_id": "gid://shopify/Market/12345",
      "currency": "string",
      "granularity": "string",
      "metrics": "string",
      "include_deposits": "string",
      "include_balances": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/reports/by_offer/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

By Product

GET
https://app.stoqapp.com/api/v2/external/preorders/reports/by_product

Per-product preorder performance, rolled up across variants.

Parameters

fromanyquery
toanyquery
offer_idanyquery
offer_idsanyquery
product_idanyquery
currencyanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

By Product
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/reports/by_product'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/by_product', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/reports/by_product')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

By Product Export

POST
https://app.stoqapp.com/api/v2/external/preorders/reports/by_product/export

Async CSV export of the per-product preorder report.

Body

application/json
fromany
toany
offer_idany
offer_idsany
product_idany
variant_idany
market_idany
currencyany
granularityany
metricsany
include_depositsany
include_balancesany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

By Product Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/reports/by_product/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "offer_id": "string",
    "offer_ids": [
      "string"
    ],
    "product_id": "78000000001",
    "variant_id": "45000000001",
    "market_id": "gid://shopify/Market/12345",
    "currency": "string",
    "granularity": "string",
    "metrics": "string",
    "include_deposits": "string",
    "include_balances": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/by_product/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "offer_id": "string",
      "offer_ids": [
        "string"
      ],
      "product_id": "78000000001",
      "variant_id": "45000000001",
      "market_id": "gid://shopify/Market/12345",
      "currency": "string",
      "granularity": "string",
      "metrics": "string",
      "include_deposits": "string",
      "include_balances": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/reports/by_product/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

By Variant

GET
https://app.stoqapp.com/api/v2/external/preorders/reports/by_variant

Per-variant preorder performance for a specific offer.

Note: Requires offer_id (or offer_ids[]). Variant-level data without an offer scope isn't supported.

Parameters

fromanyquery
toanyquery
offer_idanyquery
offer_idsanyquery
product_idanyquery
variant_idanyquery
currencyanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

By Variant
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/reports/by_variant'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/by_variant', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/reports/by_variant')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

By Variant Export

POST
https://app.stoqapp.com/api/v2/external/preorders/reports/by_variant/export

Async CSV export of the per-variant preorder report.

Body

application/json
fromany
toany
offer_idany
offer_idsany
product_idany
variant_idany
market_idany
currencyany
granularityany
metricsany
include_depositsany
include_balancesany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

By Variant Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/reports/by_variant/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "offer_id": "string",
    "offer_ids": [
      "string"
    ],
    "product_id": "78000000001",
    "variant_id": "45000000001",
    "market_id": "gid://shopify/Market/12345",
    "currency": "string",
    "granularity": "string",
    "metrics": "string",
    "include_deposits": "string",
    "include_balances": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/by_variant/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "offer_id": "string",
      "offer_ids": [
        "string"
      ],
      "product_id": "78000000001",
      "variant_id": "45000000001",
      "market_id": "gid://shopify/Market/12345",
      "currency": "string",
      "granularity": "string",
      "metrics": "string",
      "include_deposits": "string",
      "include_balances": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/reports/by_variant/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Cancellations

GET
https://app.stoqapp.com/api/v2/external/preorders/reports/cancellations

Preorder cancellation metrics with reason and per-offer breakdowns.

Note: Reason breakdown requires the cancel_reason field on OrderAttribution. Reasons not yet captured will appear as 'unknown'.

Parameters

fromanyquery
toanyquery
offer_idanyquery
offer_idsanyquery
currencyanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Cancellations
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/reports/cancellations'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/cancellations', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/reports/cancellations')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Cancellations Export

POST
https://app.stoqapp.com/api/v2/external/preorders/reports/cancellations/export

Async CSV export of the cancellations report.

Body

application/json
fromany
toany
offer_idany
offer_idsany
product_idany
variant_idany
market_idany
currencyany
granularityany
metricsany
include_depositsany
include_balancesany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Cancellations Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/reports/cancellations/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "offer_id": "string",
    "offer_ids": [
      "string"
    ],
    "product_id": "78000000001",
    "variant_id": "45000000001",
    "market_id": "gid://shopify/Market/12345",
    "currency": "string",
    "granularity": "string",
    "metrics": "string",
    "include_deposits": "string",
    "include_balances": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/cancellations/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "offer_id": "string",
      "offer_ids": [
        "string"
      ],
      "product_id": "78000000001",
      "variant_id": "45000000001",
      "market_id": "gid://shopify/Market/12345",
      "currency": "string",
      "granularity": "string",
      "metrics": "string",
      "include_deposits": "string",
      "include_balances": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/reports/cancellations/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Customers

GET
https://app.stoqapp.com/api/v2/external/preorders/reports/customers

Paginated list of customers with preorder activity in the window.

Parameters

fromanyquery
toanyquery
offer_idanyquery
offer_idsanyquery
currencyanyquery
pageanyquery
per_pageanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Customers
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/reports/customers'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/customers', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/reports/customers')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Customers Export

POST
https://app.stoqapp.com/api/v2/external/preorders/reports/customers/export

Async CSV export of the customers report.

Body

application/json
fromany
toany
offer_idany
offer_idsany
product_idany
variant_idany
market_idany
currencyany
granularityany
metricsany
include_depositsany
include_balancesany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Customers Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/reports/customers/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "offer_id": "string",
    "offer_ids": [
      "string"
    ],
    "product_id": "78000000001",
    "variant_id": "45000000001",
    "market_id": "gid://shopify/Market/12345",
    "currency": "string",
    "granularity": "string",
    "metrics": "string",
    "include_deposits": "string",
    "include_balances": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/customers/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "offer_id": "string",
      "offer_ids": [
        "string"
      ],
      "product_id": "78000000001",
      "variant_id": "45000000001",
      "market_id": "gid://shopify/Market/12345",
      "currency": "string",
      "granularity": "string",
      "metrics": "string",
      "include_deposits": "string",
      "include_balances": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/reports/customers/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Engagement

GET
https://app.stoqapp.com/api/v2/external/preorders/reports/engagement

Preorder button engagement/funnel analytics: impressions, add-to-carts, add-to-cart rate, orders, and order rate — the same numbers on the merchant's preorder Engagement dashboard. Rates use unique shoppers. order_rate can exceed 1.0 because orders come from placed preorder orders, a different denominator than unique add-to-carts.

Parameters

fromanyquery
toanyquery
market_idanyquery
variant_idsanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Engagement
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/reports/engagement'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/engagement', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/reports/engagement')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Exports

GET
https://app.stoqapp.com/api/v2/external/preorders/reports/exports/{job_id}

Check the status of an async report export and get the download URL when ready.

Parameters

job_idstringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Exports
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/reports/exports/{job_id}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/exports/{job_id}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/reports/exports/{job_id}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Revenue

GET
https://app.stoqapp.com/api/v2/external/preorders/reports/revenue

Preorder revenue over a date window, bucketed by day/week/month.

Parameters

fromanyquery
toanyquery
offer_idanyquery
offer_idsanyquery
product_idanyquery
variant_idanyquery
market_idanyquery
currencyanyquery
granularityanyquery
include_depositsanyquery
include_balancesanyquery

Response

200OKobject

Success — example response shown.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Revenue
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/reports/revenue'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/revenue', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/reports/revenue')
data = response.json()
{
  "window": {
    "from": "2026-05-26T00:00:00Z",
    "to": "2026-06-25T23:59:59Z"
  },
  "granularity": "day",
  "currency": "USD",
  "include_deposits": true,
  "include_balances": true,
  "total_revenue": "47825.50",
  "series": [
    {
      "date": "2026-06-25T00:00:00Z",
      "revenue": "2450.75",
      "orders": 18
    },
    {
      "date": "2026-06-24T00:00:00Z",
      "revenue": "3180.25",
      "orders": 24
    }
  ],
  "by_offer": [
    {
      "offer_id": 1,
      "offer_name": "Summer Sneaker Drop",
      "revenue": "28500.00"
    },
    {
      "offer_id": 2,
      "offer_name": "Winter Collection",
      "revenue": "19325.50"
    }
  ]
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Revenue Export

POST
https://app.stoqapp.com/api/v2/external/preorders/reports/revenue/export

Async CSV export of the preorder revenue report.

Body

application/json
fromany
toany
offer_idany
offer_idsany
product_idany
variant_idany
market_idany
currencyany
granularityany
metricsany
include_depositsany
include_balancesany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Revenue Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/reports/revenue/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "offer_id": "string",
    "offer_ids": [
      "string"
    ],
    "product_id": "78000000001",
    "variant_id": "45000000001",
    "market_id": "gid://shopify/Market/12345",
    "currency": "string",
    "granularity": "string",
    "metrics": "string",
    "include_deposits": "string",
    "include_balances": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/revenue/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "offer_id": "string",
      "offer_ids": [
        "string"
      ],
      "product_id": "78000000001",
      "variant_id": "45000000001",
      "market_id": "gid://shopify/Market/12345",
      "currency": "string",
      "granularity": "string",
      "metrics": "string",
      "include_deposits": "string",
      "include_balances": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/reports/revenue/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Summary

GET
https://app.stoqapp.com/api/v2/external/preorders/reports/summary

High-level overview of preorder activity over a date window.

Parameters

rangestring | nullquery
fromanyquery
toanyquery
offer_idanyquery
offer_idsanyquery
product_idanyquery
variant_idanyquery
market_idanyquery
currencyanyquery

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Summary
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/reports/summary'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/summary', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/reports/summary')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Summary Export

POST
https://app.stoqapp.com/api/v2/external/preorders/reports/summary/export

Async CSV export of the preorder summary report.

Body

application/json
fromany
toany
offer_idany
offer_idsany
product_idany
variant_idany
market_idany
currencyany
granularityany
metricsany
include_depositsany
include_balancesany
pageany
per_pageany

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Summary Export
curl -X POST 'https://app.stoqapp.com/api/v2/external/preorders/reports/summary/export' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "string",
    "to": "string",
    "offer_id": "string",
    "offer_ids": [
      "string"
    ],
    "product_id": "78000000001",
    "variant_id": "45000000001",
    "market_id": "gid://shopify/Market/12345",
    "currency": "string",
    "granularity": "string",
    "metrics": "string",
    "include_deposits": "string",
    "include_balances": "string",
    "page": "string",
    "per_page": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/reports/summary/export', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "from": "string",
      "to": "string",
      "offer_id": "string",
      "offer_ids": [
        "string"
      ],
      "product_id": "78000000001",
      "variant_id": "45000000001",
      "market_id": "gid://shopify/Market/12345",
      "currency": "string",
      "granularity": "string",
      "metrics": "string",
      "include_deposits": "string",
      "include_balances": "string",
      "page": "string",
      "per_page": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}

response = requests.post('https://app.stoqapp.com/api/v2/external/preorders/reports/summary/export', json=payload)
data = response.json()
Request Body
{
  "from": "string",
  "to": "string",
  "offer_id": "string",
  "offer_ids": [
    "string"
  ],
  "product_id": "78000000001",
  "variant_id": "45000000001",
  "market_id": "gid://shopify/Market/12345",
  "currency": "string",
  "granularity": "string",
  "metrics": "string",
  "include_deposits": "string",
  "include_balances": "string",
  "page": "string",
  "per_page": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Preorders · Templates

Read

GET
https://app.stoqapp.com/api/v2/external/preorders/templates/{locale}

Read the position-0 preorder confirmation email/SMS template for a locale.

Parameters

localestringrequiredpath

Response

200OKobject

Success — the requested resource.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Read
curl -X GET 'https://app.stoqapp.com/api/v2/external/preorders/templates/{locale}'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/templates/{locale}', {
  method: 'GET',
});

const data = await response.json();
import requests

response = requests.get('https://app.stoqapp.com/api/v2/external/preorders/templates/{locale}')
data = response.json()
{}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Update

PATCH
https://app.stoqapp.com/api/v2/external/preorders/templates/{locale}

Update the position-0 preorder confirmation email/SMS template for a locale.

Note: Deep partial over the template fields. Rejects HTML (except in email_css_config) and runs Template validations and callbacks. email_reviews_title is the heading for the Judge.me reviews section that renders on the preorder confirmation email (for example "What customers are saying"). Colours are flat hex fields. Social links and the social icon colour are shared: saving one sets it on every notification template of the shop.

Body

application/json
email_subjectstring
email_preheaderstring
email_headerstring
email_descriptionstring
email_button_textstring
email_footerstring
email_reviews_titlestring
push_titlestring
push_bodystring
push_button_textstring
sms_bodystring
klaviyo_flow_namestring
klaviyo_sms_flow_namestring
email_background_colorstring
email_section_colorstring
email_text_colorstring
email_border_radiusany
email_button_background_colorstring
email_button_text_colorstring
email_button_border_radiusany
email_css_configstring
email_facebook_linkstring
email_instagram_linkstring
email_pinterest_linkstring
email_twitter_linkstring
email_tiktok_linkstring
email_whatsapp_linkstring
email_youtube_linkstring
email_social_icon_colorstring
email_reviews_enabledboolean
email_reviews_countany
email_reviews_min_ratingany

Parameters

localestringrequiredpath

Response

200OKobject

Success — the updated resource.

202AcceptedJobAccepted

Accepted — async/bulk work was queued. Poll the returned job.

401UnauthorizedError

Missing or invalid X-Auth-Token.

404Not FoundError

The resource does not exist for this shop, or the action path is not registered.

422Unprocessable EntityError

The request failed validation.

429Too Many RequestsError

Rate limited — cost-weighted per token (read 1, write 2; 40 points / 60s). Check Retry-After.

Authorization

ApiKeyAuthapiKey in header

Send your shop’s STOQ API key in the X-Auth-Token header on every request. Find it in the STOQ app under Settings → Integrations → API Key. The key resolves the shop context; the same scheme is used by the MCP server and the v1 API.

Update
curl -X PATCH 'https://app.stoqapp.com/api/v2/external/preorders/templates/{locale}' \
  -H 'Content-Type: application/json' \
  -d '{
    "email_subject": "string",
    "email_preheader": "string",
    "email_header": "string",
    "email_description": "string",
    "email_button_text": "Preorder now",
    "email_footer": "string",
    "email_reviews_title": "string",
    "push_title": "string",
    "push_body": "string",
    "push_button_text": "Preorder now",
    "sms_body": "string",
    "klaviyo_flow_name": "Summer Sneaker Drop",
    "klaviyo_sms_flow_name": "Summer Sneaker Drop",
    "email_background_color": "#1A1A1A",
    "email_section_color": "#1A1A1A",
    "email_text_color": "#1A1A1A",
    "email_border_radius": "string",
    "email_button_background_color": "#1A1A1A",
    "email_button_text_color": "#1A1A1A",
    "email_button_border_radius": "string",
    "email_css_config": "string",
    "email_facebook_link": "string",
    "email_instagram_link": "string",
    "email_pinterest_link": "string",
    "email_twitter_link": "string",
    "email_tiktok_link": "string",
    "email_whatsapp_link": "string",
    "email_youtube_link": "string",
    "email_social_icon_color": "#1A1A1A",
    "email_reviews_enabled": true,
    "email_reviews_count": 5,
    "email_reviews_min_rating": "string"
  }'
const response = await fetch('https://app.stoqapp.com/api/v2/external/preorders/templates/{locale}', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "email_subject": "string",
      "email_preheader": "string",
      "email_header": "string",
      "email_description": "string",
      "email_button_text": "Preorder now",
      "email_footer": "string",
      "email_reviews_title": "string",
      "push_title": "string",
      "push_body": "string",
      "push_button_text": "Preorder now",
      "sms_body": "string",
      "klaviyo_flow_name": "Summer Sneaker Drop",
      "klaviyo_sms_flow_name": "Summer Sneaker Drop",
      "email_background_color": "#1A1A1A",
      "email_section_color": "#1A1A1A",
      "email_text_color": "#1A1A1A",
      "email_border_radius": "string",
      "email_button_background_color": "#1A1A1A",
      "email_button_text_color": "#1A1A1A",
      "email_button_border_radius": "string",
      "email_css_config": "string",
      "email_facebook_link": "string",
      "email_instagram_link": "string",
      "email_pinterest_link": "string",
      "email_twitter_link": "string",
      "email_tiktok_link": "string",
      "email_whatsapp_link": "string",
      "email_youtube_link": "string",
      "email_social_icon_color": "#1A1A1A",
      "email_reviews_enabled": true,
      "email_reviews_count": 5,
      "email_reviews_min_rating": "string"
    }),
});

const data = await response.json();
import requests

payload = {
  "email_subject": "string",
  "email_preheader": "string",
  "email_header": "string",
  "email_description": "string",
  "email_button_text": "Preorder now",
  "email_footer": "string",
  "email_reviews_title": "string",
  "push_title": "string",
  "push_body": "string",
  "push_button_text": "Preorder now",
  "sms_body": "string",
  "klaviyo_flow_name": "Summer Sneaker Drop",
  "klaviyo_sms_flow_name": "Summer Sneaker Drop",
  "email_background_color": "#1A1A1A",
  "email_section_color": "#1A1A1A",
  "email_text_color": "#1A1A1A",
  "email_border_radius": "string",
  "email_button_background_color": "#1A1A1A",
  "email_button_text_color": "#1A1A1A",
  "email_button_border_radius": "string",
  "email_css_config": "string",
  "email_facebook_link": "string",
  "email_instagram_link": "string",
  "email_pinterest_link": "string",
  "email_twitter_link": "string",
  "email_tiktok_link": "string",
  "email_whatsapp_link": "string",
  "email_youtube_link": "string",
  "email_social_icon_color": "#1A1A1A",
  "email_reviews_enabled": True,
  "email_reviews_count": 5,
  "email_reviews_min_rating": "string"
}

response = requests.patch('https://app.stoqapp.com/api/v2/external/preorders/templates/{locale}', json=payload)
data = response.json()
Request Body
{
  "email_subject": "string",
  "email_preheader": "string",
  "email_header": "string",
  "email_description": "string",
  "email_button_text": "Preorder now",
  "email_footer": "string",
  "email_reviews_title": "string",
  "push_title": "string",
  "push_body": "string",
  "push_button_text": "Preorder now",
  "sms_body": "string",
  "klaviyo_flow_name": "Summer Sneaker Drop",
  "klaviyo_sms_flow_name": "Summer Sneaker Drop",
  "email_background_color": "#1A1A1A",
  "email_section_color": "#1A1A1A",
  "email_text_color": "#1A1A1A",
  "email_border_radius": "string",
  "email_button_background_color": "#1A1A1A",
  "email_button_text_color": "#1A1A1A",
  "email_button_border_radius": "string",
  "email_css_config": "string",
  "email_facebook_link": "string",
  "email_instagram_link": "string",
  "email_pinterest_link": "string",
  "email_twitter_link": "string",
  "email_tiktok_link": "string",
  "email_whatsapp_link": "string",
  "email_youtube_link": "string",
  "email_social_icon_color": "#1A1A1A",
  "email_reviews_enabled": true,
  "email_reviews_count": 5,
  "email_reviews_min_rating": "string"
}
{}
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}
{
  "errors": [
    "Unauthorized"
  ]
}
{
  "errors": [
    "Offer not found"
  ]
}
{
  "errors": [
    "name is required"
  ]
}
{
  "errors": [
    "Rate limit exceeded"
  ]
}

Models

Error

object

Error envelope returned by every failed request.

errorsArray<string>required
Example
{
  "errors": [
    "name is required"
  ]
}

JobAccepted

object

Returned for async/bulk work — poll the job until it reaches a terminal state.

job_idstring
status_urlstring
Example
{
  "job_id": "job_a1b2c3",
  "status_url": "/api/v2/external/jobs/job_a1b2c3"
}