Examples use illustrative IDs and product titles. Replace them with your own shop’s values. Requests go to ci-api.notasideproject.com, not this documentation host.
Authentication
Every request requires both headers. The key selects the shop; the shop domain must match that key.
Use the full *.myshopify.com hostname. Do not include a protocol, path, or port. Surrounding whitespace is trimmed and comparison is case-insensitive. A shop query or body field cannot replace the header.
In API keys → Add, give the integration a name and choose its permissions. The secret is shown only once. Store it on your server in a credential manager, never in storefront JavaScript or a public repository.
A shop can create up to five keys. Existing shops with more can keep them, but must drop below five before creating another. Names and permissions cannot be edited; create a replacement key and delete the old one. Deletion revokes access immediately.
A missing or unknown key returns 401 invalid_key. With a valid key, a missing or blank domain returns 400 shop_domain_required; a mismatch returns 403 shop_domain_mismatch. Without an Advance entitlement, requests return 402 plan_required.
Permissions
Read is always included. Write and Delete are independent permissions selected when a key is created.
API key permissions
Field
Description
Readalways included
All GET endpoints: groups, settings, refresh progress, activity logs, and sync history.
Writeoptional
Create or replace manual and bundle groups; enable any group type; start smart-group refreshes.
Deleteoptional
Delete manual or bundle groups; disable any group type, including smart groups.
Disabling smart groups deletes their generated groups and members. Disabling manual or bundle groups only changes the setting and preserves the groups.
Pagination
All list endpoints return data and next_cursor, ordered by descending app ID. Send the returned cursor as the next request’s after query parameter. Treat it as opaque. Stop when it is null.
Empty or final page
{ "data": [], "next_cursor": null}
limit defaults to 50 and is capped at 200, except /sync_histories, which is capped at 50. Smaller positive limits are honored. Zero, negative, and nonnumeric values fall back to 50. An invalid after returns 422 validation_failed.
Lists contain summaries. Use the detail endpoint for variants, bundle members, or sync result arrays. Bundle member_count counts the master plus components; component quantity does not multiply the count.
Group summary response fields
Field
Description
idinteger
Connected Inventory group ID, not a Shopify ID.
namestring
Stored group name.
statusstring
Stored group status, for example active. Separate from the group type’s enabled setting.
created_at / updated_atstring | null
ISO 8601 timestamps.
member_countinteger
Number of members. Bundles count the master plus components, regardless of component quantity.
Rate limits & retries
The default allowance is 60 requests per fixed minute per shop, shared by all keys and all v1 endpoints. The minute starts with the first counted request and does not slide forward with later requests. The server can configure a different allowance.
Reads, writes, polling, validation failures, and idempotent replays all count. Failed key, domain, and plan checks do not.
Rate limit response
HTTP/1.1 429 Too Many RequestsRetry-After: 60Cache-Control: no-store{"error":{"code":"rate_limited","message":"API rate limit exceeded. Retry after 60 seconds."}}
Wait for Retry-After before retrying; add a small random delay when multiple clients retry together. Reuse the same idempotency key and exact body when retrying a create. No remaining-budget header is returned. A failed rate-limit check returns 503 rate_limit_unavailable and the action does not run.
Space refresh polling out—for example, every five seconds—and stop on a terminal status. A 202 refresh response only means the request was accepted.
Idempotency
POST /manual_groups and POST /bundle_groups require Idempotency-Key. Use a fresh value for each logical create and preserve it across retries.
Keys are scoped to an API key, across both create endpoints. Reusing a key with the same raw body returns the original response and status (201) without creating another group. Whitespace or JSON property order changes alter the raw body and can trigger 409 idempotency_conflict. Keep the serialized bytes identical.
An unfinished request returns 409 idempotency_in_progress; retry later. Missing keys return 400 idempotency_key_required. Other endpoints do not require or implement this create-replay contract.
Variant data & validation
Manual and bundle writes require JSON objects with Content-Type: application/json. Every variant must include these five fields:
Required variant fields
Field
Description
product_gidstring · required
Full Shopify Product GID, such as gid://shopify/Product/100.
variant_gidstring · required
Full Shopify ProductVariant GID, such as gid://shopify/ProductVariant/1001.
inventory_item_gidstring · required
Full Shopify InventoryItem GID. Its numeric ID is used for inventory sync.
product_titlestring · required
Nonblank product title. Saved as supplied; not fetched from Shopify.
variant_titlestring · required
Nonblank variant title. Use the actual variant title, including Default Title where applicable.
GIDs are case-sensitive and must end in a positive decimal ID. Bare numbers, wrong resource types, whitespace, query strings, and fragments are rejected. Legacy product_id, variant_id, and inventory_item_id fields are rejected.
You supply the variant metadata. The API saves these values without fetching the variant from Shopify. Verify that the variant belongs to your shop and that its product, variant, and inventory item IDs match. Returned titles are saved values, not a live Shopify read.
Manual groups: at least two distinct variants. A variant cannot belong to another manual group.
Bundles: one master and at least one distinct component. Every component requires an integer quantity ≥ 1.
A bundle master cannot be a component in the same or another bundle, or the master of another bundle. Components can be shared across bundles if they are not masters.
PUT replaces: always send the complete desired name and membership. It is not a patch.
Errors
Handled API errors use this JSON shape. Inspect the stable code and use message for context. Infrastructure or unknown-route errors may use a different response format.
Error response
{ "error": { "code": "validation_failed", "message": "A manual group must contain at least two distinct variants." }}
HTTP
Code & recovery
400
shop_domain_required
Send a nonblank X-Shopify-Shop-Domain header.
400
idempotency_key_required
Send Idempotency-Key when creating a manual or bundle group.
401
invalid_key
The bearer key is missing, unknown, or revoked.
402
plan_required
The shop needs an active Advance entitlement.
403
shop_domain_mismatch
The supplied domain does not match the key’s shop.
403
permission_required
The key lacks Write or Delete permission for this operation.
404
not_found
The resource does not exist in this shop. Another shop’s resource is also reported as not found.
409
idempotency_conflict
This API key already used the Idempotency-Key with different raw request bytes.
409
idempotency_in_progress
A create with this Idempotency-Key is still running. Retry later with the same key and body.
409
smart_groups_disabled
Enable smart groups before requesting a refresh.
409
refresh_in_progress
A smart-group refresh is already running. Wait for it to finish before starting another.
422
validation_failed
Invalid JSON, request fields, group membership, or pagination cursor. Read error.message for the reason.
429
rate_limited
The shop’s shared request allowance is exhausted. Wait for Retry-After (60 seconds).
503
rate_limit_unavailable
The rate limit could not be checked; the action did not run. Retry later.
503
shopify_unavailable
Shopify could not be reached while checking the subscription. Retry later.
Endpoints
Manual groups
Connect specific variants that share inventory. A variant can belong to only one manual group.
Enable smart groups. Switching from off to on starts at most one refresh in the background. Repeating enable while already enabled does not start another.
The response does not contain a run ID and does not mean the scan is complete. A separate refresh request can return refresh_in_progress until the automatic scan finishes. No request body is required.
Disable smart groups and delete the shop’s generated smart groups and their members. Shopify products and variants are not deleted.
Unlike disabling manual or bundle groups, this removes the generated groups. Enabling smart groups again starts a new scan. No request body is required.
Read the local run record. queued means waiting; running covers scanning, importing, and promoting. completed means the new groups can be read. failed and canceled are also terminal states.
Stop polling on completed, failed, or canceled. error contains the stored failure or cancellation reason when available. This read does not call Shopify.
id — required positive integer identifying this resource in Connected Inventory.
Return order sync history summaries in descending ID order. The default and maximum page size are both 50. Fetch a history by its app ID to read child results.
Query: limit (default 50, maximum 50) and after (the previous next_cursor). See pagination.
Arrays of group sync results; an empty array means there are no stored results for that group type.
SyncResultobject
status, group_name, variant_id, product_title, variant_title. Values are stored strings or null; variant_id is a legacy numeric Shopify ID string, not a GID.