Build with Connected Inventory

API reference

Connect your inventory to your own tools or AI agents. Manage groups and bundles, refresh SKU connections, and follow sync activity.

The API is still in early access and subject to change.
BASE URLhttps://ci-api.notasideproject.com/api/v1OpenAPI 3.1 ↓
Advance plan required. Open Connected Inventory in Shopify Admin to check your plan and access, or contact us at support@notasideproject.com.

Your first request

Create a key in the app’s API keys page. Set CI_API_KEY and SHOP_DOMAIN in your server environment, then list your manual groups:

cURL · list manual groups
curl --request GET 'https://ci-api.notasideproject.com/api/v1/manual_groups?limit=50' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"

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.

Required headers
Authorization: Bearer civ_<your-secret>
X-Shopify-Shop-Domain: your-store.myshopify.com

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
FieldDescription
Readalways includedAll GET endpoints: groups, settings, refresh progress, activity logs, and sync history.
WriteoptionalCreate or replace manual and bundle groups; enable any group type; start smart-group refreshes.
DeleteoptionalDelete 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
FieldDescription
idintegerConnected Inventory group ID, not a Shopify ID.
namestringStored group name.
statusstringStored group status, for example active. Separate from the group type’s enabled setting.
created_at / updated_atstring | nullISO 8601 timestamps.
member_countintegerNumber 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 Requests
Retry-After: 60
Cache-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
FieldDescription
product_gidstring · requiredFull Shopify Product GID, such as gid://shopify/Product/100.
variant_gidstring · requiredFull Shopify ProductVariant GID, such as gid://shopify/ProductVariant/1001.
inventory_item_gidstring · requiredFull Shopify InventoryItem GID. Its numeric ID is used for inventory sync.
product_titlestring · requiredNonblank product title. Saved as supplied; not fetched from Shopify.
variant_titlestring · requiredNonblank 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."
  }
}
HTTPCode & recovery
400shop_domain_required

Send a nonblank X-Shopify-Shop-Domain header.

400idempotency_key_required

Send Idempotency-Key when creating a manual or bundle group.

401invalid_key

The bearer key is missing, unknown, or revoked.

402plan_required

The shop needs an active Advance entitlement.

403shop_domain_mismatch

The supplied domain does not match the key’s shop.

403permission_required

The key lacks Write or Delete permission for this operation.

404not_found

The resource does not exist in this shop. Another shop’s resource is also reported as not found.

409idempotency_conflict

This API key already used the Idempotency-Key with different raw request bytes.

409idempotency_in_progress

A create with this Idempotency-Key is still running. Retry later with the same key and body.

409smart_groups_disabled

Enable smart groups before requesting a refresh.

409refresh_in_progress

A smart-group refresh is already running. Wait for it to finish before starting another.

422validation_failed

Invalid JSON, request fields, group membership, or pagination cursor. Read error.message for the reason.

429rate_limited

The shop’s shared request allowance is exhausted. Wait for Retry-After (60 seconds).

503rate_limit_unavailable

The rate limit could not be checked; the action did not run. Retry later.

503shopify_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.

List manual groups

GET/api/v1/manual_groups
Read permission200 OK

Return group summaries in descending ID order. Fetch a group by ID to read its members.

Query: limit (default 50, maximum 200) and after (the previous next_cursor). See pagination.

Request example
cURL
curl --request GET 'https://ci-api.notasideproject.com/api/v1/manual_groups?limit=50' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "data": [
    {
      "id": 42,
      "name": "Everyday totes",
      "status": "active",
      "created_at": "2026-10-12T08:00:00Z",
      "updated_at": "2026-10-12T08:00:00Z",
      "member_count": 2
    }
  ],
  "next_cursor": null
}

data is an array of the records below; next_cursor is a string or null.

List manual groups: response fields
FieldDescription
idintegerConnected Inventory group ID, not a Shopify ID.
namestringStored group name.
statusstringStored group status, for example active. Separate from the group type’s enabled setting.
created_at / updated_atstring | nullISO 8601 timestamps.
member_countintegerNumber of members. Bundles count the master plus components, regardless of component quantity.

Get a manual group

GET/api/v1/manual_groups/{id}
Read permission200 OK

Return one group and every saved member belonging to the authenticated shop.

id — required positive integer identifying this resource in Connected Inventory.

Request example
cURL
curl --request GET 'https://ci-api.notasideproject.com/api/v1/manual_groups/42' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "id": 42,
  "name": "Everyday totes",
  "variants": [
    {
      "product_gid": "gid://shopify/Product/100",
      "variant_gid": "gid://shopify/ProductVariant/1001",
      "inventory_item_gid": "gid://shopify/InventoryItem/2001",
      "product_title": "Everyday tote",
      "variant_title": "Natural"
    },
    {
      "product_gid": "gid://shopify/Product/101",
      "variant_gid": "gid://shopify/ProductVariant/1002",
      "inventory_item_gid": "gid://shopify/InventoryItem/2002",
      "product_title": "Everyday tote — gift listing",
      "variant_title": "Natural"
    }
  ],
  "status": "active",
  "created_at": "2026-10-12T08:00:00Z",
  "updated_at": "2026-10-12T08:00:00Z"
}
Get a manual group: response fields
FieldDescription
id / name / status / created_at / updated_atgroup fieldsSame fields as a group summary, without member_count.
variantsVariant[]Every saved member with the five variant fields. GIDs can be null for older incomplete records.

Operation errors: 404 not_found. All operations also use the shared authentication and rate-limit errors.

Create a manual group

POST/api/v1/manual_groups
Write permission201 CreatedIdempotency-Key required

Create a group using the supplied variant metadata. This does not look up or verify the variants in Shopify.

Create a manual group: request fields
FieldDescription
namestring · requiredNonblank group name.
variantsVariantInput[] · requiredAt least two distinct variants, each with all five variant fields. No duplicate variant_gid values.
Request example
cURL
curl --request POST 'https://ci-api.notasideproject.com/api/v1/manual_groups' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN" \
  --header 'Idempotency-Key: create-manual-groups-001' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Everyday totes",
  "variants": [
    {
      "product_gid": "gid://shopify/Product/100",
      "variant_gid": "gid://shopify/ProductVariant/1001",
      "inventory_item_gid": "gid://shopify/InventoryItem/2001",
      "product_title": "Everyday tote",
      "variant_title": "Natural"
    },
    {
      "product_gid": "gid://shopify/Product/101",
      "variant_gid": "gid://shopify/ProductVariant/1002",
      "inventory_item_gid": "gid://shopify/InventoryItem/2002",
      "product_title": "Everyday tote — gift listing",
      "variant_title": "Natural"
    }
  ]
}'
Response example and fields
201 response
{
  "id": 42,
  "name": "Everyday totes",
  "variants": [
    {
      "product_gid": "gid://shopify/Product/100",
      "variant_gid": "gid://shopify/ProductVariant/1001",
      "inventory_item_gid": "gid://shopify/InventoryItem/2001",
      "product_title": "Everyday tote",
      "variant_title": "Natural"
    },
    {
      "product_gid": "gid://shopify/Product/101",
      "variant_gid": "gid://shopify/ProductVariant/1002",
      "inventory_item_gid": "gid://shopify/InventoryItem/2002",
      "product_title": "Everyday tote — gift listing",
      "variant_title": "Natural"
    }
  ],
  "status": "active",
  "created_at": "2026-10-12T08:00:00Z",
  "updated_at": "2026-10-12T08:00:00Z"
}
Create a manual group: response fields
FieldDescription
id / name / status / created_at / updated_atgroup fieldsSame fields as a group summary, without member_count.
variantsVariant[]Every saved member with the five variant fields. GIDs can be null for older incomplete records.

Operation errors: 400 idempotency_key_required, 409 idempotency_conflict, 409 idempotency_in_progress, 422 validation_failed. All operations also use the shared authentication and rate-limit errors.

Replace a manual group

PUT/api/v1/manual_groups/{id}
Write permission200 OK

Replace the complete group name and membership. Send all desired members; omitted members are removed. This is not a partial update.

id — required positive integer identifying this resource in Connected Inventory.

Replace a manual group: request fields
FieldDescription
namestring · requiredNonblank group name.
variantsVariantInput[] · requiredAt least two distinct variants, each with all five variant fields. No duplicate variant_gid values.
Request example
cURL
curl --request PUT 'https://ci-api.notasideproject.com/api/v1/manual_groups/42' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN" \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Everyday totes",
  "variants": [
    {
      "product_gid": "gid://shopify/Product/100",
      "variant_gid": "gid://shopify/ProductVariant/1001",
      "inventory_item_gid": "gid://shopify/InventoryItem/2001",
      "product_title": "Everyday tote",
      "variant_title": "Natural"
    },
    {
      "product_gid": "gid://shopify/Product/101",
      "variant_gid": "gid://shopify/ProductVariant/1002",
      "inventory_item_gid": "gid://shopify/InventoryItem/2002",
      "product_title": "Everyday tote — gift listing",
      "variant_title": "Natural"
    }
  ]
}'
Response example and fields
200 response
{
  "id": 42,
  "name": "Everyday totes",
  "variants": [
    {
      "product_gid": "gid://shopify/Product/100",
      "variant_gid": "gid://shopify/ProductVariant/1001",
      "inventory_item_gid": "gid://shopify/InventoryItem/2001",
      "product_title": "Everyday tote",
      "variant_title": "Natural"
    },
    {
      "product_gid": "gid://shopify/Product/101",
      "variant_gid": "gid://shopify/ProductVariant/1002",
      "inventory_item_gid": "gid://shopify/InventoryItem/2002",
      "product_title": "Everyday tote — gift listing",
      "variant_title": "Natural"
    }
  ],
  "status": "active",
  "created_at": "2026-10-12T08:00:00Z",
  "updated_at": "2026-10-12T08:00:00Z"
}
Replace a manual group: response fields
FieldDescription
id / name / status / created_at / updated_atgroup fieldsSame fields as a group summary, without member_count.
variantsVariant[]Every saved member with the five variant fields. GIDs can be null for older incomplete records.

Operation errors: 404 not_found, 422 validation_failed. All operations also use the shared authentication and rate-limit errors.

Delete a manual group

DELETE/api/v1/manual_groups/{id}
Delete permission204 No Content

Delete this group and its membership records. Shopify products and variants are not deleted. There is no response body.

id — required positive integer identifying this resource in Connected Inventory.

Request example
cURL
curl --request DELETE 'https://ci-api.notasideproject.com/api/v1/manual_groups/42' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"

Operation errors: 404 not_found. All operations also use the shared authentication and rate-limit errors.

Read manual-group status

GET/api/v1/manual_groups/status
Read permission200 OK

Read the shop-wide enabled setting for this group type.

Request example
cURL
curl --request GET 'https://ci-api.notasideproject.com/api/v1/manual_groups/status' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "enabled": true
}
Read manual-group status: response fields
FieldDescription
enabledbooleanWhether this group type is enabled for the entire shop.

Enable manual groups

PUT/api/v1/manual_groups/enable
Write permission200 OK

Enable this group type for the shop. Repeating the request leaves the setting enabled. No request body is required.

Request example
cURL
curl --request PUT 'https://ci-api.notasideproject.com/api/v1/manual_groups/enable' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "enabled": true
}
Enable manual groups: response fields
FieldDescription
enabledbooleanWhether this group type is enabled for the entire shop.

Disable manual groups

PUT/api/v1/manual_groups/disable
Delete permission200 OK

Disable this group type for the shop. Existing groups and members are retained. No request body is required.

Request example
cURL
curl --request PUT 'https://ci-api.notasideproject.com/api/v1/manual_groups/disable' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "enabled": false
}
Disable manual groups: response fields
FieldDescription
enabledbooleanWhether this group type is enabled for the entire shop.

Endpoints

Bundle groups

Define a sellable master variant and the component quantities that make up a bundle.

List bundle groups

GET/api/v1/bundle_groups
Read permission200 OK

Return group summaries in descending ID order. Fetch a group by ID to read its members.

Query: limit (default 50, maximum 200) and after (the previous next_cursor). See pagination.

Request example
cURL
curl --request GET 'https://ci-api.notasideproject.com/api/v1/bundle_groups?limit=50' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "data": [
    {
      "id": 42,
      "name": "Tote duo",
      "status": "active",
      "created_at": "2026-10-12T08:00:00Z",
      "updated_at": "2026-10-12T08:00:00Z",
      "member_count": 2
    }
  ],
  "next_cursor": null
}

data is an array of the records below; next_cursor is a string or null.

List bundle groups: response fields
FieldDescription
idintegerConnected Inventory group ID, not a Shopify ID.
namestringStored group name.
statusstringStored group status, for example active. Separate from the group type’s enabled setting.
created_at / updated_atstring | nullISO 8601 timestamps.
member_countintegerNumber of members. Bundles count the master plus components, regardless of component quantity.

Get a bundle group

GET/api/v1/bundle_groups/{id}
Read permission200 OK

Return one group and every saved member belonging to the authenticated shop.

id — required positive integer identifying this resource in Connected Inventory.

Request example
cURL
curl --request GET 'https://ci-api.notasideproject.com/api/v1/bundle_groups/42' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "id": 42,
  "name": "Tote duo",
  "master": {
    "product_gid": "gid://shopify/Product/101",
    "variant_gid": "gid://shopify/ProductVariant/1002",
    "inventory_item_gid": "gid://shopify/InventoryItem/2002",
    "product_title": "Tote duo",
    "variant_title": "Default Title"
  },
  "components": [
    {
      "product_gid": "gid://shopify/Product/100",
      "variant_gid": "gid://shopify/ProductVariant/1001",
      "inventory_item_gid": "gid://shopify/InventoryItem/2001",
      "product_title": "Everyday tote",
      "variant_title": "Natural",
      "quantity": 2
    }
  ],
  "status": "active",
  "created_at": "2026-10-12T08:00:00Z",
  "updated_at": "2026-10-12T08:00:00Z"
}
Get a bundle group: response fields
FieldDescription
id / name / status / created_at / updated_atgroup fieldsSame fields as a group summary, without member_count.
masterVariantThe saved master with the five variant fields.
componentsComponent[]Saved component variants, each with an integer quantity in addition to the five variant fields.

Operation errors: 404 not_found. All operations also use the shared authentication and rate-limit errors.

Create a bundle group

POST/api/v1/bundle_groups
Write permission201 CreatedIdempotency-Key required

Create a group using the supplied variant metadata. This does not look up or verify the variants in Shopify.

Create a bundle group: request fields
FieldDescription
namestring · requiredNonblank group name.
masterVariantInput · requiredThe sellable bundle variant. All five variant fields are required.
componentsComponentInput[] · requiredAt least one distinct component, with all five variant fields and quantity (integer ≥ 1) on each.
Request example
cURL
curl --request POST 'https://ci-api.notasideproject.com/api/v1/bundle_groups' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN" \
  --header 'Idempotency-Key: create-bundle-groups-001' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Tote duo",
  "master": {
    "product_gid": "gid://shopify/Product/101",
    "variant_gid": "gid://shopify/ProductVariant/1002",
    "inventory_item_gid": "gid://shopify/InventoryItem/2002",
    "product_title": "Tote duo",
    "variant_title": "Default Title"
  },
  "components": [
    {
      "product_gid": "gid://shopify/Product/100",
      "variant_gid": "gid://shopify/ProductVariant/1001",
      "inventory_item_gid": "gid://shopify/InventoryItem/2001",
      "product_title": "Everyday tote",
      "variant_title": "Natural",
      "quantity": 2
    }
  ]
}'
Response example and fields
201 response
{
  "id": 42,
  "name": "Tote duo",
  "master": {
    "product_gid": "gid://shopify/Product/101",
    "variant_gid": "gid://shopify/ProductVariant/1002",
    "inventory_item_gid": "gid://shopify/InventoryItem/2002",
    "product_title": "Tote duo",
    "variant_title": "Default Title"
  },
  "components": [
    {
      "product_gid": "gid://shopify/Product/100",
      "variant_gid": "gid://shopify/ProductVariant/1001",
      "inventory_item_gid": "gid://shopify/InventoryItem/2001",
      "product_title": "Everyday tote",
      "variant_title": "Natural",
      "quantity": 2
    }
  ],
  "status": "active",
  "created_at": "2026-10-12T08:00:00Z",
  "updated_at": "2026-10-12T08:00:00Z"
}
Create a bundle group: response fields
FieldDescription
id / name / status / created_at / updated_atgroup fieldsSame fields as a group summary, without member_count.
masterVariantThe saved master with the five variant fields.
componentsComponent[]Saved component variants, each with an integer quantity in addition to the five variant fields.

Operation errors: 400 idempotency_key_required, 409 idempotency_conflict, 409 idempotency_in_progress, 422 validation_failed. All operations also use the shared authentication and rate-limit errors.

Replace a bundle group

PUT/api/v1/bundle_groups/{id}
Write permission200 OK

Replace the complete group name and membership. Send all desired members; omitted members are removed. This is not a partial update.

id — required positive integer identifying this resource in Connected Inventory.

Replace a bundle group: request fields
FieldDescription
namestring · requiredNonblank group name.
masterVariantInput · requiredThe sellable bundle variant. All five variant fields are required.
componentsComponentInput[] · requiredAt least one distinct component, with all five variant fields and quantity (integer ≥ 1) on each.
Request example
cURL
curl --request PUT 'https://ci-api.notasideproject.com/api/v1/bundle_groups/42' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN" \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Tote duo",
  "master": {
    "product_gid": "gid://shopify/Product/101",
    "variant_gid": "gid://shopify/ProductVariant/1002",
    "inventory_item_gid": "gid://shopify/InventoryItem/2002",
    "product_title": "Tote duo",
    "variant_title": "Default Title"
  },
  "components": [
    {
      "product_gid": "gid://shopify/Product/100",
      "variant_gid": "gid://shopify/ProductVariant/1001",
      "inventory_item_gid": "gid://shopify/InventoryItem/2001",
      "product_title": "Everyday tote",
      "variant_title": "Natural",
      "quantity": 2
    }
  ]
}'
Response example and fields
200 response
{
  "id": 42,
  "name": "Tote duo",
  "master": {
    "product_gid": "gid://shopify/Product/101",
    "variant_gid": "gid://shopify/ProductVariant/1002",
    "inventory_item_gid": "gid://shopify/InventoryItem/2002",
    "product_title": "Tote duo",
    "variant_title": "Default Title"
  },
  "components": [
    {
      "product_gid": "gid://shopify/Product/100",
      "variant_gid": "gid://shopify/ProductVariant/1001",
      "inventory_item_gid": "gid://shopify/InventoryItem/2001",
      "product_title": "Everyday tote",
      "variant_title": "Natural",
      "quantity": 2
    }
  ],
  "status": "active",
  "created_at": "2026-10-12T08:00:00Z",
  "updated_at": "2026-10-12T08:00:00Z"
}
Replace a bundle group: response fields
FieldDescription
id / name / status / created_at / updated_atgroup fieldsSame fields as a group summary, without member_count.
masterVariantThe saved master with the five variant fields.
componentsComponent[]Saved component variants, each with an integer quantity in addition to the five variant fields.

Operation errors: 404 not_found, 422 validation_failed. All operations also use the shared authentication and rate-limit errors.

Delete a bundle group

DELETE/api/v1/bundle_groups/{id}
Delete permission204 No Content

Delete this group and its membership records. Shopify products and variants are not deleted. There is no response body.

id — required positive integer identifying this resource in Connected Inventory.

Request example
cURL
curl --request DELETE 'https://ci-api.notasideproject.com/api/v1/bundle_groups/42' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"

Operation errors: 404 not_found. All operations also use the shared authentication and rate-limit errors.

Read bundle-group status

GET/api/v1/bundle_groups/status
Read permission200 OK

Read the shop-wide enabled setting for this group type.

Request example
cURL
curl --request GET 'https://ci-api.notasideproject.com/api/v1/bundle_groups/status' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "enabled": true
}
Read bundle-group status: response fields
FieldDescription
enabledbooleanWhether this group type is enabled for the entire shop.

Enable bundle groups

PUT/api/v1/bundle_groups/enable
Write permission200 OK

Enable this group type for the shop. Repeating the request leaves the setting enabled. No request body is required.

Request example
cURL
curl --request PUT 'https://ci-api.notasideproject.com/api/v1/bundle_groups/enable' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "enabled": true
}
Enable bundle groups: response fields
FieldDescription
enabledbooleanWhether this group type is enabled for the entire shop.

Disable bundle groups

PUT/api/v1/bundle_groups/disable
Delete permission200 OK

Disable this group type for the shop. Existing groups and members are retained. No request body is required.

Request example
cURL
curl --request PUT 'https://ci-api.notasideproject.com/api/v1/bundle_groups/disable' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "enabled": false
}
Disable bundle groups: response fields
FieldDescription
enabledbooleanWhether this group type is enabled for the entire shop.

Endpoints

Smart groups

Read groups generated from matching SKUs. The API calls these auto_groups. Membership is generated by a refresh, rather than written directly.

List smart groups

GET/api/v1/auto_groups
Read permission200 OK

Return active smart-group summaries in descending ID order. The list does not include member details.

Query: limit (default 50, maximum 200) and after (the previous next_cursor). See pagination.

Request example
cURL
curl --request GET 'https://ci-api.notasideproject.com/api/v1/auto_groups?limit=50' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "data": [
    {
      "id": 42,
      "name": "TOTE-NATURAL",
      "status": "active",
      "created_at": "2026-10-12T08:00:00Z",
      "updated_at": "2026-10-12T08:00:00Z",
      "member_count": 2
    }
  ],
  "next_cursor": null
}

data is an array of the records below; next_cursor is a string or null.

List smart groups: response fields
FieldDescription
idintegerConnected Inventory group ID, not a Shopify ID.
namestringStored group name.
statusstringStored group status, for example active. Separate from the group type’s enabled setting.
created_at / updated_atstring | nullISO 8601 timestamps.
member_countintegerNumber of members. Bundles count the master plus components, regardless of component quantity.

Get a smart group

GET/api/v1/auto_groups/{id}
Read permission200 OK

Read an active smart group and all of its saved members. Missing, inactive, and other shops’ groups return not_found.

id — required positive integer identifying this resource in Connected Inventory.

Request example
cURL
curl --request GET 'https://ci-api.notasideproject.com/api/v1/auto_groups/42' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "id": 42,
  "name": "TOTE-NATURAL",
  "variants": [
    {
      "product_gid": "gid://shopify/Product/100",
      "variant_gid": "gid://shopify/ProductVariant/1001",
      "inventory_item_gid": "gid://shopify/InventoryItem/2001",
      "product_title": "Everyday tote",
      "variant_title": "Natural"
    },
    {
      "product_gid": "gid://shopify/Product/101",
      "variant_gid": "gid://shopify/ProductVariant/1002",
      "inventory_item_gid": "gid://shopify/InventoryItem/2002",
      "product_title": "Everyday tote — gift listing",
      "variant_title": "Natural"
    }
  ],
  "status": "active",
  "created_at": "2026-10-12T08:00:00Z",
  "updated_at": "2026-10-12T08:00:00Z"
}
Get a smart group: response fields
FieldDescription
id / name / status / created_at / updated_atgroup fieldsSame fields as a group summary, without member_count.
variantsVariant[]Every saved member with the five variant fields. GIDs can be null for older incomplete records.

Operation errors: 404 not_found. All operations also use the shared authentication and rate-limit errors.

Read smart-group status

GET/api/v1/auto_groups/status
Read permission200 OK

Read the shop-wide smart-group setting.

Request example
cURL
curl --request GET 'https://ci-api.notasideproject.com/api/v1/auto_groups/status' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "enabled": true
}
Read smart-group status: response fields
FieldDescription
enabledbooleanWhether this group type is enabled for the entire shop.

Enable smart groups

PUT/api/v1/auto_groups/enable
Write permission200 OK

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.

Request example
cURL
curl --request PUT 'https://ci-api.notasideproject.com/api/v1/auto_groups/enable' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "enabled": true
}
Enable smart groups: response fields
FieldDescription
enabledbooleanWhether this group type is enabled for the entire shop.

Disable smart groups

PUT/api/v1/auto_groups/disable
Delete permission200 OK

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.

Request example
cURL
curl --request PUT 'https://ci-api.notasideproject.com/api/v1/auto_groups/disable' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "enabled": false
}
Disable smart groups: response fields
FieldDescription
enabledbooleanWhether this group type is enabled for the entire shop.

Start a smart-group refresh

POST/api/v1/auto_groups/refresh
Write permission202 Accepted

Queue a scan to rebuild smart groups. Smart groups must already be enabled. No request body or Idempotency-Key is required.

202 means accepted, not completed. Poll status_url on the API host using the same headers. Polling counts against the shared rate limit.

Request example
cURL
curl --request POST 'https://ci-api.notasideproject.com/api/v1/auto_groups/refresh' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
202 response
{
  "run_id": 7,
  "status": "queued",
  "status_url": "/api/v1/auto_groups/refresh_runs/7"
}
Start a smart-group refresh: response fields
FieldDescription
run_idintegerID of the accepted refresh run.
statusstringCurrent public status; usually queued on acceptance.
status_urlstringRelative API path to poll on the API host, with the same authentication headers.

Operation errors: 409 smart_groups_disabled, 409 refresh_in_progress. All operations also use the shared authentication and rate-limit errors.

Get refresh progress

GET/api/v1/auto_groups/refresh_runs/{id}
Read permission200 OK

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.

Request example
cURL
curl --request GET 'https://ci-api.notasideproject.com/api/v1/auto_groups/refresh_runs/7' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "run_id": 7,
  "status": "completed",
  "started_at": "2026-10-12T08:00:00Z",
  "finished_at": "2026-10-12T08:01:00Z",
  "error": null
}
Get refresh progress: response fields
FieldDescription
run_idintegerRefresh run ID.
statusstringqueued, running, completed, failed, or canceled. Stop polling on the last three.
started_at / finished_atstring | nullISO 8601 timestamps; null until set.
errorstring | nullStored reason for a failed or canceled run, when available; otherwise null.

Operation errors: 404 not_found. All operations also use the shared authentication and rate-limit errors.

Endpoints

Activity logs

Read the shop’s stored activity messages.

List activity logs

GET/api/v1/activity_logs
Read permission200 OK

Return the shop’s stored activity messages in descending ID order. This is the activity log, not the internal API audit log.

Query: limit (default 50, maximum 200) and after (the previous next_cursor). See pagination.

Request example
cURL
curl --request GET 'https://ci-api.notasideproject.com/api/v1/activity_logs?limit=50' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "data": [
    {
      "id": 108,
      "message": "Manual group created",
      "created_at": "2026-10-12T08:00:00Z"
    }
  ],
  "next_cursor": null
}

data is an array of the records below; next_cursor is a string or null.

List activity logs: response fields
FieldDescription
idintegerActivity log ID.
messagestring | nullStored activity message.
created_atstring | nullISO 8601 timestamp.

Endpoints

Sync history

Inspect stored inventory sync history and the group results associated with an order.

List sync history

GET/api/v1/sync_histories
Read permission200 OK

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.

Request example
cURL
curl --request GET 'https://ci-api.notasideproject.com/api/v1/sync_histories?limit=50' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "data": [
    {
      "id": 83,
      "order_id": "6001",
      "order_name": "#1001",
      "location_id": "9001",
      "location_name": "Main warehouse",
      "topic": "orders/create",
      "created_at": "2026-10-12T08:00:00Z"
    }
  ],
  "next_cursor": null
}

data is an array of the records below; next_cursor is a string or null.

List sync history: response fields
FieldDescription
idintegerConnected Inventory sync history ID; use this in the detail endpoint.
order_id / order_namestring | nullShopify order ID and display name, as stored.
location_id / location_namestring | nullShopify location ID and name, as stored.
topicstring | nullShopify event topic, such as orders/create.
created_atstring | nullISO 8601 timestamp.

Get a sync history

GET/api/v1/sync_histories/{id}
Read permission200 OK

Return a stored history with auto, manual, and bundle result arrays. The path ID is the Connected Inventory history ID, not the Shopify order ID.

id — required positive integer identifying this resource in Connected Inventory.

Request example
cURL
curl --request GET 'https://ci-api.notasideproject.com/api/v1/sync_histories/83' \
  --header "Authorization: Bearer $CI_API_KEY" \
  --header "X-Shopify-Shop-Domain: $SHOP_DOMAIN"
Response example and fields
200 response
{
  "id": 83,
  "order_id": "6001",
  "order_name": "#1001",
  "location_id": "9001",
  "location_name": "Main warehouse",
  "topic": "orders/create",
  "created_at": "2026-10-12T08:00:00Z",
  "auto": [],
  "manual": [
    {
      "status": "finished",
      "group_name": "Everyday totes",
      "variant_id": "1001",
      "product_title": "Everyday tote",
      "variant_title": "Natural"
    }
  ],
  "bundle": []
}
Get a sync history: response fields
FieldDescription
id / order_id / order_name / location_id / location_name / topic / created_athistory fieldsSame fields as a sync history summary.
auto / manual / bundleSyncResult[]Arrays of group sync results; an empty array means there are no stored results for that group type.
SyncResultobjectstatus, 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.

Operation errors: 404 not_found. All operations also use the shared authentication and rate-limit errors.

Ready to connect?

Start with a read-only key, then add the permissions your integration needs.

Get help with your integrationBack to the top ↑