Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/shopify

README.md

223 lines · 8.2 KB · Markdown

@kody/shopify

Intent

Give agents a fork-ready Shopify Admin API toolkit — GraphQL-first shop, product, order, customer, inventory, collection, fulfillment, draft-order, webhook, and metafield helpers — without a Kody Shopify OAuth integration. Transport is one compact authenticated client against https://{shop}.myshopify.com/admin. Use ./graphql or ./request for any unwrapped Admin path.

This listing is meant to be forked. The live @kody/shopify package does not talk to a shared store. After you fork, save your own shop credentials and call the helpers in your account.

When To Use

  • Read a shop profile, catalog, orders, or customers from Admin GraphQL
  • Preview or apply catalog, inventory, fulfillment, draft-order, webhook, or metafield writes (dryRun defaults on)
  • Call an unwrapped Admin GraphQL operation or legacy REST resource
  • Start a private Shopify workflow by forking this package instead of scaffolding from zero

Do not use this package to invent a platform Shopify OAuth app. Auth is secret-backed on purpose.

Required setup

You need a shop handle plus one credential lane. There is no saved Kody shopify integration.

1. Shop handle

Pass shop: "your-store" (the *.myshopify.com subdomain) on each call. After you fork, you can persist a default with ./config.

Approve outbound host {your-store}.myshopify.com in the account secrets UI. Admin API traffic is shop-hosted; there is no single shared API hostname.

2a. Preferred — Dev Dashboard client credentials

Shopify's current custom-app path issues a Client ID and Client secret. You exchange those for a 24-hour Admin access token. This package does that per invoke and never stores the access token.

  1. Create and install a Dev Dashboard app on your shop. Docs: https://shopify.dev/docs/apps/build/dev-dashboard/create-apps-using-dev-dashboard
  2. Copy Client ID and Client secret from Settings.
  3. Save them as user secrets (do not paste values into chat):

Then approve host {your-store}.myshopify.com on those secrets.

Token exchange docs: https://shopify.dev/docs/apps/build/dev-dashboard/get-api-access-tokens

2b. Legacy — Admin API access token

Some older custom apps still show a static Admin API access token (shpat_…). Save that as shopifyAdminAccessToken. If this secret exists, it wins over client credentials.

Access scopes

Grant only what you will call. Typical starting set:

  • read_products / write_products
  • read_orders / write_orders (protected customer data may need extra Shopify approval)
  • read_customers / write_customers
  • read_inventory / write_inventory
  • read_locations
  • read_fulfillments / write_fulfillments
  • read_draft_orders / write_draft_orders
  • read_content or the webhook topics you subscribe to

Default API version is 2026-07. Override per call with apiVersion or store a fork-local default.

Exports

ExportDescription
.Package overview and domain map
./graphqlshopifyGraphql — Admin GraphQL escape hatch
./requestshopifyRequest — Admin REST escape hatch
./shopgetShop
./productslistProducts, getProduct, createProduct, updateProduct
./orderslistOrders, getOrder
./customerslistCustomers, getCustomer, createCustomer
./inventorylistLocations, listInventoryLevels, adjustInventory
./collectionslistCollections, getCollection
./fulfillmentslistFulfillmentOrders, createFulfillment
./draft-orderslistDraftOrders, getDraftOrder, createDraftOrder
./webhookslistWebhooks, createWebhook, deleteWebhook
./metafieldslistMetafields, setMetafield
./configgetConfig, setDefaultShop, setDefaultApiVersion, clearConfig
./smoke-testLocal helper checks plus optional live shop read
./typesShared TypeScript types

Default exports: ./graphqlgraphql; ./requestshopifyRequest; ./shopgetShop; ./productslistProducts; ./orderslistOrders; ./customerslistCustomers; ./inventorylistLocations; ./collectionslistCollections; ./fulfillmentslistFulfillmentOrders; ./draft-orderslistDraftOrders; ./webhookslistWebhooks; ./metafieldslistMetafields; ./configgetConfig; ./smoke-testsmokeTest.

Writes default to dry-run. Pass dryRun: false only after the user confirms the exact shop and mutation.

Example

import { getShop } from 'kody:@kody/shopify/shop'
import { listProducts } from 'kody:@kody/shopify/products'
import { listOrders } from 'kody:@kody/shopify/orders'

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,
})

Unwrapped GraphQL:

import { shopifyGraphql } from 'kody:@kody/shopify/graphql'

const data = await shopifyGraphql({
	shop: 'acme',
	query: `query ($query: String) {
		products(first: 5, query: $query) {
			nodes { id title handle }
		}
	}`,
	variables: { query: 'vendor:acme' },
})

Preview a write, then apply only after confirmation:

import { createProduct } from 'kody:@kody/shopify/products'

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,
})

Forking

Community listings are snapshots. Fork this listing into your account, review the source, publish your copy, then save secrets. Do not treat the live @kody/shopify packageStorage() as yours — platform packages share the Kody-scope bucket.

See CONTRIBUTING.md for the clone-edit-publish loop and how to add another domain module.

One-click listing URL after publish: https://kody.codes/@kody/shopify

Smoke test

./smoke-test always runs local shop/id helper checks. When shop and credentials are present it also reads shop { name }.

import smokeTest from 'kody:@kody/shopify/smoke-test'

export default async function main() {
	return await smokeTest({ shop: 'acme' })
}

Notes

  • GraphQL is the supported Admin surface. REST remains as ./request because some older resources are 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}.
  • This package is not affiliated with or endorsed by Shopify Inc.

Branding

The community icon is The Shopping Bag, Shopify's official brandmark, taken from the public brand-assets kit (shopify-shopping-bag.zipshopify_glyph.svg). Paths are unmodified. Shopify® and The Shopping Bag are trademarks of Shopify Inc.

Docs