# @kody/shopify — agent notes Human setup and intent live in [`README.md`](./README.md). This file is for agents: imports, smoke/dryRun execute snippets, and edge cases. Secrets by **name** only — never paste token values. Do not disable live webhooks or jobs. ## Auth | Lane | Credential | Notes | | --- | --- | --- | | Preferred | User secrets `shopifyClientId` + `shopifyClientSecret` | Dev Dashboard client credentials; token exchanged per invoke | | Legacy | User secret `shopifyAdminAccessToken` | Static Admin token (`shpat_…`); wins if present | Pass `shop: "your-store"` (myshopify subdomain) on each call. Approve host `{shop}.myshopify.com`. Default API version `2026-07` (`apiVersion` override). No platform Shopify OAuth integration. ## Import paths | Export | Import | | --- | --- | | package overview | `kody:@kody/shopify` | | graphql | `kody:@kody/shopify/graphql` | | request | `kody:@kody/shopify/request` | | shop | `kody:@kody/shopify/shop` | | products | `kody:@kody/shopify/products` | | orders | `kody:@kody/shopify/orders` | | customers | `kody:@kody/shopify/customers` | | inventory | `kody:@kody/shopify/inventory` | | collections | `kody:@kody/shopify/collections` | | fulfillments | `kody:@kody/shopify/fulfillments` | | draft-orders | `kody:@kody/shopify/draft-orders` | | webhooks | `kody:@kody/shopify/webhooks` | | metafields | `kody:@kody/shopify/metafields` | | config | `kody:@kody/shopify/config` | | smoke-test | `kody:@kody/shopify/smoke-test` | | types | `kody:@kody/shopify/types` | Prefer static `kody:@kody/shopify/...` imports from `execute`. Do not lead with `packages.invoke`. Default exports: `./graphql` → `graphql`; `./request` → `shopifyRequest`; `./shop` → `getShop`; `./products` → `listProducts`; `./orders` → `listOrders`; `./customers` → `listCustomers`; `./inventory` → `listLocations`; `./collections` → `listCollections`; `./fulfillments` → `listFulfillmentOrders`; `./draft-orders` → `listDraftOrders`; `./webhooks` → `listWebhooks`; `./metafields` → `listMetafields`; `./config` → `getConfig`; `./smoke-test` → `smokeTest`. ## Smoke test `./smoke-test` always runs local shop/id helper checks. When `shop` and credentials are present it also reads `shop { name }`. ```js import smokeTest from 'kody:@kody/shopify/smoke-test' export default async function main() { return await smokeTest({ shop: 'acme' }) } ``` ## Common snippets Read shop, products, unpaid orders: ```js import { getShop } from 'kody:@kody/shopify/shop' import { listProducts } from 'kody:@kody/shopify/products' import { listOrders } from 'kody:@kody/shopify/orders' export default async function main() { const shop = await getShop({ shop: 'acme' }) const products = await listProducts({ shop: 'acme', query: 'status:active', first: 10, }) const unpaid = await listOrders({ shop: 'acme', query: 'financial_status:pending', first: 10, }) return { shop, products, unpaid } } ``` Unwrapped GraphQL: ```js import { shopifyGraphql } from 'kody:@kody/shopify/graphql' export default async function main() { return await shopifyGraphql({ shop: 'acme', query: `query ($query: String) { products(first: 5, query: $query) { nodes { id title handle } } }`, variables: { query: 'vendor:acme' }, }) } ``` ## dryRun (writes) Writes default to **dry-run**. Pass `dryRun: false` only after the user confirms the exact shop and mutation. ```js import { createProduct } from 'kody:@kody/shopify/products' export default async function main() { const preview = await createProduct({ shop: 'acme', title: 'Hiking backpack', status: 'DRAFT', }) // => { dryRun: true, wouldCall: { mutation: 'productCreate', product: { ... } } } const created = await createProduct({ shop: 'acme', title: 'Hiking backpack', status: 'DRAFT', dryRun: false, }) return { preview, created } } ``` ## Edge cases / fork notes - GraphQL is the supported Admin surface. REST remains as `./request` for older resources still documented there. - Requests stay on `{shop}.myshopify.com/admin/…`. Arbitrary hosts are rejected. - Client-credentials tokens are requested per invoke and never written to `packageStorage()`. - Rate limits: GraphQL uses calculated query cost; REST is 40 req/min (higher on Shopify Plus). The client retries `429` / `5xx` and honors `Retry-After`. - Helpers project slim objects. Use `./graphql` when you need extra fields. - Numeric ids are accepted and normalized to `gid://shopify/{Type}/{id}`. - Fork first: do not treat live `@kody/shopify` `packageStorage()` as yours. - Never paste Shopify client secrets or Admin access tokens into chat or logs.