From deb97ebf0f60bea3038620546c4a6efb7ca7e881 Mon Sep 17 00:00:00 2001 From: Adam Barrus Date: Tue, 9 Jun 2026 11:40:50 -0700 Subject: [PATCH] Document supported Shopify resource intent types --- .github/pull_request_template.md | 6 +- CONTRIBUTING.md | 6 +- README.md | 46 ++++++++----- types/shopify-customer.md | 107 +++++++++++++++++++++++++++++++ types/shopify-order.md | 107 +++++++++++++++++++++++++++++++ types/shopify-product.md | 106 ++++++++++++++++++++++++++++++ 6 files changed, 358 insertions(+), 20 deletions(-) create mode 100644 types/shopify-customer.md create mode 100644 types/shopify-order.md create mode 100644 types/shopify-product.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b49fffd..48e0d4d 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -8,8 +8,8 @@ https://github.com/Shopify/app-intent-types/discussions/categories/rfc ## Proposed type -- **Type:** `application/...` -- **Actions:** `create` / `edit` / both +- **Type:** `application/...` or `shopify/...` +- **Actions:** `create` / `edit` / both, or `import` / `import+bulk` / both - **One-line summary:** ## Why this type @@ -38,6 +38,8 @@ Either a JSON Schema fenced below, or a link to a Gist / branch / external schem Confirmed: - [ ] `inputSchema` does not declare `required` fields - [ ] Field names are consistent with neighboring types in `types/` +- [ ] For `application/*`, the schema refs the canonical application schema +- [ ] For `shopify/*`, `value` and `outputSchema` use the matching Shopify resource GID schema ## Prior art diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index deb6b9b..ed60046 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,14 +10,14 @@ Thanks for proposing a Sidekick intent type. This doc describes the workflow. ## Opening a PR -A type-proposal PR adds **one file** under `types/`, named `application-{name}.md`. Use [`types/application-email.md`](./types/application-email.md) as the template. +A type-proposal PR adds **one file** under `types/`, named for the intent type. Use `application-{name}.md` for app-owned shapes or `shopify-{resource}.md` for Shopify resource intents. Use [`types/application-email.md`](./types/application-email.md) or [`types/shopify-product.md`](./types/shopify-product.md) as templates. The file should cover: -- **Type and actions** — what MIME type, which of `create` / `edit` you're registering for, and why. +- **Type and actions** — what MIME type, which supported actions you're registering for, and why. `application/*` types support `create` / `edit`; `shopify/*` resource types support `import` / `import+bulk`. - **When to register** — the merchant intents this type captures, with concrete examples. - **TOML example** — a real `shopify.extension.toml` block showing how an extension would register. -- **Schema** — either inline JSON Schema in a fenced block or a link to a Gist / branch. Must `$ref` the canonical schema URL once published. Must not declare `required` fields. +- **Schema** — either inline JSON Schema in a fenced block or a link to a Gist / branch. `application/*` intents must `$ref` the canonical application schema URL once published. `shopify/*` intents must use the published resource GID schema for `value` and `outputSchema`. Must not declare `required` fields. - **Field overview** — a short table orienting readers to the major fields. - **Common pitfalls** — anything that tripped you up while drafting. - **Related types** — pointers to existing types this could be confused with, and why yours is distinct. diff --git a/README.md b/README.md index 4b3bc6d..754ec2e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Sidekick app extensions intent types -Public catalog and proposal venue for **Sidekick app intent types** — the MIME-typed schemas that Shopify apps register to declare "I can create or edit a thing of this shape." +Public catalog and proposal venue for **Sidekick app intent types** — the MIME-typed schemas that Shopify apps register to declare "I can create, edit, or import a thing of this shape." If you're building a Shopify app and the type you need to register an intent for doesn't exist yet, **this is the place to ask for it.** @@ -8,23 +8,39 @@ If you're building a Shopify app and the type you need to register an intent for ## What's here -- **[`types/`](./types/)** — every intent type Shopify currently supports, one file per type, with the JSON Schema URL, the actions it supports (`create`, `edit`), and example use cases. +- **[`types/`](./types/)** — every intent type Shopify currently supports, one file per type, with the JSON Schema URL, supported actions, and example use cases. - **[Discussions](../../discussions)** — open conversations about intent design, early-stage proposals, and questions. Use this before a formal PR. - **Pull requests** — formal proposals for new types, additions to existing types, and refinements. See [How to propose a new type](#how-to-propose-a-new-type) below. ## Currently supported types -| Type | Actions | Schema | -|---|---|---| -| `application/ad` | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/ad.json) | -| `application/campaign` | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/campaign.json) | -| `application/email` | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/email.json) | -| `application/faq` | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/faq.json) | -| `application/loyalty-program` | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/loyalty-program.json) | -| `application/return` | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/return.json) | -| `application/review` | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/review.json) | -| `application/shipment` | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/shipment.json) | -| `application/ticket` | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/ticket.json) | +This list mirrors the supported types documented in [Build an app action](https://shopify.dev/docs/apps/build/sidekick/build-app-actions). + +### `application/*` intents + +Use `application/*` intents when your app owns the data shape. Each type supports both `create` and `edit` actions. + +| Type | Description | Actions | Schema | +|---|---|---|---| +| [`application/ad`](./types/application-ad.md) | Ad campaigns | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/ad.json) | +| [`application/campaign`](./types/application-campaign.md) | Marketing campaigns | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/campaign.json) | +| [`application/email`](./types/application-email.md) | Email campaigns | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/email.json) | +| [`application/faq`](./types/application-faq.md) | FAQ management | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/faq.json) | +| [`application/loyalty-program`](./types/application-loyalty-program.md) | Loyalty programs | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/loyalty-program.json) | +| [`application/return`](./types/application-return.md) | Returns management | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/return.json) | +| [`application/review`](./types/application-review.md) | Product reviews | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/review.json) | +| [`application/shipment`](./types/application-shipment.md) | Shipment tracking | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/shipment.json) | +| [`application/ticket`](./types/application-ticket.md) | Support tickets | `create`, `edit` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/application/ticket.json) | + +### `shopify/*` resource intents + +Use `shopify/*` intents when your app operates on a Shopify resource identified by a GID. Each type supports both `import` and `import+bulk` actions. + +| Type | Description | Actions | GID schema | +|---|---|---|---| +| [`shopify/customer`](./types/shopify-customer.md) | Shopify customers | `import`, `import+bulk` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/customer/gid.json) | +| [`shopify/order`](./types/shopify-order.md) | Shopify orders | `import`, `import+bulk` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/order/gid.json) | +| [`shopify/product`](./types/shopify-product.md) | Shopify products | `import`, `import+bulk` | [schema](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/product/gid.json) | ## How to propose a new type @@ -47,8 +63,8 @@ Once the shape is settled (either through discussion or because the type is obvi A type proposal PR should include: -- A new file `types/application-{name}.md` describing the type, actions, schema, and example use cases. -- A draft JSON Schema (inline in the PR or linked from a Gist) that conforms to the [Sidekick schema requirements](https://shopify.dev/docs/apps/build/sidekick/build-app-actions#step-2-create-an-input-schema). Critically, **`inputSchema` must not declare `required` fields** — Sidekick fills missing fields via UI before invoking your extension. +- A new file under `types/` describing the type, actions, schema, and example use cases. Use `application-{name}.md` for app-owned shapes and `shopify-{resource}.md` for Shopify resource intents. +- A draft JSON Schema (inline in the PR or linked from a Gist) that conforms to the [Sidekick schema requirements](https://shopify.dev/docs/apps/build/sidekick/build-app-actions). Critically, **`inputSchema` must not declare `required` fields** — Sidekick fills missing fields via UI before invoking your extension. - A short rationale: who's asking for this, what problem it unblocks, and any prior art. We'll review and either merge, request changes, or move it back to a discussion if more shaping is needed. diff --git a/types/shopify-customer.md b/types/shopify-customer.md new file mode 100644 index 0000000..ee35b9f --- /dev/null +++ b/types/shopify-customer.md @@ -0,0 +1,107 @@ +# `shopify/customer` + +Sidekick intent type for importing one or more **Shopify customers** into an app-provided workflow and returning Shopify Customer GIDs. + +- **Status:** ✅ Supported +- **Actions:** `import`, `import+bulk` +- **GID schema:** [`https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/customer/gid.json`](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/customer/gid.json) + +## When to register an intent for this type + +Register a `shopify/customer` intent when your app operates on an existing Shopify Customer identified by a GID and produces a Shopify Customer result. + +Typical examples: +- A **CRM app** registering `import` so a merchant can import a Shopify customer into a customer-enrichment workflow. +- A **loyalty app** registering `import` so a merchant can apply loyalty-specific state to a Shopify customer and return the updated customer reference. +- A **segmentation app** registering `import+bulk` so a merchant can process a set of Shopify customers in a bulk workflow. + +Use `shopify/customer` when the source and output are Shopify Customer resources. If your app owns the artifact shape instead, use an `application/*` type. + +## Example: register the intent + +In your extension's `shopify.extension.toml`: + +```toml +api_version = "2026-04" + +[[extensions]] +name = "Import customer" +description = "Take an existing Shopify customer and import them into an app workflow" +handle = "import-customer" +type = "admin_link" + + [[extensions.targeting]] + target = "admin.app.intent.link" + url = "/customers/{id}/import" + tools = "./tools.json" + instructions = "./instructions.md" + + [[extensions.targeting.intents]] + type = "shopify/customer" + action = "import" + schema = "./customer-import-schema.json" +``` + +Three things to notice: + +1. **`type`** is the Shopify resource type from this catalog. Required. +2. **`action`** is `import` for one resource or `import+bulk` for many resources. Required. +3. **`schema`** points to a local JSON Schema file. Required. Use `shopify-intent.json` for `import` and `shopify-intent-bulk.json` for `import+bulk`. + +## Example: the import schema + +`./customer-import-schema.json`: + +```json +{ + "$schema": "https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify-intent.json", + "value": { + "$ref": "https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/customer/gid.json", + "mapTo": "param", + "fieldName": "id" + }, + "inputSchema": { + "type": "object", + "properties": { + "instructions": { + "type": "string", + "description": "Merchant-provided instructions for the customer workflow." + } + } + }, + "outputSchema": { + "type": "object", + "properties": { + "id": { + "$ref": "https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/customer/gid.json" + } + } + } +} +``` + +## Fields the schema describes + +A Shopify resource intent schema has a fixed shape: + +| Field | Type | Notes | +|---|---|---| +| `value` | Shopify Customer GID | Source customer passed to the app. Uses the `shopify/customer` GID schema. | +| `inputSchema` | object | App-specific input fields. Do not declare `required` fields. | +| `outputSchema.properties.id` | Shopify Customer GID | Result customer returned by `shopify.intents.response.ok`. | + +For `import+bulk`, `value` is an array of Customer GIDs and the output should return an array under `outputSchema.properties.ids`. + +## Common pitfalls + +- **Using `create` or `edit` with `shopify/customer`.** Those verbs are reserved for Shopify-native Admin intents. Third-party app extensions use `import` or `import+bulk`. +- **Using the wrong meta-schema.** `import` requires `shopify-intent.json`; `import+bulk` requires `shopify-intent-bulk.json`. +- **Pointing at an application schema.** `value.$ref` must point to the Customer GID schema, not an `application/*` schema. +- **Treating the URL `{id}` as a full GID.** When mapped as a `param`, Sidekick passes the bare tail ID into the URL path. Read the full GID from the intent payload if you need it. + +## Related types + +- **[`shopify/product`](./shopify-product.md)** — for importing Shopify Product resources. +- **[`shopify/order`](./shopify-order.md)** — for importing Shopify Order resources. +- **[`application/loyalty-program`](./application-loyalty-program.md)** — for app-owned loyalty program artifacts. +- **[`application/ticket`](./application-ticket.md)** — for app-owned support ticket workflows. diff --git a/types/shopify-order.md b/types/shopify-order.md new file mode 100644 index 0000000..b9cbdd5 --- /dev/null +++ b/types/shopify-order.md @@ -0,0 +1,107 @@ +# `shopify/order` + +Sidekick intent type for importing one or more **Shopify orders** into an app-provided workflow and returning Shopify Order GIDs. + +- **Status:** ✅ Supported +- **Actions:** `import`, `import+bulk` +- **GID schema:** [`https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/order/gid.json`](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/order/gid.json) + +## When to register an intent for this type + +Register a `shopify/order` intent when your app operates on an existing Shopify Order identified by a GID and produces a Shopify Order result. + +Typical examples: +- A **fulfillment app** registering `import` so a merchant can import an order into an app-specific fulfillment workflow. +- A **returns or support app** registering `import` so a merchant can start from a Shopify order and continue in the app's order workflow. +- An **operations app** registering `import+bulk` so a merchant can process multiple orders at once. + +Use `shopify/order` when the source and output are Shopify Order resources. If your app owns the artifact shape instead, use an `application/*` type. + +## Example: register the intent + +In your extension's `shopify.extension.toml`: + +```toml +api_version = "2026-04" + +[[extensions]] +name = "Import order" +description = "Take an existing Shopify order and import it into an app workflow" +handle = "import-order" +type = "admin_link" + + [[extensions.targeting]] + target = "admin.app.intent.link" + url = "/orders/{id}/import" + tools = "./tools.json" + instructions = "./instructions.md" + + [[extensions.targeting.intents]] + type = "shopify/order" + action = "import" + schema = "./order-import-schema.json" +``` + +Three things to notice: + +1. **`type`** is the Shopify resource type from this catalog. Required. +2. **`action`** is `import` for one resource or `import+bulk` for many resources. Required. +3. **`schema`** points to a local JSON Schema file. Required. Use `shopify-intent.json` for `import` and `shopify-intent-bulk.json` for `import+bulk`. + +## Example: the import schema + +`./order-import-schema.json`: + +```json +{ + "$schema": "https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify-intent.json", + "value": { + "$ref": "https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/order/gid.json", + "mapTo": "param", + "fieldName": "id" + }, + "inputSchema": { + "type": "object", + "properties": { + "instructions": { + "type": "string", + "description": "Merchant-provided instructions for the order workflow." + } + } + }, + "outputSchema": { + "type": "object", + "properties": { + "id": { + "$ref": "https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/order/gid.json" + } + } + } +} +``` + +## Fields the schema describes + +A Shopify resource intent schema has a fixed shape: + +| Field | Type | Notes | +|---|---|---| +| `value` | Shopify Order GID | Source order passed to the app. Uses the `shopify/order` GID schema. | +| `inputSchema` | object | App-specific input fields. Do not declare `required` fields. | +| `outputSchema.properties.id` | Shopify Order GID | Result order returned by `shopify.intents.response.ok`. | + +For `import+bulk`, `value` is an array of Order GIDs and the output should return an array under `outputSchema.properties.ids`. + +## Common pitfalls + +- **Using `create` or `edit` with `shopify/order`.** Those verbs are reserved for Shopify-native Admin intents. Third-party app extensions use `import` or `import+bulk`. +- **Using the wrong meta-schema.** `import` requires `shopify-intent.json`; `import+bulk` requires `shopify-intent-bulk.json`. +- **Pointing at an application schema.** `value.$ref` must point to the Order GID schema, not an `application/*` schema. +- **Treating the URL `{id}` as a full GID.** When mapped as a `param`, Sidekick passes the bare tail ID into the URL path. Read the full GID from the intent payload if you need it. + +## Related types + +- **[`shopify/customer`](./shopify-customer.md)** — for importing Shopify Customer resources. +- **[`shopify/product`](./shopify-product.md)** — for importing Shopify Product resources. +- **[`application/return`](./application-return.md)** — for app-owned return workflows. +- **[`application/shipment`](./application-shipment.md)** — for app-owned shipment workflows. diff --git a/types/shopify-product.md b/types/shopify-product.md new file mode 100644 index 0000000..2e241bf --- /dev/null +++ b/types/shopify-product.md @@ -0,0 +1,106 @@ +# `shopify/product` + +Sidekick intent type for importing one or more **Shopify products** into an app-provided workflow and returning Shopify Product GIDs. + +- **Status:** ✅ Supported +- **Actions:** `import`, `import+bulk` +- **GID schema:** [`https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/product/gid.json`](https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/product/gid.json) + +## When to register an intent for this type + +Register a `shopify/product` intent when your app operates on an existing Shopify Product identified by a GID and produces a Shopify Product result. + +Typical examples: +- A **print-on-demand app** registering `import` so a merchant can start from a blank base product and create a custom-printed variant. +- A **product merchandising app** registering `import+bulk` so a merchant can import several products into a bulk optimization workflow. +- A **product enrichment app** registering `import` so a merchant can enhance a product with app-specific content, data, or assets before returning the resulting Shopify Product. + +Use `shopify/product` when the source and output are Shopify Product resources. If your app owns the artifact shape instead, use an `application/*` type. + +## Example: register the intent + +In your extension's `shopify.extension.toml`: + +```toml +api_version = "2026-04" + +[[extensions]] +name = "Customize product" +description = "Take an existing Shopify product and create a customized product result" +handle = "customize-product" +type = "admin_link" + + [[extensions.targeting]] + target = "admin.app.intent.link" + url = "/customize/{id}" + tools = "./tools.json" + instructions = "./instructions.md" + + [[extensions.targeting.intents]] + type = "shopify/product" + action = "import" + schema = "./product-import-schema.json" +``` + +Three things to notice: + +1. **`type`** is the Shopify resource type from this catalog. Required. +2. **`action`** is `import` for one resource or `import+bulk` for many resources. Required. +3. **`schema`** points to a local JSON Schema file. Required. Use `shopify-intent.json` for `import` and `shopify-intent-bulk.json` for `import+bulk`. + +## Example: the import schema + +`./product-import-schema.json`: + +```json +{ + "$schema": "https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify-intent.json", + "value": { + "$ref": "https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/product/gid.json", + "mapTo": "param", + "fieldName": "id" + }, + "inputSchema": { + "type": "object", + "properties": { + "instructions": { + "type": "string", + "description": "Merchant-provided customization instructions." + } + } + }, + "outputSchema": { + "type": "object", + "properties": { + "id": { + "$ref": "https://extensions.shopifycdn.com/shopifycloud/schemas/v1/shopify/product/gid.json" + } + } + } +} +``` + +## Fields the schema describes + +A Shopify resource intent schema has a fixed shape: + +| Field | Type | Notes | +|---|---|---| +| `value` | Shopify Product GID | Source product passed to the app. Uses the `shopify/product` GID schema. | +| `inputSchema` | object | App-specific input fields. Do not declare `required` fields. | +| `outputSchema.properties.id` | Shopify Product GID | Result product returned by `shopify.intents.response.ok`. | + +For `import+bulk`, `value` is an array of Product GIDs and the output should return an array under `outputSchema.properties.ids`. + +## Common pitfalls + +- **Using `create` or `edit` with `shopify/product`.** Those verbs are reserved for Shopify-native Admin intents. Third-party app extensions use `import` or `import+bulk`. +- **Using the wrong meta-schema.** `import` requires `shopify-intent.json`; `import+bulk` requires `shopify-intent-bulk.json`. +- **Pointing at an application schema.** `value.$ref` must point to the Product GID schema, not an `application/*` schema. +- **Treating the URL `{id}` as a full GID.** When mapped as a `param`, Sidekick passes the bare tail ID into the URL path. Read the full GID from the intent payload if you need it. + +## Related types + +- **[`shopify/customer`](./shopify-customer.md)** — for importing Shopify Customer resources. +- **[`shopify/order`](./shopify-order.md)** — for importing Shopify Order resources. +- **[`application/campaign`](./application-campaign.md)** — for app-owned marketing campaign artifacts.