The shop's ad and analytics tags
- Credentials
- OAuth access token
- Scopes
settings:write- Role
- Owners and admins only. Staff get
403 forbidden. - Subscription
- Needs an active plan. Otherwise
403 subscription_locked. - Idempotency
- Send an
Idempotency-Keyheader. A retry with the same key does the work once.
Meta pixel ID (digits), Google Analytics ID (G-...), Google site verification and Google Ads (AW-... or AW-.../label). Loaded on every shop page, so anything that is not exactly an ID is refused. A key left out keeps the stored tag; null or an empty string removes it. Answers with all four as saved.
Access: OAuth scope settings:write; owner/admin only; write-gated by the subscription.
merchantOAuth settings:writeAuthorizationBearer <token>OAuth 2.1 (authorization code + PKCE S256, public clients, dynamic registration) for connected AI apps. Effective power is scopes granted AND the person's role today AND the plan. orders:refund, billing:write and team:write are opt-in on the consent screen. Write implies read for marketing:read and messages:read, so a grant holding marketing:write passes a marketing:read check, and messages:send passes messages:read.
Scope: settings:write
storeId*stringA store the person can reach. Any other id answers 404, never 403.
Idempotency-Key*stringRequired on every write. Minted on the device when the person taps, reused on every retry. A write without one, or with one that does not match the pattern, is refused with 422 validation_error. Scoped to the token's subject, remembered 24 hours. A replay returns the first 2xx response with Idempotent-Replay: true; a request still running answers 409 in_flight; the same key with a different method, path or body answers 409 idempotency_key_reused; non-2xx results are not remembered. If the key store cannot be read nothing is processed and the answer is 503 idempotency_unavailable: retry with the same key.
^[A-Za-z0-9_-]{8,128}$application/json- body
Only what is sent changes; null or an empty string removes a tag.
metaPixelId?|length <= 4000ga4MeasurementId?|length <= 4000googleSiteVerification?|length <= 4000googleAds?|AW-... or AW-.../label, or the snippet Google emails.
length <= 4000OK
application/json- response
data*curl -X PATCH 'https://api.shopeazy.co/v1/merchant/stores/<storeId>/tracking' \ -H 'Authorization: Bearer <access_token>' \ -H 'Idempotency-Key: <unique_key>' \ -H 'Content-Type: application/json' \ -d '{}'{ "data": { "metaPixelId": "string", "ga4MeasurementId": "string", "googleSiteVerification": "string", "googleAds": "string" }}Change the shop's web address and/or connect its own domain PUT
Moves the ShopEazy address (`address`) and/or connects the merchant's own domain (`customDomain`; an empty one disconnects it). Only what is sent changes. A taken address is refused with the closest free one (422 `validation_error`); a custom domain needs the add-on, included on Growth (403 `plan_limit`). Connecting a domain attaches it (and its www/apex twin) to the storefronts project and to the sign-in domains, then checks its DNS: `domainState` says whether it is live and `records` what to create at the registrar until it is. Buying a domain is done elsewhere. Access: OAuth scope `settings:write`; owner/admin only; write-gated by the subscription.
Which sales channels are on, and why an off one cannot be switched on yet GET
The storefront, the API and WhatsApp. The same gates the console uses. Access: OAuth scope `store:read`; owner/admin only; not write-gated.