Gentic Shopify — Documentation
Connect any AI agent to a Shopify store for orders, products, customers, and bulk revenue exports — all through the Model Context Protocol. Read-only by design: list and inspect data, export CSVs for joins against your ad spend, and run free-form Admin GraphQL when the typed tools don't cover what you need.
1. Getting Started
Sign Up & Get Your API Key
Before you can use Gentic Shopify, you need an API key to authenticate your requests.
- Go to gentic.co/shopify and create an account.
- Create an organization from your dashboard. API keys and billing are scoped to the organization.
- Generate an API key and use it as a Bearer token in your MCP client.
2. Connecting to the MCP Server
The server is available at https://mcp.gentic.co/shopify. For Claude Code:
claude mcp add gentic-shopify \
--transport http \
https://mcp.gentic.co/shopify \
--header "Authorization: Bearer YOUR_API_KEY"For Claude Web and ChatGPT you can also connect via OAuth — no API key needed. See the connect section on the landing page for other MCP clients (n8n, OpenClaw).
3. Agent Skill
For the best results, pair the MCP server with the Gentic Shopify agent skill. The MCP server gives your agent tool access; the skill teaches it the optimal workflow order. Both the raw SKILL.md and a ready-to-upload .skill bundle are generated on demand from the live manifest, so they always reflect the current tools and pricing.
Add the skill directly via URL:
https://gentic.co/shopify/SKILL.mdOr upload a .skill bundle to Claude Managed Agents:
https://gentic.co/shopify/gentic-shopify.skillDownload this file and upload it wherever Claude Managed Agents asks for a .skill file. It's a zip bundle generated on demand from the latest SKILL.md.
4. When to Apply
- User wants to inspect or analyze Shopify orders, products, or customers in plain English.
- User wants to compute ROAS, attributed revenue, or CAC by joining Shopify orders against ad spend from Meta or Google Ads.
- User wants a CSV export of orders filtered by date, financial status, or channel (source_name).
- User wants the top customers by lifetime value, or to investigate a specific customer's order history.
- User wants to look up a single order, product, or customer by ID, GID, or product handle.
- User wants to run an arbitrary Admin GraphQL query against the Shopify store (read-only).
- User wants to know which Shopify store is connected, or check the store's currency, timezone, or plan.
5. Workflow
1. Check connection with `shopify_connection_status`
Free call — returns whether the org has connected a Shopify store, plus the `shop_domain` and `updated_at` timestamp when connected. If not connected, direct the user to the Gentic dashboard → Integrations → Shopify to paste a shop subdomain and Admin API access token. At least one of `read_orders` / `read_products` / `read_customers` must be granted on the token; individual tools that need a specific scope will surface their own error at call time if it's missing.
2. Grab store basics with `get_shop_info`
Free call — returns name, email, primary domain, currency, IANA timezone, weight unit, and plan. Worth calling once per session: the currency drives how you format revenue numbers, and the timezone matters for any date-bucketed analysis (`processed_at` comes back in store-local time).
3. List orders with `list_orders` (5¢/call)
Cursor-paginated. Sort defaults to `processed_at` descending — the right key for revenue attribution, since `processed_at` is when the order was actually placed (`created_at` can include draft-order timestamps that lag). Filter by date range (`processed_at_min`/`max` for ROAS, `created_at_min`/`max` for funnel analysis), `financial_status`, `fulfillment_status`, and `source_name` (the channel — workhorse for ROAS attribution). Watch for `line_items_truncated: true` on orders with >50 line items — follow up with `get_order` for the full breakdown.
4. Drill into a single record (free)
`get_order`, `get_product`, and `get_customer` are all free. `get_order` returns full line items (up to 250), refunds, fulfillments + tracking, addresses, and customer summary. `get_product` accepts either `id` or `handle` and returns up to 20 images + 100 variants with prices, SKUs, and inventory quantities — set `include_html: true` to also pull `descriptionHtml`. `get_customer` returns the customer profile plus the 10 most recent orders inline (handy for LTV / churn / cohort analysis without a second roundtrip).
5. List products with `list_products` (5¢/call)
Most recently updated first. Filter by `status` (ACTIVE / ARCHIVED / DRAFT), `vendor`, `product_type`, and `title` (substring match). Returns summary fields including price range and total inventory. For variants, SKUs, and full descriptions, follow up with `get_product`. Use `extra_query` for any Shopify search syntax the typed filters don't cover.
6. List customers with `list_customers` (5¢/call)
Sorts by `total_spent` descending by default — top customers first, the right order for LTV analysis. Filter by `email` (exact), `tag` (exact), `total_spent_min`/`max`, `orders_count_min`, `created_at_min`/`max`. `extra_query` is the escape hatch for free-form Shopify search. Paginate via `next_cursor` — `resultCount` reflects the page only, not the total.
7. Export revenue for joins with `export_orders_report` ($1/call)
The ROAS workhorse. Returns a CSV download URL that expires in **1 hour** AND persists the rows to MotherDuck `shopify_orders` with a schema that matches the row layout exactly. Pre-computes `net_revenue` (= `current_total_price` − `total_refunded`) and `processed_date` (DATE part of `processed_at`) so the join against `meta_ad_insights` is a single equality predicate, not a CASE-laden CTE. Filter by `processed_at_min`/`max` (preferred for ROAS attribution), `created_at_min`/`max`, `financial_status`, `source_name`, or `extra_query`. Caps at 10,000 orders per call — narrow the date window if you hit it. Tell the user the 1-hour expiry up front.
8. Use `shopify_graphql_query` as an escape hatch (10¢/call)
When the typed tools don't cover a specific field, drop into raw Admin GraphQL (API version `2026-04`). Mutations and subscriptions are rejected server-side — Gentic's Shopify surface is analytics-only and won't modify the store. Returns the raw GraphQL response plus rate-limit cost info. Prefer the typed tools when they exist: they paginate, normalize money fields, and surface consistent error messages.
9. Present results clearly
For orders: lead with the headline (period revenue, order count, AOV), show a ranked table by the metric the user cares about, and call out outliers (huge orders, refunds, unusual channels). For customers: surface lifetime value, order count, and the most recent order date prominently. For exports: show the download URL **and the 1-hour expiry** clearly so the user doesn't lose access to the file. For ROAS workflows: after running `export_orders_report`, hand the analysis to the Data MCP server to join `shopify_orders.processed_date` against `meta_ad_insights.date` and compute ROAS = `net_revenue / spend`.
6. Tool Reference
10 tools, rendered live from the Gentic MCP manifest. Parameter tables come directly from each tool's JSON Schema.
export_orders_report
Export Shopify orders to a CSV (1-hour signed URL) AND persist to MotherDuck `shopify_orders` for SQL-level joins with `meta_ad_insights`. Filters: `processed_at_min`/`max` (preferred for ROAS attribution), `created_at_min`/`max`, `financial_status`, `source_name`, `extra_query`. Paginates up to 10000 orders per call — narrow the date window if you hit the cap. The row schema matches `SHOPIFY_ORDERS_SCHEMA` exactly so the CSV and the warehouse table stay aligned. Pre-computes `net_revenue` (= `current_total_price` − `total_refunded`) and `processed_date` (DATE part of `processed_at`) so the join query against `meta_ad_insights` is a single equality predicate. $1.00 per call.
| Parameter | Type | Description |
|---|---|---|
processed_at_min | string | ISO-8601 lower bound on `processed_at`. Strongly recommended for ROAS analytics — `processed_at` is when payment actually happened, which matches how ad-spend dates work. |
processed_at_max | string | — |
created_at_min | string | ISO-8601 lower bound on `created_at`. Use when the analysis tracks order initiation including drafts. |
created_at_max | string | — |
financial_status | string | Filter to a financial status (e.g. 'paid'). Common practice for ROAS analysis is `paid` only. |
source_name | string | Filter by Shopify channel/source name. |
extra_query | string | Optional raw Shopify search-syntax clauses appended to the compiled query (parens-wrapped when combined with typed filters). |
get_customer
Fetch a single Shopify customer by ID. Accepts a numeric ID or full GID like 'gid://shopify/Customer/123456789'. Returns the customer profile plus the 10 most recent orders inline (useful for LTV / churn / cohort analysis without a second roundtrip). Free.
| Parameter | Type | Description |
|---|---|---|
idrequired | string | Customer ID. Either a numeric string ('1234567890') or full GID ('gid://shopify/Customer/1234567890'). |
get_order
Fetch a single Shopify order by ID. Accepts either a numeric ID (from a Shopify admin URL) or a full GID like 'gid://shopify/Order/123456789'. Returns the full order detail including all line items (up to 250), refunds, fulfillments + tracking, addresses, and customer summary. Free.
| Parameter | Type | Description |
|---|---|---|
idrequired | string | Order ID. Either a numeric string ('1234567890') or a full GID ('gid://shopify/Order/1234567890'). |
get_product
Fetch a single Shopify product by ID or handle. Provide exactly one of `id` (numeric or full GID) or `handle` (the url-safe slug). Returns full product detail including up to 20 images and 100 variants with prices, SKUs, and inventory quantities. By default the response carries the plain-text `description` only — set `include_html: true` to also pull `descriptionHtml` (roughly doubles the token cost on products with long marketing copy). Free.
| Parameter | Type | Description |
|---|---|---|
id | string | Product ID — numeric string ('1234567890') or full GID ('gid://shopify/Product/1234567890'). Mutually exclusive with `handle`. |
handle | string | Product handle (url slug, e.g. 'cool-tshirt'). Mutually exclusive with `id`. |
include_html | boolean | Include `descriptionHtml` (the rich-text form) in the response. Defaults to false. |
get_shop_info
Get basic information about the connected Shopify store: name, email, primary domain, currency, IANA timezone, weight unit, and plan. Free. Useful as a connection sanity check and to discover the currency/timezone needed for downstream order/revenue analysis.
This tool takes no parameters.
list_customers
List Shopify customers. Cursor-paginated. Typed filters: `email` (exact match), `tag` (exact tag match), `total_spent_min`/`max`, `orders_count_min`, `created_at_min`/`max`. Free-form Shopify search via `extra_query` (auto-wrapped in parens when combined with typed filters). Sort by `total_spent` (default, descending — top customers first, ideal for LTV analysis), `created_at`, `updated_at`, or `name`. $0.05 per call. `resultCount` reflects the page size only — paginate via `next_cursor`.
| Parameter | Type | Description |
|---|---|---|
email | string | Exact-match email filter (Shopify also supports wildcards like 'foo@*.com' via `extra_query`). |
tag | string | Exact-match customer tag filter. |
total_spent_min | number | Lower bound on lifetime total_spent (in shop currency). Use to filter to whale / VIP cohorts. min 0 |
total_spent_max | number | Upper bound on lifetime total_spent. min 0 |
orders_count_min | integer | Lower bound on lifetime order count. Use to filter to repeat-buyer cohorts. 0 – 9007199254740991 |
created_at_min | string | ISO-8601 lower bound on customer `created_at` (signup date). Use for cohort analysis. |
created_at_max | string | — |
extra_query | string | Optional raw Shopify customer search-syntax clauses appended to the compiled query. Examples: 'email:*@gmail.com', 'last_order_id:>0'. Auto-wrapped in parens when combined with typed filters. |
sort_by | string | Sort key. Defaults to 'total_spent' (descending) — most valuable customers first. enum: total_spent, created_at, updated_at, name |
reverse | boolean | Reverse the sort direction. Default true when sorting by spend or recency (descending); false for name (alphabetical). |
limitrequired | integer | Max results per page (1–250). Default 50. Shopify caps this at 250 even if a higher value is requested. 1 – 250 · default: 50 |
cursor | string | Opaque cursor from a prior call's `next_cursor`. Omit to start at the beginning. |
list_orders
List Shopify orders. Cursor-paginated. Filter by date range (`created_at_min/max`, `processed_at_min/max`, `updated_at_min/max`), `financial_status`, `fulfillment_status`, and `source_name` (channel — workhorse for ROAS attribution). Sort defaults to `processed_at` descending — that's the right key for revenue attribution because `processed_at` reflects when the order was actually placed; `created_at` can include the draft-order timestamp which lags. Returns flattened orders with shopMoney totals for analytics consistency. Each order carries `line_items_truncated: true` when more than 50 line items exist on it — follow up with `get_order` (250-item cap) for the full breakdown. $0.05 per call. `resultCount` reflects the page size only — paginate via `next_cursor`. For very large pull-downs (>1k orders) prefer `export_orders_report` (shipping in PR 3) which bulk-exports to CSV + MotherDuck.
| Parameter | Type | Description |
|---|---|---|
created_at_min | string | ISO-8601 lower bound on `created_at`, inclusive. Use this when the agent's clock tracks when orders were started (drafts included). |
created_at_max | string | ISO-8601 upper bound on `created_at`, inclusive. |
processed_at_min | string | ISO-8601 lower bound on `processed_at`, inclusive. Prefer this for ROAS / revenue-attribution polling — `processed_at` is when payment actually happened. |
processed_at_max | string | ISO-8601 upper bound on `processed_at`, inclusive. |
updated_at_min | string | ISO-8601 lower bound on `updated_at`. Use for change-data-capture flows that need to catch refunds and edits. |
updated_at_max | string | — |
financial_status | string | Filter by Shopify financial status. Common values: 'paid', 'pending', 'authorized', 'partially_paid', 'refunded', 'partially_refunded', 'voided'. |
fulfillment_status | string | Filter by fulfillment status. Common values: 'fulfilled', 'unfulfilled', 'partial', 'restocked'. |
source_name | string | Filter by Shopify channel/source name (e.g. 'web', 'pos', 'shopify_draft_order', or a specific connected-app source name). |
extra_query | string | Optional raw Shopify search-syntax clauses appended to the compiled query. Auto-wrapped in parens when combined with typed filters so OR clauses scope correctly. See https://shopify.dev/docs/api/usage/search-syntax. |
sort_by | string | Sort key. Defaults to 'processed_at' (descending) which matches revenue-attribution expectations. Set 'created_at' if the polling pattern tracks order-start timestamps including drafts. enum: processed_at, created_at, updated_at |
reverse | boolean | Reverse the sort order. Defaults to `true` (descending — newest first). |
limitrequired | integer | Max results per page (1–250). Default 50. Shopify caps this at 250 even if a higher value is requested. 1 – 250 · default: 50 |
cursor | string | Opaque cursor from a prior call's `next_cursor`. Omit to start at the beginning. |
list_products
List Shopify products, most recently updated first. Cursor-paginated. Filter by `status` (ACTIVE / ARCHIVED / DRAFT), `vendor`, `product_type`, and `title` (substring match). Free-form Shopify search via `extra_query` (auto-wrapped in parens when combined with typed filters). Returns summary fields including price range and total inventory — for variants and full descriptions, follow up with `get_product`. $0.05 per call. `resultCount` reflects the page size only — paginate via `next_cursor`.
| Parameter | Type | Description |
|---|---|---|
status | string | Product status filter. enum: ACTIVE, ARCHIVED, DRAFT |
vendor | string | Vendor name filter (exact match). |
product_type | string | Product type filter (exact match). |
title | string | Substring match on product title. |
extra_query | string | Optional raw Shopify search-syntax clauses appended to the compiled query. Auto-wrapped in parens when combined with typed filters so OR clauses scope correctly. |
limitrequired | integer | Max results per page (1–250). Default 50. Shopify caps this at 250 even if a higher value is requested. 1 – 250 · default: 50 |
cursor | string | Opaque cursor from a prior call's `next_cursor`. Omit to start at the beginning. |
shopify_connection_status
Check whether the calling organization has connected a Shopify store. Returns `{ connected, shop_domain, updated_at }` when connected, or `{ connected: false }` otherwise. Free. Call this before any other Shopify tool to give the user actionable guidance when the integration is missing.
This tool takes no parameters.
shopify_graphql_query
Execute a read-only GraphQL query against the Shopify Admin API (version 2026-04). Use this as an escape hatch when the typed Shopify tools don't cover what you need. Mutations and subscriptions are rejected — Gentic's v1 Shopify surface is analytics-only and will not modify the store. Prefer the typed tools (list_orders, list_products, etc.) when they exist — they handle pagination, field selection, and error formatting consistently. Returns the raw GraphQL response plus rate-limit cost info. $0.10 per call.
| Parameter | Type | Description |
|---|---|---|
queryrequired | string | A complete GraphQL query string (read-only — mutations/subscriptions are rejected). Must end with a closing brace. Example: '{ shop { name } }'. Reference: https://shopify.dev/docs/api/admin-graphql/2026-04 |
variables | object | Optional GraphQL variables object for parameterized queries, e.g. { id: 'gid://shopify/Product/123' }. |
7. Pricing
Pricing is pulled live from the Gentic MCP manifest. All prices are per call and deducted from your Gentic credits.
| Tool | Cost |
|---|---|
| export_orders_report | 100¢ / call |
| get_customer | Free |
| get_order | Free |
| get_product | Free |
| get_shop_info | Free |
| list_customers | 5¢ / call |
| list_orders | 5¢ / call |
| list_products | 5¢ / call |
| shopify_connection_status | Free |
| shopify_graphql_query | 10¢ / call |
8. Notes
- **Read-only by design.** Every tool in v1 is read-only; `shopify_graphql_query` rejects mutations and subscriptions server-side.
- **Scopes are not all-or-nothing.** Connection succeeds as long as at least one of `read_orders` / `read_products` / `read_customers` is granted. A ROAS-focused user can connect with `read_orders` alone; tools that need a different scope error at call time with a clear message naming the scope to add.
- **`processed_at` vs `created_at`:** `processed_at` is when the order was actually placed and is the right key for revenue attribution. `created_at` can include draft-order timestamps that lag. Default sort and the export's pre-computed `processed_date` both use `processed_at`.
- `shop_domain` is the subdomain only (e.g. `my-shop` for `my-shop.myshopify.com`) and is stored as plaintext — it's a tenant identifier, not a secret. The Admin API access token is encrypted at rest.
- `list_*` tools cap each page at 50 records and paginate via `next_cursor`. `resultCount` is the page size, not the total — there's no cheap total count on Shopify, by design.
- `get_order` returns up to 250 line items; if an order has more (rare), use `shopify_graphql_query` for the rest.
- `get_product` accepts either `id` (numeric or full GID) or `handle` (the url-safe slug) — exactly one, not both.
- **`export_orders_report` CSV links expire in 1 hour.** The MotherDuck `shopify_orders` table persists, so you don't lose the data — re-export only if you need a fresh CSV file.
- `export_orders_report` caps at 10,000 orders per call. Narrow the date window if you hit it; the warehouse table is appended/upserted in chunks so multiple calls compose cleanly.
- Shopify Admin API version pinned to `2026-04`. Bumps are coordinated with the gentic-web validator's `SHOPIFY_API_VERSION` constant.
- All tools are organization-scoped — users only see their own Shopify store.