{"count":29,"docs":[{"slug":"blog/dry-run-preview","title":"Dry-run: preview every agent action before it happens","tags":["blog","feature","safety"],"body":"\n# Dry-run: preview every agent action before it happens\n\nEvery write tool in Shopigent accepts `dry_run: true`. When set, the tool validates the input, resolves all references (products, variants, customers), and returns **the exact mutation it would execute** — without executing it.\n\n## Why it matters\n\nAgents are great at intent, imperfect at details. Dry-run catches the gap:\n\n```json\n{\n  \"tool\": \"discounts_create\",\n  \"dry_run\": true,\n  \"input\": { \"title\": \"WEEKEND20\", \"value\": \"20%\", \"applies_to\": \"collection:hoodies\" }\n}\n```\n\nThe response shows the resolved discount — which collection ID matched, start/end dates, usage limits — so the agent (or you) can verify before committing.\n\n## Dry-run + confirmation gate\n\nThe two features stack:\n\n1. Agent calls the tool with `dry_run: true` → sees the preview.\n2. Agent calls it for real → Shopigent pauses at the **confirmation gate**.\n3. You approve in the dashboard → the mutation runs and lands in the **audit log**.\n\nThree checkpoints between \"the agent had an idea\" and \"your store changed\". That's how it should be.\n"},{"slug":"blog/feature-read-tools-content","title":"Manage collections, blogs, articles, and pages — now with read tools","tags":["blog","feature","content","collections"],"body":"\n# Manage collections, blogs, articles, and pages — now with read tools\n\nShopigent has always supported **write tools** for collections, blogs, articles, and pages (create, update, delete). What was missing was the ability to *explore* them first — to list what exists, inspect a specific item, and decide what to act on.\n\nNow every content category has both **read and write** tools.\n\n## New read tools\n\n### Collections (5 tools)\n\nCollections organize your products. The new read tools let you browse and inspect them:\n\n```\nList all my collections and show me which ones have\nthe most products.\n```\n\n```\nGet the \"Winter Sale\" collection — I need to see\nits current products and description.\n```\n\n| Tool | What it does |\n|------|-------------|\n| `list_collections` | Lists all collections (manual + automated) with id, title, handle, sort order |\n| `get_collection_by_id` | Fetches a single collection by GID, including description, image, product count |\n\n### Blogs (5 tools)\n\nBlogs hold your articles. Read tools let you discover them:\n\n```\nList all my blogs and show me which ones have the\nmost recent articles.\n```\n\n| Tool | What it does |\n|------|-------------|\n| `list_blogs` | Lists all blogs with id, title, handle, comment policy |\n| `get_blog_by_id` | Fetches a single blog by GID, including its articles and metadata |\n\n### Articles (5 tools)\n\nArticles are individual blog posts. Now you can read them:\n\n```\nList all articles in the \"News\" blog, ordered by date.\n```\n\n```\nGet the article about the summer sale — I need to\ncheck its publish date.\n```\n\n| Tool | What it does |\n|------|-------------|\n| `list_articles` | Lists all blog articles for a blog, with optional filters |\n| `get_article_by_id` | Fetches a single article by GID, including body, summary, tags, author |\n\n### Pages (5 tools)\n\nPages are static content (About, Contact, etc.):\n\n```\nList all my pages and tell me which ones are unpublished.\n```\n\n```\nGet the \"About Us\" page and show me its current content.\n```\n\n| Tool | What it does |\n|------|-------------|\n| `list_pages` | Lists all pages with id, title, handle, and status |\n| `get_page_by_id` | Fetches a single page by GID, including body and SEO metadata |\n\n## Why this matters\n\nBefore these read tools, an agent could only *write* content — but couldn't discover what exists. The workflow was:\n\n**Before:** \"Delete the About page\" → \"I don't know which page that is.\"\n**After:** \"List my pages. Find 'About'. Delete it.\"\n\nIt's a small change that makes the agent dramatically more useful — especially for repetitive tasks like auditing content, cleaning up old blogs, or restructuring collections.\n\n## Full category breakdown\n\nThe current seeded merchant catalog is organized into **nine categories**:\n\n| Category | Tools |\n|----------|-------|\n| Products | 31 |\n| Content | 16 |\n| Metaobjects & Custom Data | 15 |\n| Theme Pull Requests | 4 |\n| Orders | 6 |\n| Customers | 5 |\n| Discounts | 4 |\n| Fulfillments | 4 |\n| Inventory | 1 |\n\n**Total: 86 distinct seeded merchant tools** across nine categories. Runtime\nconnection identity and capability utilities are excluded from this count.\nTheme work is GitHub-only: Shopigent reads explicit repository files and creates\na confirmed pull request; the merchant merges it, then Shopify's native GitHub\nintegration synchronizes the connected branch to the merchant-selected theme.\nShopigent never merges, deploys, publishes, or directly edits Shopify theme code."},{"slug":"blog/feature-search-products","title":"Find any product instantly with full-text search","tags":["blog","feature","products"],"body":"\n# Find any product instantly with full-text search\n\nShopigent's `search_products` tool gives your AI agent the ability to search across your entire product catalog by keyword — just like the Shopify admin search, but accessible from any MCP client.\n\n## What it is\n\n`search_products` is a new read tool that performs full-text search across product titles, descriptions, and tags. It returns matching products with relevance scores, so the most relevant results appear first.\n\n```\nSearch my store for \"wool beanie\" — show me the top 5 matches.\n```\n\n## Why it's different from list_products\n\n`list_products` returns products with optional filters (status, collection, etc.). `search_products` is built for *discovery* — when you don't know exactly what you're looking for but have a keyword in mind.\n\n| Tool | Best for |\n|------|----------|\n| `list_products` | Browsing a category, paginated listing, status filters |\n| `search_products` | Keyword search, finding a specific product by name or description |\n\n## Example prompts\n\n### Find products by material\n\n```\nSearch for products containing \"organic cotton\" in their description.\nList the top 3 with their prices and inventory.\n```\n\n### Find products by tag or keyword\n\n```\nSearch for \"clearance\" across all product names and tags.\nShow me how many are still in stock.\n```\n\n### Product research\n\n```\nSearch for \"running\" in my store and tell me which products\nneed better meta descriptions based on their search ranking.\n```\n\n### Compare with list_products\n\n```\nSearch for \"winter\" products. Then for each result, check\nif the inventory is below 10 and add it to a restock list.\n```\n\n## How it works with the tool grid\n\n`search_products` is part of the **Products** category (15 tools). Enable it in Curated Tools alongside `list_products`, `get_product_by_id`, and the product write tools.\n\nAvailable on all plans (Free, Growth, Pro)."},{"slug":"blog/shopigent-vs-raw-api-key","title":"Shopigent vs a raw Admin API key: why curated tools win","tags":["blog","comparison","security"],"body":"\n# Shopigent vs a raw Admin API key\n\nTechnically, you don't need Shopigent to connect an LLM to Shopify. You can create a custom app, grab an Admin API token, and hand it to your agent. Merchants ask us why they shouldn't. Fair question — here's the honest comparison.\n\n## What a raw token gives you\n\n- **Everything, forever.** Whatever scopes the token has, the agent has — 24/7, no questions asked.\n- **No record.** Shopify logs API calls internally, but *you* have no readable trail of what your agent did or why.\n- **No brakes.** A hallucinated ID in a `productDelete` mutation executes just as happily as a correct one.\n- **Raw GraphQL complexity.** The agent burns tokens (and makes mistakes) constructing mutations, cursors, and error handling from scratch.\n\n## What curated tools change\n\n| | Raw Admin token | Shopigent |\n|---|---|---|\n| Access control | All-or-nothing scopes | Per-category toggles, per-key |\n| Destructive actions | Execute immediately | Pause at the confirmation gate |\n| Visibility | None | Full audit log (input, result, latency) |\n| Agent ergonomics | Raw GraphQL | 86 validated merchant tools |\n| Failure mode | Silent damage | Rejected input or pending approval |\n| Revocation | Rotate token, redeploy | Revoke key in one click |\n\n## The deeper point\n\nAgents don't fail like humans. They fail *confidently*, at machine speed, in bulk. The right response isn't \"never connect an agent\" — it's **structure the access so mistakes are cheap**. Validated inputs catch most errors; the confirmation gate catches the rest; the audit log tells you what happened either way.\n\nThat's the entire product, honestly. Fewer capabilities exposed, more safely, with receipts.\n\n*Try it free — read-only access needs zero trust.*\n"},{"slug":"blog/use-case-bulk-edit","title":"Use case: bulk editing products from a spreadsheet","tags":["blog","use-case","products"],"body":"\n# Use case: bulk editing products from a spreadsheet\n\nShopify's bulk editor is powerful but limited to what it shows in the grid. With Shopigent + an MCP agent, you can update any field on any product — based on a spreadsheet you already have.\n\n## The workflow\n\n**Step 1:** Export a CSV from Shopify (or prepare one in Google Sheets).\n\n**Step 2:** Feed it to your agent with clear instructions.\n\n**Step 3:** The agent reads each row, matches the product in Shopify, and applies the change — always with dry-run first.\n\n## Example: price update from a CSV\n\n```\nI have a file called prices.csv with columns: SKU, new_price.\n\nFor each row, find the matching product in Shopify by SKU. \nDry-run updating the price to new_price. Report back any SKUs \nthat don't match before you execute.\n```\n\n## Example: bulk tag addition\n\n```\nAdd the tag \"winter-2026\" to every product in the \"Winter Collection\" \ncollection. Show me how many products will be affected, then dry-run\nbefore executing.\n```\n\n## Example: SEO meta update\n\n```\nRead meta-descriptions.csv (columns: title, new_meta). For each row, \nfind the product by title and update its seo.description to new_meta. \nSkip any products that already have the same meta.\n```\n\n## Example: multi-lingual translation\n\n```\nExport all products. For products where the Spanish description \nis missing, translate the English description using the product's \ntags as context. Dry-run the first 5 translations for review.\n```\n\n## Tips for spreadsheet operations\n\n### Always use SKU or GID\nProduct titles change. Use the **SKU** or the Shopify **GID** (`gid://shopify/Product/123`) to match rows reliably.\n\n### Dry-run first\nAdd `dryRun: true` to every bulk update. The agent will preview every mutation without touching your store.\n\n### Batch by category\nSplit large spreadsheets into batches (e.g. 20 products at a time) to review before committing.\n\n```\nProcess the first 20 rows and stop for review. If the output \nlooks right, I'll tell you to continue with the next 20.\n```\n\n### Use filters to narrow scope\n\n```\nList products in \"Electronics\" with inventory > 10. Export their \nSKUs and current prices, then reduce each price by 15%.\n```\n\nThis avoids updating products that shouldn't change.\n\n## Why this works\n\nShopigent's `update_product` tool supports every field: title, description, price, compareAtPrice, tags, status, SEO, metafields, and more. Combined with `dryRun`, you get the power of a full API client without writing a single GraphQL query."},{"slug":"blog/use-case-bulk-seo","title":"Use case: bulk-editing product SEO with an agent","tags":["blog","use-case","products"],"body":"\n# Use case: bulk-editing product SEO with an agent\n\nProduct SEO is the most common \"should do, never does\" task. There are hundreds of products and writing unique descriptions by hand is brutal. An agent changes the math.\n\n## The prompt\n\n```\nFor products missing a meta description, write a 150-character meta description\nand a compelling product description using the title and vendor. Don't change\nprices or anything else. Show me a preview first.\n```\n\n## How it stays safe\n\n- The agent uses `products_list` (read) to find gaps — no writes yet.\n- For each product it drafts text, then calls `products_update` with `dry_run: true` so you see the before/after.\n- Only when you approve does the change go live. And you can scope it: \"only the apparel collection\" so nothing else moves.\n\n## Why not a bulk editor app?\n\nBulk editors are fast but dumb — they apply a template. An agent *understands* the product and writes per-item copy. Combined with the confirmation gate, you get bespoke quality with the safety of a bulk tool.\n\n> Tip: start read-only on the Free plan. Use the audit log to see exactly what the agent proposed, then upgrade to Growth and approve in one pass.\n"},{"slug":"blog/use-case-customer-support","title":"Use case: answering customer emails with an agent","tags":["blog","use-case","customers"],"body":"\n# Use case: answering customer emails with an agent\n\nSupport emails pile up fast — \"Where's my order?\", \"Can I change my address?\", \"Do you have this in a different size?\" — and every answer means digging through the Shopify admin.\n\nWith Shopigent, your AI agent reads the store data and drafts replies in seconds.\n\n## The workflow\n\n**Step 1:** A customer emails you.\n\n**Step 2:** Your agent searches for the customer and their orders in Shopify — without you leaving your email client or chat.\n\n```\nFind customer by email \"maria@example.com\" and show their \nlast 3 orders with status and fulfillment info.\n```\n\n**Step 3:** The agent drafts a reply based on live data.\n\n**Step 4:** If the reply involves a store change (refund, address update), the agent prepares it for your approval via the confirmation gate.\n\n## Example prompts\n\n### Check an order status\n\n```\nA customer named \"Elena\" emailed asking about order #1234. \nFind the order status, tracking number, and estimated delivery.\n```\n\n### Update a shipping address\n\n```\nCustomer \"Carlos\" needs his shipping address changed on order #5678 — \nhe moved to 42 New Street, Berlin. Dry-run the update first.\n```\n\n### Process a simple refund\n\n```\nOrder #9012 was returned. Refund the full amount to the original \npayment method. Use dryRun first to preview the refund mutation.\n```\n\n### Draft a support reply\n\n```\nLook up customer \"Sofia\" — her email is sofia@example.com. She has 14 \norders and her last one (#3456) shows \"delivered\" but she says it hasn't \narrived. What's the tracking status? Draft a reply offering options.\n```\n\n## Why this works\n\nShopigent's tools cover everything support needs:\n- **`get_customer`** → fetch contact details, tags, notes\n- **`list_orders`** → find recent orders by customer\n- **`get_order`** → check status, fulfillment, tracking\n- **`update_customer`** → change address, add tags\n- **`refund_order`** → process returns (with confirmation gate)\n\nAnd the audit log means every action is recorded — useful for tracking which tickets were handled through the agent."},{"slug":"blog/use-case-inventory-sync","title":"Use case: inventory sync after a stocktake","tags":["blog","use-case","inventory"],"body":"\n# Use case: inventory sync after a stocktake\n\nAfter a physical count, you often need to reconcile Shopify stock with what's on the shelves. Doing it by hand in the admin is slow and error-prone. Here's the agent-assisted version.\n\n## The prompt\n\n```\nFrom the attached stock count (SKU → quantity), adjust each variant's available\ninventory to match. Use inventory_adjust with dry_run first and report what will change.\n```\n\n## What happens\n\n1. The agent matches each SKU to a variant via `inventory_levels_list` (read) — catching typos before anything changes.\n2. For each mismatch it calls `inventory_adjust` with `dry_run: true`, returning a clear summary: \"SKU AB-123: 14 → 9\".\n3. You review the summary in the confirmation card and approve. No mismatched number slips through because the preview shows every delta.\n\n## The audit trail\n\nEvery adjustment — input, result, timestamp — lands in the audit log. So if a number looks wrong next month, you can see exactly when it was set and by which agent session.\n\n> Particularly useful for stores with multiple locations: the agent can target a specific location per SKU without you hunting through dropdown menus.\n"},{"slug":"blog/use-case-weekend-sale","title":"Use case: set up a weekend sale in two minutes","tags":["blog","use-case","discounts"],"body":"\n# Use case: set up a weekend sale in two minutes\n\nThe workflow merchants automate first is almost always discounts. It's fiddly in the admin (collection, value, dates, limits, code) and it's exactly the kind of structured task agents nail. Here's the full flow with Shopigent.\n\n## The prompt\n\nIn Claude, Cursor, or Hermes:\n\n```\nCreate a 20% discount code WEEKEND20 for the Hoodies collection,\nvalid Friday 00:00 to Sunday 23:59, one use per customer.\n```\n\n## What the agent does\n\n1. `products_list` / collections lookup — resolves \"Hoodies\" to the real collection ID.\n2. `discounts_create` with `dry_run: true` — previews the exact discount object.\n3. `discounts_create` for real — and here it **stops**.\n\n## What you do\n\nYour Shopigent dashboard shows a confirmation card:\n\n> **discounts_create** — WEEKEND20 · 20% off · collection: Hoodies (14 products) · Fri 00:00 → Sun 23:59 · 1/customer\n\nOne tap to approve. The discount goes live, the action lands in the audit log, and the agent confirms back in chat.\n\n## Variations that work just as well\n\n- \"Extend WEEKEND20 until Monday night\" → `discounts_update`\n- \"How did WEEKEND20 perform?\" → `orders_list` filtered by discount code\n- \"Kill the sale now\" → `discounts_delete` (confirmation again — deletes are always gated)\n\n## Why this beats doing it by hand\n\nNot because clicking is hard — because **the agent gets the details right** (IDs, dates, limits) and the gate means you review *one summary card* instead of five admin screens. Two minutes, fully audited.\n"},{"slug":"blog/why-ai-agents-for-shopify","title":"Why your Shopify store needs an AI agent (and how to stay in control)","tags":["blog","ai-agents","mcp"],"body":"\n# Why your Shopify store needs an AI agent (and how to stay in control)\n\nAI agents are past the demo phase. They can genuinely run store operations: updating product copy, building discounts, answering \"what were my top sellers last month\", adjusting inventory after a stocktake. The blocker was never intelligence — it was **safe access**.\n\n## The problem with raw API access\n\nGive an agent your Admin API key and you've given it everything, forever, with no record. One hallucinated `DELETE` and your catalog is gone. That's why most merchants (rightly) never connect an LLM to their store.\n\n## Scoped tools + human gate\n\nShopigent takes a different route:\n\n1. **You pick the categories** an agent can touch — Products yes, Orders no, for example.\n2. **Reads are free, writes are gated.** Any create/edit/delete/refund pauses and asks *you* to approve it in the dashboard.\n3. **Everything is logged.** Every call, its input, its result, its latency.\n\n> The agent proposes; you approve. That's the entire trust model, and it works.\n\n## What merchants actually automate first\n\nFrom what we see, the first wins are boring and valuable:\n\n- Bulk product copy cleanup and SEO descriptions\n- Seasonal discount setup (\"20% off everything in Collection X this weekend\")\n- Answering ops questions without opening five admin tabs\n- Tagging and segmenting customers after imports\n\nStart read-only on the Free plan, watch the audit log for a week, then enable writes for the categories you trust. Control first, speed second — and you end up with both.\n"},{"slug":"changelog","title":"Changelog","tags":["changelog"],"body":"\n# Changelog\n\n## 2026-10-05\n- **Files scope pair made explicit.** `upload_product_media` needs **three**\n  prerequisites verified against the live OAuth grant: `write_products`,\n  `read_files` and `write_files`. `read_files` is now declared as a required\n  scope alongside `write_files` rather than inferred from the write scope, and\n  the runtime scope set on the deployed app was corrected — it previously\n  omitted the file scopes entirely, which is why an already-installed store\n  could still hit `MISSING_SCOPE` on media upload after reauthorizing. This\n  supersedes the single-scope wording in the SH-017 entry below.\n\n## 2026-09-29\n- **SH-017 — file-scope authorization for media upload.** `upload_product_media`\n  now requires a verified live OAuth grant containing both `write_products` and\n  `write_files`. The server fails closed before decoding payloads or issuing\n  confirmation tokens when a prerequisite scope is missing. Error normalization\n  now reports exact scope handles (`missingScopes[]`) instead of the vague\n  `\"requiredScope\"` field, and handles the case where Shopify does not disclose\n  the scope (`null` with `knownPrerequisites[]`). The confirmation response\n  carries `resendRequired: \"full_identical_payload\"` — a token alone does not\n  resume after expiry.\n- `write_files` is declared as a **required** scope. The embedded app surfaces\n  four distinct states: tool enabled, scope requested, scope granted (verified),\n  and executable. An enabled toggle is never proof of Shopify authorization.\n  The Scopes & Permissions page now includes a **Files / Media upload** category\n  with the exact scope handle shown in the missing-scopes banner when the store\n  has not yet granted it.\n- The media upload workflow now emits structured observability logs at every\n  pipeline stage with secret-safe rules — no tokens, headers, confirmation\n  tokens, or base64 payloads are logged.\n\n## 2026-09-24\n- **SH-015 publication workflow — implementation prepared, not deployed.** Added the catalog contracts for `list_publications` and `publish_product_to_channel`, bringing the deduplicated seed catalog to **86 distinct merchant tools across nine categories**. Runtime-only connection identity and capability utilities remain excluded from this count.\n- `write_publications` is declared as an optional permission. Merchants explicitly enable or revoke it from the embedded **Scopes & Permissions** page; all other tools continue to work without it. Declaring the scope does not grant it, and no live merchant grant was performed as part of this change.\n- Publication targets come from `list_publications` and are selected explicitly by ID. The write workflow requires verified `writeProducts` and `writePublications` capabilities, dry-run planning, non-disableable human confirmation, idempotency protection, final readback, and compensation that never removes a pre-existing edge.\n- This entry documents the pending implementation only: no app-version release, deployment, production data change, or live product publication has occurred, and SH-015 is not yet resolved.\n- **Theme Pull Requests replace direct Shopify theme access.** The four `github_*` tools read explicit repository files and create a branch, commits, and PR only after dry-run and human confirmation. Shopigent never merges, deploys, publishes, or directly edits Shopify theme code through the Admin Theme API.\n- After the merchant reviews and merges, Shopify's native GitHub theme integration synchronizes the connected branch to the merchant-selected theme. Reviewer demonstrations use an unpublished connected theme so the live storefront remains unchanged.\n\n## 2026-09-23\n- Added `update_product_variant_weight`, a focused weight-only mutation for product variants.\n- The tool supports grams, kilograms, ounces, and pounds; validates product/variant IDs and weight values before Shopify is called; and always requires an args-bound human confirmation token.\n- `search_products` and `get_product_by_id` now return each variant's current shipping weight for safe readback and verification.\n\n## 2026-09-03\n- Added the four-tool repository workflow now named **Theme Pull Requests**: `github_theme_connection`, `github_list_theme_branches`, `github_theme_file`, and `github_create_theme_pr`.\n\n## 2026-09-03 (earlier)\n- **fix(object-arg payloads)** — object-payload tools (`create/update_metafield_definition`, `create/update_metaobject_definition`, `create/update_metaobject`) now send the full payload to Shopify (previously sent `{}` due to Zod STRIP-mode). (PR #5)\n- **fix(scopes)** — the **Metaobjects & Custom Data** category now shows \"Granted\" after reauthorize (added to scope-granted sync). (PR #6)\n- **fix(MCP metafield-read + HTTP)**:\n  - `list_product_metafield_definitions` & `get_metafield_definition` — correct nested `type { name }` selections (previously GraphQL error).\n  - `get_metafield_definition` accepts only `id` (no longer sends ownerType).\n  - HTTP JSON body limit raised **100KB → 50MB** — media uploads (`upload_product_media`) with large base64 now work (previously HTTP 413). Plus structured JSON errors instead of HTML. (PR #7)\n- **UI polish** — uniform scopes badges + aligned; dashboard quick-stats in one row; responsive mobile pages; tool cards with clear Enable/confirmation.\n\n## 2026-09-03 (earlier)\n- Added the **Metaobjects & Custom Data** category with 15 tools.\n- **Product media (SH-002, SH-007)** — new `upload_product_media` (staged-upload), `get_product_media`, and `get_product_publications`.\n- **Custom Data (SH-003)** — 15 metaobject & metafield-definition tools. Requires a dedicated **Custom Data** scope category; many are destructive and require confirmation.\n- **Template suffix (SH-004)** — `update_product` now supports `templateSuffix` / `clearTemplateSuffix`.\n- **Customers** — `create_customer` added (Customers now 5 tools).\n- **API version 2026-07**, new `read_publications` scope + `metaobjects` scopes.\n\n## 2026-09-01\n- Added read tools for collections, blogs, articles, and pages. Inventory was merged into Products.\n- **`search_products`** — new full-text search tool that finds products by keyword across titles, descriptions, and tags with relevance scoring.\n- **Content read tools** — `list_pages`, `get_page_by_id`, `list_blogs`, `get_blog_by_id`, `list_articles`, `get_article_by_id` make every content category fully readable.\n- **Collection read tools** — `list_collections`, `get_collection_by_id` let you browse collections before writing.\n- **Hero terminal slider** — homepage demo now cycles through 5 interactive prompt examples with prev/next controls and clickable dots.\n\n## 2026-07-20\n- **Connect guides** — added setup guides for Claude, Cursor, and Hermes agents.\n- **Plans & Billing doc** — clarified plan limits and upgrade flow.\n\n## 2026-07-12\n- **Security & Trust doc** — published our access model, key handling, and data practices.\n- **Scopes reference** — mapped every tool category to its Shopify OAuth scopes.\n\n## 2026-06-30\n- **Confirmation gate** ships to all paid plans — confirmation-gated actions are approved in the merchant's AI client.\n- **Audit log** — records tool name, input, result, and latency for every call.\n\n## 2026-06-15\n- **Dry-run preview** — every write tool supports `dry_run: true` to preview the exact mutation before executing.\n\n## 2026-05-01\n- **Public launch** — Shopigent launched with scope-based access control.\n"},{"slug":"guides/connect-chatgpt","title":"Connect ChatGPT to your store","tags":["guide","chatgpt","mcp","openai"],"body":"\n# Connect ChatGPT to your store\n\nChatGPT (GPT-4o and newer) supports MCP servers natively through **ChatGPT MCP** — giving you a conversational interface to your store data.\n\n> **Prerequisite:** You've installed Shopigent and issued an MCP API key. See [Getting Started](/guides/getting-started).\n\n## 1. Configure the MCP server\n\nOpen **ChatGPT Settings → MCP Servers → Add** and paste:\n\n```json\n{\n  \"mcpServers\": {\n    \"shopigent\": {\n      \"url\": \"https://mcp.shopigent.greeknous.com/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\nYou can also configure it via `~/.chatgpt/mcp.json` if you use ChatGPT Desktop.\n\n## 2. Ask your first query\n\n```\nShow me my top 10 products by revenue this month.\n```\n\nChatGPT uses `orders_list` and `products_list` through MCP and answers with live numbers.\n\n## 3. Go further with prompts\n\n```\nI want to create a discount for customers who spent over €200 last year.\nFirst find those customers, then suggest a discount structure.\n```\n\n```\nMy \"Trail Beanie\" has inventory 34 units. Check the last 90 days of sales \nfor that product and tell me if 34 units is enough or if I should reorder.\n```\n\n## 4. Combine with ChatGPT plugins\n\nPair Shopigent with ChatGPT's data analysis (code interpreter) to export store data and build reports — all from the same chat.\n\n## Troubleshooting\n\n- **MCP not showing** — ensure ChatGPT Desktop is updated to a version that supports MCP (GPT-4o, 2025+ releases).\n- **Key rejected** — the key is one-time. Generate a fresh one from the Shopigent dashboard.\n- **Scope denied** — the category you're querying isn't enabled in Curated Tools."},{"slug":"guides/connect-claude","title":"Connect Claude to your store","tags":["guide","claude","mcp"],"body":"\n# Connect Claude to your store\n\nThis guide shows how to connect Claude (Desktop or Code) to Shopigent's MCP endpoint.\n\n> **Prerequisite:** You've installed Shopigent and issued an MCP API key from the dashboard. See [Getting Started](/guides/getting-started).\n\n## 1. Add the MCP server\n\nAdd Shopigent to your Claude MCP configuration (`claude_desktop_config.json` or `~/.claude/mcp.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"shopigent\": {\n      \"url\": \"https://mcp.shopigent.greeknous.com/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n## 2. Verify the connection\n\nAsk Claude something read-only first:\n\n```\nList my 5 most recent orders with customer name and total.\n```\n\nClaude should call `orders_list` and return real data from your store.\n\n## 3. Example prompts for Claude\n\n### Explore your store\n\n```\nDescribe my store: how many products, customers, orders, and active discounts? \nUse the appropriate tools one at a time.\n```\n\n```\nShow me a dashboard: my top 3 products by revenue this month, my 3 lowest-stock \nitems, and how many pending orders I have — all in one response.\n```\n\n### Merchandising\n\n```\nFind 5 products with no meta description. For each one, draft a compelling \nmeta description based on its title and tags. Show me the drafts, then \nupdate them if I approve.\n```\n\n```\nWhich products in my store are tagged \"clearance\" but still at full price? \nList them with options to mark them down.\n```\n\n### Customer insights\n\n```\nWho are my top 5 customers by total spend? Show name, email, order count, \nand total spent. Don't change anything — just report.\n```\n\n```\nI want to send a birthday promo. List customers with birthdays this month, \ntheir email, and their favourite product category based on purchase history.\n```\n\n## 4. Try a write action (Growth/Pro)\n\n```\nCreate a 10% discount code SUMMER10 valid until end of month for all products.\n```\n\nShopigent will show a **confirmation prompt** in the app before the discount is created. Approve it, and check the audit log.\n\n### Bulk operations (always dry-run first)\n\n```\nDry-run: set the price of all products tagged \"sale\" to 20% off their current \nprice. Show me the before/after for 3 examples before executing.\n```\n\n## Troubleshooting\n\n- **401 Unauthorized** — the API key is wrong or was revoked. Issue a new one from the dashboard.\n- **Tool not available** — the category (e.g. Discounts) is disabled in your Curated Tools settings, or your plan doesn't include write access.\n- **Action blocked** — a pending confirmation is waiting in the Shopigent app."},{"slug":"guides/connect-claude-code","title":"Connect Claude Code to your store","tags":["guide","claude-code","claude","mcp"],"body":"\n# Connect Claude Code to your store\n\n[Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) is Anthropic's terminal-based agent. Combined with Shopigent, you can execute store operations — reads, writes, bulk edits — from the same terminal where you code.\n\n> **Prerequisite:** You've installed Shopigent and issued an MCP API key. See [Getting Started](/guides/getting-started).\n\n## 1. Start Claude Code with the MCP config\n\nCreate `~/.claude/shopigent.json`:\n\n```json\n{\n  \"shopigent\": {\n    \"url\": \"https://mcp.shopigent.greeknous.com/mcp\",\n    \"headers\": {\n      \"Authorization\": \"Bearer YOUR_API_KEY\"\n    }\n  }\n}\n```\n\nThen start Claude Code:\n\n```bash\nclaude --mcp ~/.claude/shopigent.json\n```\n\nOr add Shopigent to your project's `.claude/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"shopigent\": {\n      \"url\": \"https://mcp.shopigent.greeknous.com/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n## 2. Terminal-native prompts\n\nClaude Code shines at batch operations. Try these:\n\n```\nRead store-data/products.json, then for every product in that file that \nis out of stock, update its status to DRAFT using shopigent.\n```\n\n```\nList all discounts that expire this week. For each one, calculate the \ntotal revenue it generated and create a report.\n```\n\n## 3. Developer workflows\n\n```\nRead \"templates/index.json\" from my connected theme repository. Propose the\nsmallest repository-file change as a dry-run only; do not open a PR yet.\n```\n\n```\nPull the last 50 orders and check if any need fulfillment \n(fulfillment status = null). Return them as a JSON array.\n```\n\n## 4. Script it\n\nBecause Claude Code runs in the terminal, you can pipe results into scripts:\n\n```bash\nclaude --mcp shopigent \"List all products with inventory < 5\" | \\\n  jq '.products[].title' | xargs -I{} echo \"Reorder: {}\"\n```\n\n## Troubleshooting\n\n- **CLI not found** — install Claude Code: `npm install -g @anthropic-ai/claude-code`\n- **Connection error** — verify the MCP URL and key. Keys from the dashboard work for 24 hours.\n- **Batch too large** — use `dryRun: true` to preview mutations before running them in bulk."},{"slug":"guides/connect-codex","title":"Connect Codex CLI to your store","tags":["guide","codex","mcp","openai"],"body":"\n# Connect Codex CLI to your store\n\n[OpenAI Codex CLI](https://codex.openai.com) is an agentic terminal that combines Claude/ChatGPT-like reasoning with a live shell. Add Shopigent's MCP tools and your store becomes accessible from any terminal session.\n\n> **Prerequisite:** You've installed Shopigent and issued an MCP API key. See [Getting Started](/guides/getting-started).\n\n## 1. Configure Codex CLI\n\nCodex reads MCP servers from `~/.codex/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"shopigent\": {\n      \"url\": \"https://mcp.shopigent.greeknous.com/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\nStart Codex:\n\n```bash\ncodex\n```\n\n## 2. Prompts for Codex\n\nCodex is built for engineering workflows. Try:\n\n```\nUse shopigent to export all my product titles, prices, and inventory \ncounts to a CSV file called inventory-export.csv.\n```\n\n```\nFind every product whose description mentions \"cotton\" and replace \nit with \"organic cotton\". Preview with dryRun first.\n```\n\n## 3. Bulk operations\n\n```\nRun a dry-run discount: create a 15% off code called FALL15 for all \nproducts in the \"Fall Collection\" collection. If it looks right, \nconfirm it.\n```\n\n```\nList products where compareAtPrice < price (sale is inverted). \nFix each one.\n```\n\n## Troubleshooting\n\n- **Config not found** — ensure `~/.codex/mcp.json` has valid JSON.\n- **Tool calls return 401** — the key expired. Generate a new one.\n- **Rate-limited** — Free plan: 25 calls/day. Upgrade to Growth or Pro for higher limits."},{"slug":"guides/connect-continue","title":"Connect Continue.dev to your store","tags":["guide","continue","mcp","vscode"],"body":"\n# Connect Continue.dev to your store\n\n[Continue.dev](https://continue.dev) is an open-source AI code assistant that runs in VS Code and JetBrains. It supports MCP servers, so you can add Shopigent and manage your store without leaving the editor.\n\n> **Prerequisite:** You've installed Shopigent and issued an MCP API key. See [Getting Started](/guides/getting-started).\n\n## 1. Add Shopigent to Continue\n\nEdit `~/.continue/config.json`:\n\n```json\n{\n  \"experimental\": {\n    \"mcpServers\": {\n      \"shopigent\": {\n        \"url\": \"https://mcp.shopigent.greeknous.com/mcp\",\n        \"headers\": {\n          \"Authorization\": \"Bearer YOUR_API_KEY\"\n        }\n      }\n    }\n  }\n}\n```\n\nRestart VS Code (or reload the Continue extension).\n\n## 2. Ask from your editor\n\nOpen Continue's chat panel (Ctrl+Shift+R / Cmd+Shift+R) and try:\n\n```\nUsing shopigent, what are my 3 best-selling products this month?\n```\n\n```\nCheck the inventory of product \"Approach Under Glove\" and tell me \nif I need to reorder.\n```\n\n## 3. Code + store data\n\nContinue's strength is combining code context with external data:\n\n```\nI'm building a product card component. Fetch 3 real products from \nmy store with shopigent, and show me the shape of the data I need.\n```\n\n```\nI need to add a \"Low Stock\" badge. Query my inventory and tell me \nwhich products have fewer than 10 units — I'll handle the front-end.\n```\n\n## Troubleshooting\n\n- **Tools not available** — ensure Continue version supports MCP (≥ v0.9.0).\n- **Key invalid** — regenerate from the Shopigent dashboard.\n- **Read-only** — Free plan limits to read-only tools. Upgrade for writes."},{"slug":"guides/connect-cursor","title":"Connect Cursor to your store","tags":["guide","cursor","mcp"],"body":"\n# Connect Cursor to your store\n\nCursor supports MCP servers natively, which means your editor's AI can read and manage your Shopify store through Shopigent while you code.\n\n> **Prerequisite:** You've installed Shopigent and issued an MCP API key from the dashboard. See [Getting Started](/guides/getting-started).\n\n## 1. Add the MCP server\n\nOpen **Cursor Settings → MCP → Add new MCP server**, or edit `~/.cursor/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"shopigent\": {\n      \"url\": \"https://mcp.shopigent.greeknous.com/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\nRestart Cursor. The Shopigent tools appear in the MCP tools list.\n\n## 2. Verify\n\nIn a Cursor chat, ask:\n\n```\nUsing shopigent, list my products that are out of stock.\n```\n\n## 3. Prompts for Cursor developers\n\n### Development + store data\n\n```\nI'm building a product grid component. Use shopigent to fetch 6 real products \nfrom my store so I can preview how the grid renders with actual data.\n```\n\n```\nI need to test the checkout flow. Use shopigent to create a 1€ test product \nfor me, then delete it after I've finished testing.\n```\n\n### Bulk edits from code\n\n```\nRead the file ./products-to-update.json. For each SKU in the file, find \nthe matching product in Shopify and update its price to the new_price \nfrom the JSON. Use dryRun first.\n```\n\n### Theme development\n\n```\nRead \"sections/header.liquid\" from my connected theme repository on main.\nExplain where the header logo size is controlled. Do not write anything.\n```\n\n```\nI updated \"sections/header.liquid\" locally. Prepare a one-file Theme Pull\nRequest dry-run. Wait for my explicit approval before opening the PR.\n```\n\n## Ideas for developer workflows\n\n- Generate SEO descriptions in your editor and push them straight to products.\n- Pull real product data while building a storefront, instead of mocking it.\n- Propose explicit repository-file changes through a merchant-reviewed Theme Pull Request.\n- Use Cursor's `Cmd+K` to ask: \"Add a 10% student discount using shopigent\" — it calls the tools inline.\n\n## Troubleshooting\n\n- **Tools don't appear** — check the JSON syntax and restart Cursor completely.\n- **401 Unauthorized** — regenerate the API key in the Shopigent dashboard.\n- **Writes rejected** — your plan is read-only (Free) or the category is disabled."},{"slug":"guides/connect-hermes","title":"Connect Hermes Agent to your store","tags":["guide","hermes","mcp"],"body":"\n# Connect Hermes Agent to your store\n\nHermes Agent can operate your store conversationally — from Discord, Telegram, or the desktop app — through Shopigent's MCP endpoint.\n\n> **Prerequisite:** You've installed Shopigent and issued an MCP API key. See [Getting Started](/guides/getting-started).\n\n## 1. Add the MCP server to Hermes\n\n```bash\nhermes mcp add shopigent https://mcp.shopigent.greeknous.com/mcp \\\n  --header \"Authorization: Bearer ***\"\n```\n\nOr add it to your Hermes `config.yaml`:\n\n```yaml\nmcp:\n  servers:\n    shopigent:\n      url: https://mcp.shopigent.greeknous.com/mcp\n      headers:\n        Authorization: \"Bearer YOUR_API_KEY\"\n```\n\n## 2. Talk to your store\n\nFrom any connected chat:\n\n```\nΠόσες παραγγελίες είχαμε σήμερα; Ποια προϊόντα πούλησαν περισσότερο;\n```\n\nHermes calls `orders_list` / `products_list` and answers with live data — in any language.\n\n## 3. Prompts for any language\n\n### Greek\n\n```\nΒρες τα προϊόντα που έχουν απόθεμα κάτω από 5 τεμάχια και φτιάξε \nμια λίστα για παραγγελία.\n```\n\n```\nΠόσα προϊόντα πωλήθηκαν αυτή την εβδομάδα; Σύγκρινε με την προηγούμενη.\n```\n\n### English\n\n```\nShow me all orders from last week grouped by day. Which day had the most revenue?\n```\n\n```\nCreate a discount called SPRING25 for 25% off on all products in the \n\"Spring Collection\" collection, valid for 7 days. Dry-run first.\n```\n\n## 4. Autonomous routines\n\nBecause Hermes supports scheduled jobs, you can combine it with Shopigent for recurring ops:\n\n- Daily sales summary delivered to Discord every morning\n- Low-stock alerts checked hourly\n- Weekly draft of a promo discount, waiting for your approval via the confirmation gate\n\nThe confirmation gate is key: an autonomous agent can *prepare* destructive actions around the clock, but nothing executes until you approve.\n\n## Troubleshooting\n\n- **Connection fails** — verify the URL and that the key hasn't been revoked.\n- **Tool missing** — the category is toggled off in Curated Tools, or your plan doesn't include it.\n- **Scheduled job fails** — check Hermes' cron logs; the API key may have expired."},{"slug":"guides/getting-started","title":"Getting Started with Shopigent","tags":["guide","getting-started"],"body":"\n# Getting Started with Shopigent\n\nThis guide walks you through connecting an AI agent to your Shopify store with Shopigent.\n\n## 1. Install\nInstall Shopigent from the [Shopify App Store](https://apps.shopify.com/shopigent) and grant the scopes your store needs.\n\n## 2. Enable tool categories\nOpen the **Curated Tools** dashboard in the app. Each category (Products, Orders, Customers, etc.) has a toggle — enable only what you want your agent to access.\n\n## 3. Issue an MCP API key\nFrom the dashboard, generate an MCP API key. The plaintext key is shown once — store it securely. Shopigent stores only a hash.\n\n## 4. Connect your AI agent\n\nNow that you have an API key, choose your tool and follow the dedicated guide:\n\n- **[Claude Desktop](/guides/connect-claude)** — Anthropic's standalone app\n- **[Claude Code](/guides/connect-claude-code)** — Claude in your terminal\n- **[Cursor](/guides/connect-cursor)** — AI-native code editor\n- **[Hermes Agent](/guides/connect-hermes)** — Autonomous agent (Discord, Telegram)\n- **[ChatGPT](/guides/connect-chatgpt)** — OpenAI's MCP-capable chat\n- **[Codex CLI](/guides/connect-codex)** — OpenAI's terminal agent\n- **[Continue.dev](/guides/connect-continue)** — VS Code extension\n\nOr read the **[Prompts & Best Practices](/guides/prompts-best-practices)** guide for tips and examples.\n\n## 5. Confirmation gate\n\nAny destructive action (create, edit, delete, refund) triggers a confirmation prompt. Approve it to proceed. Every action is recorded in the audit log.\n\n## Reauthorizing after an app update\n\nWhen Shopigent ships a new scope (e.g. the `read_files` and `write_files` pair from a recent update),\nalready-installed stores need to reauthorize the app before the new tool\nbecomes available. Here is the lifecycle:\n\n1. **Deploy.** The app update ships with the new scope declared in its\n   configuration.\n2. **Detect.** The Scopes & Permissions page shows the scope as\n   **Not yet granted** and lists the exact missing handle.\n3. **Grant.** Click **Enable new scopes** — this redirects to the Shopify\n   install screen. Your store sees the exact new permissions requested.\n4. **Approve.** Shopify asks you to confirm the new permissions. Approve to\n   complete reauthorization.\n5. **Persist.** The app stores the updated grant and verifies it against a\n   live Shopify snapshot.\n6. **Refresh.** Capability caches are invalidated. The Curated Tools page\n   updates instantly — `uploadProductMedia` changes from a warning badge to\n   a green \"available\" state.\n7. **Verify.** The tool is now executable. Retry the agent call with the same\n   full payload.\n\n> **Enabled vs. granted:** The checkbox toggle in Curated Tools controls\n> whether a tool shows up in the control panel. It does **not** add or remove\n> Shopify OAuth scopes. A tool can be enabled in Shopigent but unavailable\n> until the store grants the underlying permission. The dashboard shows both\n> states independently.\n\n## Next steps\n\n- Browse all [curated tools](/reference/tools) with descriptions\n- See [scopes & permissions](/reference/scopes-and-permissions) to enable only what your agent needs\n- Compare [plans and pricing](/guides/plans-and-billing)\n- Read the [Prompts & Best Practices](/guides/prompts-best-practices) guide\n"},{"slug":"guides/plans-and-billing","title":"Plans & Billing","tags":["guide","plans","billing"],"body":"\n# Plans & Billing\n\nShopigent bills through the [Shopify App Store](https://apps.shopify.com/shopigent), so charges appear on your regular Shopify invoice. No separate card, no separate account.\n\n## Plans at a glance\n\n| | Free | Growth | Pro |\n|---|---|---|---|\n| Price | $0 | $9.99/mo | $29/mo |\n| Read tools | ✅ All | ✅ All | ✅ All |\n| Write tools | — | ✅ Core resources | ✅ Core resources |\n| Translations | — | — | ✅ |\n| Theme Pull Requests | Read-only tools | ✅ Create after confirmation | ✅ Create after confirmation |\n| Tool calls / day | 25 | 500 | Unlimited |\n| Trial | — | 7-day trial | 7-day trial |\n\n**Core resources** = Products, Orders, Customers, Discounts, Content, Inventory, Fulfillments, Custom Data, and Theme Pull Requests.\n\n> **Agency plan — coming soon.** A multi-store plan for agencies is on our roadmap. It is not yet available; join the waitlist at [hello@greeknous.com](mailto:hello@greeknous.com).\n\n## What you get per plan\n\n### Free — $0\n- Read-only access to your whole store\n- 86 curated merchant tools across nine categories\n- Up to 25 tool calls per day\n- Full audit log of every agent action\n- Dry-run preview before any action\n- Connect any MCP client (Claude, Cursor, Hermes)\n- Email support\n- No credit card required\n\n### Growth — $9.99/mo (7-day trial)\n- Everything in Free, plus write tools\n- Create, edit, update, delete products & orders\n- Manage customers, discounts, collections\n- Up to 500 tool calls per day\n- Mandatory confirmation on destructive actions\n- Blog, page & content management\n- Inventory & fulfillment tools\n- Theme Pull Requests through a connected GitHub repository\n\n### Pro — $29/mo (7-day trial)\n- Everything in Growth\n- Translations (set/get/delete) for non-theme Shopify resources\n- Unlimited tool calls\n- Priority execution\n- Custom tools builder\n\n## Theme Pull Request boundary\n\nConnect a designated repository through the Shopigent Connector Public GitHub\nApp or an optional merchant-supplied fine-grained PAT. Shopigent reads explicit\nfiles and, after MCP dry-run and human confirmation, creates only a branch,\ncommits, and a pull request. It never merges, deploys, publishes, or directly\nedits Shopify theme code through the Admin Theme API. You review and merge;\nShopify's native GitHub theme integration synchronizes the connected branch to\nthe theme you selected. Use an unpublished connected theme for review so the\nlive storefront remains unchanged.\n\n## How limits work\n\n- A **tool call** is one MCP tool invocation — one `list_products` call, one `refund_order`, etc.\n- Limits reset at midnight UTC.\n- Calls that hit the confirmation gate count once (not again on approval).\n- `dry_run` calls count as normal calls.\n\n## Upgrading & downgrading\n\n1. Open the Shopigent dashboard in your Shopify admin.\n2. Go to **Plan** and pick the new tier.\n3. Shopify shows its standard approval screen; charges are prorated by Shopify automatically.\n\nDowngrades apply at the end of the current billing cycle. Your settings, keys, and audit log are kept — write tools simply stop being available if the new plan doesn't include them.\n\n## FAQ\n\n**Do unused calls roll over?** No, the daily allowance resets every day.\n\n**What happens if I hit my limit?** Tools return a clear `rate_limited` error with the reset time. Reads on the Free plan are throttled, never silently dropped.\n\n**Is there a trial for paid plans?** Growth and Pro include a 7-day free trial via Shopify's standard trial mechanism.\n"},{"slug":"guides/prompts-best-practices","title":"Prompts & Best Practices","tags":["guide","prompts","best-practices"],"body":"\n# Prompts & Best Practices\n\nGet the most out of Shopigent by using the right prompts, safety patterns, and workflows.\n\n## Key principles\n\n### 1. Dry-run before write\n\nEvery write tool supports `dryRun: true`. Always preview the mutation before it touches your live store:\n\n```\nDry-run: update the price of \"Approach Under Glove\" to €39.99.\n```\n\nThe agent returns the exact GraphQL mutation it *would* execute. Only when you approve does it run live.\n\n### 2. Use categories explicitly\n\nShopigent has **nine seeded merchant-tool categories** (Products, Content, Metaobjects & Custom Data, Theme Pull Requests, Orders, Customers, Discounts, Fulfillments, Inventory). Mention the category for faster tool routing:\n\n```\nUse products tools: find all products with no description in Italian.\n```\nvs.\n```\nWhat products need Italian descriptions?\n```\n\n### 3. Chain operations, don't guess\n\nInstead of asking for everything at once, chain:\n\n```\n1. List my products tagged \"clearance\".\n2. For each, update the price to 40% off current.\n3. Show me the total discount value.\n```\n\nThe agent resolves each step separately, triggering confirmation only when a write tool is used.\n\n### 4. Confirmation gate pattern\n\nConfirmation-gated writes (for example deletes, refunds, and Theme Pull Request creation) require **confirmed: true**. Use this pattern:\n\n```\nDelete product with ID gid://shopify/Product/12345.\n```\n\n→ Returns `confirmation_pending` with a token.\n\n```\nConfirm: yes, with the same token.\n```\n\n→ Executes the delete and logs it.\n\nAn agent can *propose* destructive actions autonomously — nothing executes until you approve.\n\n## Prompts by role\n\n### Store owner\n\n```\nI'm going on holiday. Check my inventory: what needs reordering, \nare there any stuck fulfillments, and do I have active discounts \nthat expire while I'm away?\n```\n\n```\nList all products with 0 inventory and no reorder point set.\n```\n\n### Developer\n\n```\nI need to rename \"Trail Beanie\" to \"Trail Beanie 2.0\" across all \nlanguages. Dry-run a translation update for each language the product \nhas, then execute.\n```\n\n```\nRead \"config/settings_schema.json\" from my connected theme repository and\nreview it for schema issues. Do not write or open a PR.\n```\n\n### Marketing\n\n```\nDraft a 15% discount code for email subscribers. The code should \nbe single-use per customer, valid for 48 hours, and exclude sale items.\n```\n\n```\nFind products with less than 2 inventory — these are running out \nand need promotion before they're gone.\n```\n\n## Tool priorities by task\n\n| If you want to… | Use… |\n|---|---|\n| Discover what's in stock | `list_products` with inventory filters |\n| Edit a product | `update_product` (dry-run first) |\n| Check revenue | `list_orders` (date range filter) |\n| Run a promotion | `create_discount` |\n| Fix customer details | `get_customer` → `update_customer` |\n| Manage content | `create_blog_post`, `update_page` |\n| Propose a theme repository change | `github_create_theme_pr` (Growth/Pro) |\n| Translate the store | `set_translations` (Pro) |\n\n## Rate limits by plan\n\n| Plan | Tool calls / day | Best for |\n|---|---|---|\n| Free | 25 | Exploring, read-only queries |\n| Growth | 500 | Daily operations with writes |\n| Pro | Unlimited | Power use + custom tools + translations |\n\nUse **dry-run preview** to avoid wasting call allowance on failed writes.\n\n## Pro tips\n\n1. **Name your operations** — agents follow steps better when you say \"Step 1… Step 2…\"\n2. **Use filters** — `list_products` with `query: \"status:ACTIVE\"` returns useful subsets\n3. **Check the audit log** — every call is recorded. Review what your agent did.\n4. **Least privilege scopes** — enable only the categories your agent needs\n5. **Trial the Pro plan** — unlock non-theme resource translations and unlimited calls"},{"slug":"guides/security-and-trust","title":"Security & Trust","tags":["guide","security","trust"],"body":"\n# Security & Trust\n\nGiving an AI agent access to your store is a trust decision. Here is exactly how Shopigent limits, records, and controls that access.\n\n## The access model\n\n1. **You choose the categories.** Each of the nine merchant-tool categories has an on/off toggle. Disabled categories are invisible to agents — the tools aren't listed, let alone callable.\n2. **Reads and writes are separated by plan.** Free is read-only by design; write tools only exist on paid plans.\n3. **Confirmation-gated actions stop before execution.** The tool returns a signed, single-use `confirmation_pending` result; you approve **in your AI client** and the agent re-calls the tool with the confirmation token bound to the same arguments. Theme Pull Request creation uses this gate after dry-run.\n4. **Everything is written to the audit log.** Tool name, full input, result, latency, timestamp. The log is append-only.\n\n## API keys\n\n- Keys are shown **once** at creation; Shopigent stores only a salted hash.\n- Keys can be revoked instantly from the dashboard.\n- Each key is scoped to one store.\n\n## Data handling\n\n- Shopigent processes your store data to execute tool calls; it does not sell it or use it for advertising.\n- Store data is **not used to train AI models**.\n- Audit log entries are retained so you can review agent activity; you can request deletion of your data at any time.\n- Uninstalling the app triggers Shopify's standard data-removal webhooks and Shopigent deletes stored shop data accordingly (see [Privacy Policy](/privacy-policy)).\n\n## Shopify-side protections\n\n- Shopigent requests only the Shopify scopes needed for the categories you use.\n- All traffic runs over TLS.\n- Billing is handled entirely by Shopify — Shopigent never sees your payment details.\n\n## Operational observability\n\nProduct media uploads emit structured JSON log entries (`event: \"media_upload_stage\"`)\nat every pipeline stage: stagedUploadsCreate, confirmation_issued, binary_upload,\nfileCreate, file_status_polling, productSet, and final_readback.\n\nEach entry carries:\n- stage name and shop identifier\n- operation ID (your idempotency key or a generated hash)\n- product ID and file count\n- on error: a sanitized diagnostic excerpt and Shopify request ID\n\n**The following are never included in any log entry:**\n- Shopify access tokens, client secrets, or session tokens\n- HTTP headers or bearer tokens\n- Confirmation token values\n- Base64 file payloads or staged upload target parameters\n- Signed URLs, X-Amz headers, or S3 credentials\n\nSee the [Privacy Policy](/privacy-policy) for data retention and deletion.\n\n## GitHub theme connections\n\n- The **Shopigent Connector** Public GitHub App is limited to the repository you designate and uses short-lived installation tokens — no long-lived PAT.\n- If you prefer a manual connection, your fine-grained token is encrypted at rest (AES-256-GCM) before it is stored and is never returned by any API or shown again.\n- Shopigent reads only explicitly requested repository files. After MCP dry-run and human confirmation it can create a branch, commits, and a pull request containing the declared changes.\n- Shopigent never merges, deploys, publishes, or directly edits Shopify theme code through the Admin Theme API, and it does not request direct Shopify theme scopes.\n- You review and merge the PR. Shopify's native GitHub theme integration then synchronizes the connected branch to the theme you selected. Use an unpublished connected theme for review so the live storefront remains unchanged; publication is always merchant-controlled.\n\n## Reporting a vulnerability\n\nFound something? Email **shopigent@greeknous.com**. We respond fast and appreciate responsible disclosure.\n"},{"slug":"guides/troubleshooting-faq","title":"Troubleshooting & FAQ","tags":["guide","faq","troubleshooting"],"body":"\n# Troubleshooting & FAQ\n\n## Connection issues\n\n**401 Unauthorized**\nThe API key is invalid or revoked. Generate a new key in the dashboard and update your MCP client config. Remember: keys are shown only once.\n\n**MCP client can't find the server**\nCheck the endpoint URL and that your client actually reloaded its config (Cursor and Claude Desktop need a full restart).\n\n## Missing or failing tools\n\n**A tool doesn't appear in the tools list**\nThe category is toggled off in **Curated Tools**, your plan doesn't include it,\nor a Theme Pull Request tool has no connected repository. Connect through the\nShopigent Connector Public GitHub App or the optional manual PAT form.\n\n**`plan_upgrade_required` error**\nThe tool exists but your plan is read-only for it. See [Plans & Billing](/guides/plans-and-billing).\n\n**`rate_limited` error**\nYou hit the daily call allowance (Free 25/day, Growth 500/day). The error includes the reset time (midnight UTC).\n\n## Confirmation gate\n\n**\"Action pending confirmation\" — nothing happens**\nThe action is waiting for approval in your AI client. Approve there so the\nagent can re-call the tool with the signed token and exactly the same arguments.\nThere is no Shopigent dashboard approval dialog.\n\n**Can I turn off confirmations?**\nNo — that's deliberate. Every destructive action requires human approval. Use `dry_run` for previews instead.\n\n## Theme Pull Requests\n\n**Why did my PR not change the Shopify storefront?**\nShopigent stops after creating the pull request. Review and merge it on GitHub.\nShopify's native GitHub theme integration then synchronizes the connected branch\nto the theme you selected. For testing, connect an unpublished theme so the live\nstorefront stays unchanged. Publishing is always a merchant action.\n\n**Can Shopigent edit or publish a Shopify theme directly?**\nNo. It does not request direct Shopify theme scopes and does not use the Admin\nTheme API. Theme repository changes are PR-only.\n\n## General\n\n**Does Shopigent work with any MCP client?**\nYes — anything that speaks Model Context Protocol: Claude, Cursor, Hermes, custom agents.\n\n**Can agents see data in disabled categories?**\nNo. Disabled categories aren't listed to the agent at all.\n\n**Where do I see what my agent did?**\nThe **Audit Log** in the dashboard — every call with input, result, and latency.\n\n**How do I completely revoke an agent's access?**\nRevoke its API key. Effect is immediate.\n\n## Missing scope\n\n**`MISSING_SCOPE` error — what does it mean?**\nShopify refused the operation because the app's current OAuth token is missing\na required permission. This is different from a disabled Shopigent category\n(which controls tool visibility) — the Shopify installation itself does not\ninclude the scope.\n\n**How do I read the error?**\nThe error response includes a `details` object with:\n- `missingScopes[]` — exact Shopify handles the store still lacks (e.g.\n  `[\"read_files\", \"write_files\"]`). This list is authoritative only when `scopeSource` is\n  `\"shopify_error\"` or `\"live_grant\"`.\n- `scopeDisclosed` — `true` when Shopify named the required scope, `false`\n  when it only said \"access denied\" without a handle.\n- When `scopeDisclosed` is `false` and known prerequisites are available,\n  `knownPrerequisites[]` lists what the tool needs — check those against your\n  OAuth grant.\n- `deniedField` — the Shopify GraphQL field that triggered the denial (e.g.\n  `stagedUploadsCreate`).\n\n**What if `requiredScope` is `null`?**\nShopify refused the operation without naming the specific scope. Open\n**Scopes & Permissions** in the embedded app, find the category the tool\nbelongs to, and grant its scopes. The app shows exact missing handles in the\nbanner when they can be determined.\n\n**How do I reauthorize?**\n1. Open the **Scopes & Permissions** page in Shopigent's embedded app.\n2. Read the missing scopes listed in the warning banner (e.g. `read_files`, `write_files`).\n3. Click **Enable new scopes** — this opens the Shopify OAuth install screen\n   with all scopes the app needs.\n4. Approve the permissions. Shopify redirects back to the app.\n5. The app verifies the new live grant. Capabilities refresh automatically;\n   the `uploadProductMedia` badge on the Curated Tools page updates to reflect\n   the new state.\n6. Retry the agent call with the same full payload.\n\n**Can I use the Scopes & Permissions checkboxes instead?**\nNo — those toggles control whether the tool appears in Shopigent's control\npanel (enabled vs. disabled). They do not add or remove Shopify OAuth scopes.\nOnly the OAuth install/reauthorize screen can grant new permissions.\n\n**Does write_files imply read_files?**\nNot for this app — Shopigent requests `read_files` and `write_files` as two\nseparate required scopes, and product media upload needs both. In Shopify's model\na write scope carries effective read access for the same resource, but\n`upload_product_media` polls file status through the Files API, so the app\ndeclares both handles explicitly rather than relying on that implication.\n\nStill stuck? Email **shopigent@greeknous.com**.\n"},{"slug":"index","title":"Shopigent — Operate your Shopify store with AI agents","tags":["home","overview"],"body":""},{"slug":"privacy-policy","title":"Privacy Policy","tags":["legal","privacy"],"body":"\n# Shopigent — Privacy Policy\n\n**Last updated:** 2026-09-23 | **Controller:** Greek Nous | **Contact:** shopigent@greeknous.com\n\n## 1. What Shopigent is\nShopigent is a Shopify app that lets merchants operate their store through AI agents (any MCP-compatible client, e.g. Hermes, Claude, Cursor, OpenAI Codex, xAI Grok). It exposes a curated set of read and write operations (\"tools\") over the Shopify Admin API, gated by the merchant's chosen plan and the scopes they grant at install time.\n\n## 2. Data we access\nAt install, the merchant authorizes Shopify OAuth scopes. Shopigent only accesses data required by the tools the merchant enables. Possible scope categories include products, orders, customers, discounts, inventory, fulfillments, online store content, translations, and custom data. Shopigent does not request direct Shopify Theme API scopes and does not directly read, modify, duplicate, or publish Shopify themes. We access store data **only** to fulfill a tool call the merchant (or their agent, on their behalf) explicitly triggers.\n\nWe do **not** access: payment instrument numbers, passwords, or any data outside the authorized Shopify scopes.\n\n## 3. Data we store\n- **Shop connection metadata** (store domain, granted scopes, current plan).\n- **API key hashes** — we store only a salted SHA-256 hash of the MCP API key. The plaintext key is shown once at creation and never stored.\n- **Tool-call audit logs** — for every tool call we record: shop, tool key, operation type, input arguments, result status, and latency.\n- **Plan / billing events** — subscription status and Shopify charge IDs (received via Shopify webhooks), not card numbers.\n- **GitHub connection (optional)** — repository owner, name, branch, and either an encrypted Shopigent Connector installation marker or the merchant's encrypted fine-grained PAT. Tokens are never returned after saving.\n\n## 4. Data we share\nWe do not sell or share merchant data with third parties except:\n- with **Shopify**, necessarily, to perform the requested operations;\n- with the merchant's chosen AI client (e.g. OpenAI Codex, Anthropic Claude, xAI Grok), only the data needed to answer the specific request they made;\n- with **GitHub (optional)**, when the merchant connects a theme repository through the **Shopigent Connector** Public GitHub App (operated by us and limited to the designated repository) or supplies their own fine-grained PAT. Shopigent reads explicitly requested repository files and, after MCP dry-run and human confirmation, can create a branch, commits, and a pull request containing declared changes to valid theme files such as locale JSON, JSON templates, Liquid sections/snippets/blocks, assets, and `config/settings_data.json`. Shopigent never merges, deploys, publishes, or directly edits Shopify theme code through the Admin Theme API. The merchant reviews and merges the PR. Shopify's native GitHub integration then synchronizes the connected branch to the merchant-selected theme; reviewer demonstrations use an unpublished theme so the live storefront remains unchanged. General product, page, collection, article, and metaobject translations remain Shopify Translations API operations.\n\n## 5. Data retention\nAudit logs and connection metadata are retained while the app is installed. Uninstalling the app triggers deletion of store-specific records.\n\n## 6. Security\nMCP API keys are hashed (never stored in plaintext). GitHub connection tokens (PATs and installation markers) are encrypted at rest with AES-256-GCM before they are written to the database and are never returned by any API or tool response. All Admin API calls use the store's OAuth access token, transmitted only to Shopify over TLS. Write and destructive operations require an explicit confirmation step: the tool returns a signed, single-use, time-limited `confirmation_pending` result, the human approves **in their AI client**, and the agent re-calls the tool with the signed confirmation token before anything executes. This includes general Shopify translation writes and `github_create_theme_pr`.\n\n## 7. Your rights\nMerchants may request deletion of their data at any time via shopigent@greeknous.com or by uninstalling the app from their Shopify admin.\n\n## 8. Changes\nMaterial changes to this policy will be communicated via the support email."},{"slug":"proof-of-resolution-theme-workflow","title":"Shopigent — Theme workflow clarification and screencast","tags":["review","github","theme-workflow"],"body":"\n<style>\n.proof-intro{border-left:4px solid #269982;padding:1rem 1.25rem;background:rgba(38,153,130,.08);border-radius:0 12px 12px 0}.proof-video{width:100%;height:auto;background:#111;border-radius:16px;border:1px solid rgba(69,43,96,.25);margin:1rem 0}.proof-flow{display:flex;flex-wrap:wrap;gap:.65rem;margin:1.4rem 0}.proof-flow span{padding:.6rem .85rem;border:1px solid rgba(38,153,130,.4);border-radius:10px;font-size:.9rem}.proof-compare{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1rem;margin:1.25rem 0}.proof-compare>div{padding:1.2rem;border:1px solid rgba(38,153,130,.45);border-radius:14px}.proof-compare strong{display:block;margin-bottom:.6rem}.proof-compare p{margin:.3rem 0!important}.proof-label{font-size:.8rem;text-transform:uppercase;letter-spacing:.06em;opacity:.8}.proof-note{font-size:.9rem;opacity:.85}@media(max-width:640px){.proof-compare{grid-template-columns:1fr}}html.dark .proof-intro{background:rgba(38,153,130,.14)}\n</style>\n\n# Theme workflow clarification & screencast\n\n**Shopigent · GitHub Theme Pull Requests**\n\n<div class=\"proof-intro\">\n<strong>Answer to the open theme-functionality clarification</strong>\n<p>Shopigent does not give an AI platform direct access to Shopify’s theme editor. The merchant’s MCP client requests specific files from a designated GitHub repository through Shopigent, proposes changes, and asks Shopigent to create a pull request. The merchant reviews and merges that PR in GitHub. Shopify’s separate native GitHub integration synchronizes the connected branch to its associated theme.</p>\n<p><strong>Shopigent creates the proposal. The merchant controls the merge. Shopify performs the native synchronization. Theme publication is a separate merchant action.</strong></p>\n</div>\n\n## Watch the recorded workflow\n\nThis screencast shows actual Codex tool calls, the dry-run and confirmation response, PR creation, a human review and merge, and the resulting unpublished-theme preview alongside the unchanged live storefront. English narration and synchronized captions are included.\n\n<video class=\"proof-video\" controls playsinline preload=\"metadata\" aria-label=\"Shopigent GitHub pull request and unpublished theme workflow\">\n<source src=\"/Shopigent-GitHub-PR-Unpublished-Theme-Workflow.mp4\" type=\"video/mp4\">\nYour browser cannot play the embedded video. Use the direct MP4 link below.\n</video>\n\n[Open the video directly](/Shopigent-GitHub-PR-Unpublished-Theme-Workflow.mp4) · [Download MP4](/Shopigent-GitHub-PR-Unpublished-Theme-Workflow.mp4)\n\n<p class=\"proof-note\">Browser-compatible MP4: H.264 video, AAC audio, faststart. Runtime: approximately 2 minutes 50 seconds. Once published, this page and its video are intended to be accessible without signing in to Shopify or GitHub.</p>\n\n## How are theme updates implemented?\n\n<div class=\"proof-flow\" aria-label=\"Workflow sequence\">\n<span>1 · Explicit file read</span><span>2 · Proposed change + dry-run</span><span>3 · Merchant confirmation</span><span>4 · Branch + commit + PR</span><span>5 · Human GitHub merge</span><span>6 · Shopify-native sync</span><span>7 · Unpublished preview</span>\n</div>\n\n1. **Read an explicitly named repository file.** The merchant chooses a repository connection in Shopigent. The client calls `github_theme_file` with a path and ref; in the video, it requests `templates/index.json` on `main`. Shopigent retrieves that file from GitHub and returns it to the client. The client can use its chosen AI provider to process that returned content; this is not a claim that file content stays on the merchant’s machine.\n2. **Propose a targeted change.** Codex derives replacement file content from the actual file read. The recorded change replaces one homepage headline, preserving the rest of the file. The PR tool accepts explicitly supplied file changes; the headline example demonstrates that mechanism, not a restriction that all proposals must be text-only.\n3. **Preview and obtain confirmation.** A `dryRun: true` call returns a plan without creating a branch, commit, or PR. A subsequent unconfirmed request returns `confirmation_pending`. The merchant explicitly approves PR creation, and the confirmed request uses a token bound to the proposal arguments. Approval to create a PR is not approval to merge or publish.\n4. **Create a fresh proposal branch and PR.** Shopigent writes the declared changes to a new branch and opens a PR targeting the selected base branch. It does not write this proposal directly to the existing connected branch, merge the PR, or publish a Shopify theme.\n5. **Merchant reviews and merges outside Shopigent.** The video shows the merchant inspect the GitHub diff and manually merge the PR into `main`. This is a GitHub action performed by the merchant, not a Codex or Shopigent merge operation.\n6. **Shopify synchronizes its native theme connection.** After the merge, Shopify’s own GitHub integration synchronizes the connected `main` branch to the associated unpublished theme. Shopigent targets a repository and branch—not a Shopify theme ID. The destination and publication status are determined by the merchant’s Shopify-native theme connection.\n7. **Preview without publication.** The merchant opens the draft theme’s preview and separately checks the live storefront. No Publish action is performed in this demonstration.\n\n## Does the AI platform access and manually edit the store theme?\n\n**Not directly through Shopigent’s Shopify theme-editing APIs.** In the current GitHub Theme Pull Requests workflow, the AI client reads specifically requested GitHub files through Shopigent and supplies proposed replacement content through MCP. Shopigent applies approved proposals to a fresh GitHub branch and opens a PR. The AI provider is not given a Shopify Admin session or a direct theme-editor capability by this workflow.\n\nThe client’s AI provider may receive the requested file content to process the merchant’s instructions. GitHub receives the approved branch, commit, and PR. Shopigent processes the tool inputs and outputs, and its merchant-visible audit log records tool activity; this page does not claim that Shopigent receives or retains no content. See the [Privacy Policy](/privacy-policy) for data-handling details.\n\n**Clarification of our earlier replies:** references to direct theme duplication, theme-file updates, and theme publication described an earlier implementation. The current GitHub-only workflow does not expose those direct Shopify Theme API tools. It does not create a brand-new Shopify theme, install a theme, or publish one. Existing theme files in a merchant-designated repository can be proposed for modification, but merge and publication remain separate merchant-controlled actions.\n\n## Full scope of the GitHub functionality\n\n| Tool | Function | Boundary |\n|---|---|---|\n| `github_theme_connection` | Returns the merchant’s designated repository connection. | Does not expose connection credentials. |\n| `github_list_theme_branches` | Lists branches in that repository. | Read-only. |\n| `github_theme_file` | Reads an explicitly requested repository file at a ref. | Read-only; no Shopify theme-editor access. |\n| `github_create_theme_pr` | Previews a proposal or, after confirmation, creates a new branch, commits declared file changes, and opens a PR. | No merge, Shopify-native sync, or theme publication operation. |\n\nRepository access uses the **Shopigent Connector Public GitHub App**, operated by us, or an optional merchant-supplied GitHub token. Repository authorization in Shopigent and Shopify’s native GitHub theme connection are **two separate integrations**; configuring one does not configure the other.\n\n## What the screencast demonstrates\n\n| Sequence | Visible evidence |\n|---|---|\n| Initial state | The Current theme and a separate GitHub-connected unpublished theme. |\n| Explicit read | Codex verifies `shopigent-test.myshopify.com`, `MK-XXXVII/shopigent-kosmos-theme`, `main`, and `templates/index.json`. |\n| Dry-run | Proposed head `update/homepage-headline-01`, base `main`, one affected file, and `dry_run`. |\n| Confirmation | `confirmation_pending`, the client stops, and the merchant explicitly approves PR creation. |\n| PR creation | PR #2, **Update homepage headline**, is returned. |\n| Human review and merge | The merchant opens Files changed, reviews the one-line replacement, and manually merges in GitHub. |\n| Draft result | The GitHub-connected unpublished theme preview displays **Discover something special today**. |\n| Live result | The original Current theme’s storefront still displays **Browse our latest products**. |\n\n<div class=\"proof-compare\">\n<div><span class=\"proof-label\">Unpublished · GitHub-connected theme</span><strong>Discover something special today</strong><p>Before the proposal: Explore our latest products.</p><p>Updated through the connected branch after the merchant’s merge; not published.</p></div>\n<div><span class=\"proof-label\">Current · Live storefront</span><strong>Browse our latest products</strong><p>The original theme is not connected to this GitHub branch.</p><p>Its headline remains unchanged in the final comparison.</p></div>\n</div>\n\n**Important scope of this evidence:** the unchanged live storefront follows from this store’s separate theme connections. It is not a blanket guarantee that merging into any GitHub branch cannot affect a live theme. If a merchant connects a branch to a published theme, Shopify’s native integration can synchronize that branch to the published theme. The merchant must choose and verify the destination before merging.\n\nRecorded repository and PR: `MK-XXXVII/shopigent-kosmos-theme`, PR #2. The screencast provides the visible diff and merge evidence; direct repository access may require GitHub authorization. No reviewer credentials are published on this page.\n\n## Review scope\n\nThis page addresses **item (a)**: how AI-assisted theme proposals are implemented and the scope of the GitHub functionality. **Item (b) was marked resolved by Shopify** and is not reopened here. This evidence page does not imply Shopify has accepted the resolution; the review decision remains with Shopify.\n"},{"slug":"reference/scopes-and-permissions","title":"Scopes & Permissions Reference","tags":["reference","scopes","permissions"],"body":"\n# Scopes & Permissions Reference\n\nTwo layers of scoping protect your store: **Shopify OAuth scopes** (what the app itself may access) and **Shopigent category toggles** (what your agents may access). An agent can never exceed either layer.\n\n## Category → Shopify scope map\n\n| Shopigent category | Read scope | Write scope |\n|---|---|---|\n| Products | `read_products` | `write_products` |\n| Orders | `read_orders` | `write_orders` |\n| Customers | `read_customers` | `write_customers` |\n| Discounts | `read_discounts` | `write_discounts` |\n| Content (pages/blogs) | `read_content` | `write_content` |\n| Metaobjects & Custom Data | `read_metaobjects` | `write_metaobjects` |\n| Theme Pull Requests | app-internal GitHub repository connection | app-internal GitHub repository connection |\n| Files / Media upload | `read_files` (required) | `write_files` (required) |\n| Inventory | `read_inventory` | `write_inventory` |\n| Fulfillments | `read_fulfillments` | `write_fulfillments` |\n| Translations *(Pro)* | `read_translations` | `write_translations` |\n| Publications | `read_publications` | `write_publications` *(optional)* |\n\n### Optional publication access\n\n`read_publications` remains part of Shopigent's required read access. The separate `write_publications` scope is optional and lets Shopigent publish or unpublish resources on a sales channel selected by the user. It is not required for the rest of the tool catalog: product, order, content, media, and other enabled tools continue to work when publication access is not granted.\n\nTo enable it, open **Scopes & Permissions** in the embedded app, find **Product publication management**, and choose **Enable product publication management**. Shopify then asks the merchant to approve this scope. The embedded app reports the verified live grant; declaring the optional scope in app configuration does not grant it. A merchant may decline the request or later choose **Revoke publication access** without disabling the other tools.\n\nPublication targets are always selected explicitly from the IDs and channel labels returned for that store. Shopigent does not infer a channel from its name, choose an \"Online Store\" automatically, or publish to every channel.\n\nShopigent does **not** request Shopify's direct theme scopes. Theme repository\nwork uses the four `github_*` tools through the Shopigent Connector Public\nGitHub App or an optional merchant-supplied fine-grained PAT. Shopigent reads\nexplicit files and, after dry-run and human confirmation, can create a branch,\ncommits, and a pull request. It never merges, deploys, publishes, or edits theme\ncode through the Admin Theme API. After the merchant merges, Shopify's native\nGitHub theme integration can synchronize that connected branch to the\nmerchant-selected theme; use an unpublished theme for review so the live\nstorefront remains unchanged.\n\n## File scopes for media upload\n\n`upload_product_media` requires a **verified** live grant containing\n`write_products`, `read_files` and `write_files`. A configured or stored scope\nstring is never proof of authorization — only a live OAuth grant snapshot counts.\n\n`read_files` and `write_files` are declared as required scopes in the app\nconfiguration. Together they cover the staged upload workflow:\n\n1.  **stagedUploadsCreate** — request signed upload targets from Shopify.\n2.  **Binary upload** — PUT each file to its signed target.\n3.  **fileCreate** — register the uploaded files as Shopify MediaImage records.\n4.  **File-status polling** — wait for Shopify to process each image to READY.\n5.  **productSet (attach)** — attach images to a product in gallery order and set the featured index.\n\nA verified live grant of both `read_files` (file-status polling) and\n`write_files` (staged upload + registration) is required; requesting one without\nthe other is not enough.\n\n### Four dashboard states (never conflated)\n\nShopigent's embedded app distinguishes four layers that the dashboard surfaces\nseparately:\n\n| Layer | Means | Example state |\n|-------|-------|---------------|\n| Tool enabled | The merchant toggled `upload_product_media` on in Curated Tools | Checkbox == on |\n| Requested | The app configuration declares `read_files` and `write_files` | Process.env.SCOPES includes both |\n| Granted | The store's *live* Shopify installation actually granted `read_files` and `write_files` | Verified OAuth snapshot |\n| Executable | All four layers satisfied | Green badge: \"Media upload is available\" |\n\nWhen the live grant is stale or unverifiable, the dashboard shows\n**\"Reauthorization required\"** and an exact list of missing scope handles\n(`read_files`, `write_files`, `write_products`) rather than a vague \"access\" label.\nAn enabled toggle is never proof of Shopify authorization — a store may have\nthe tool on but the scope not yet granted.\n\nSee the [Troubleshooting guide](/guides/troubleshooting-faq#missing-scope) for\nsteps to resolve a `MISSING_SCOPE` error.\n\n## How the layers interact\n\n```\nAgent calls tool\n   │\n   ├─ 1. Is the category enabled in Curated Tools?   ── no → tool not even listed\n   ├─ 2. Does the plan allow this tool type?          ── no → plan_upgrade_required\n   ├─ 3. Does the app hold the Shopify scope?         ── no → scope_missing\n   ├─ 4. Is it destructive?                           ── yes → confirmation gate\n   └─ 5. Execute → record in audit log\n```\n\n## Principle of least privilege\n\n- Start with only the categories you need — you can enable more later without reinstalling.\n- Prefer separate API keys per agent/client, so revoking one doesn't break the others.\n- Review the audit log after enabling a new category to see how your agent uses it.\n"},{"slug":"reference/tools","title":"Tools Reference","tags":["reference","tools"],"body":"\n# Tools Reference\n\nShopigent exposes **86 distinct seeded merchant tools** across nine categories. Each category can be toggled on/off per store, and sensitive write tools pass through the confirmation gate. Runtime-only connection identity and capability utilities (`get_connection_identity`, `get_connection_capabilities`, registered by the MCP server rather than seeded) are listed separately and are not included in the 86-tool catalog count.\n\n> Tools are *curated operations*, not raw API passthrough — inputs are validated, outputs are trimmed to what agents actually need, and destructive calls require human approval.\n\n## Plans at a glance\n\n| Plan | Daily calls | Access |\n|------|-------------|--------|\n| Free | 25/day | Read-only (queries) |\n| Growth | 500/day | All writes except premium tools |\n| Pro | Unlimited | Everything, including general Shopify resource translations |\n\n**Premium (Pro-only) tools:** `set_translations`, `get_translations`, `delete_translations`.\n\n---\n\n## Products (31)\n\n| Tool | Type | Plan | What it does |\n|------|------|------|--------------|\n| `list_products` | Read | Free | Paginated list of products, optionally filtered by a search query. |\n| `search_products` | Read | Free | Full-text search across product titles, descriptions, and tags with relevance scoring. |\n| `get_product_by_id` | Read | Free | Fetch a single product by its Shopify GID. |\n| `create_product` | Write | Growth | Creates a product with optional description, status, vendor, type, tags, options, and default-variant price. |\n| `update_product` | Write | Growth | Updates a product's fields including title, description, status, vendor, type, tags, SEO, handle, and template (templateSuffix / clearTemplateSuffix). |\n| `delete_product` | Write | Growth | Permanently deletes a product. Irreversible. |\n| `create_product_variant` | Write | Growth | Adds a variant with price, SKU, barcode, and option values to an existing product. |\n| `update_product_variant` | Write | Growth | Sets SKU, price, barcode, and option values on an existing product variant. |\n| `update_product_variant_price` | Write | Growth | Sets the price of a single product variant by its GID. |\n| `update_product_variant_weight` | Write | Growth | Safely updates only a variant's shipping weight. Supports grams, kilograms, ounces, and pounds; live writes always require confirmation. |\n| `bulk_update_prices` | Write | Growth | Updates prices for multiple variants at once. |\n| `update_product_images` | Write | Growth | Manages product images (add, update alt text, delete) via the Shopify Media API. |\n| `upload_product_media` | Write | Growth | Uploads media to a product using Shopify's staged-upload flow. **Prerequisites:** a verified live grant containing `write_products`, `read_files` and `write_files`. Requires confirmation. |\n| `get_product_media` | Read | Free | Lists media attached to a product. |\n| `get_product_publications` | Read | Free | Lists where a product is published (channels, online store, etc.). |\n| `list_publications` | Read | Free | Lists this store's sales-channel publications, channel labels, and authoritative IDs for explicit selection. |\n| `publish_product_to_channel` | Write | Growth | Publishes one product to one explicitly selected publication after a dry-run and mandatory human confirmation. |\n| `get_product_metafields` | Read | Free | Reads metafields attached to a product. |\n| `set_product_metafields` | Write | Growth | Writes or updates one or more product metafields. |\n| `get_store_info` | Read | Free | Returns store-level information: name, email, currency, timezone, and plan. |\n| `list_collections` | Read | Free | Lists all collections (manual + automated) with id, title, handle, and sort order. |\n| `get_collection_by_id` | Read | Free | Fetches a single collection by its GID, including description, image, product count. |\n| `create_collection` | Write | Growth | Creates a new manual or automated collection. |\n| `update_collection` | Write | Growth | Updates a collection's title, description, handle, sort order, and/or SEO. |\n| `delete_collection` | Write | Growth | Deletes a collection by its GID. |\n| `add_products_to_collection` | Write | Growth | Adds one or more products to a collection. |\n| `remove_products_from_collection` | Write | Growth | Removes one or more products from a collection. |\n| `update_collection_image` | Write | Growth | Adds, updates, or deletes a collection's image. |\n| `get_translations` | Read | Pro | Reads all translatable content for a resource (product, collection, page, etc.) in a locale. |\n| `set_translations` | Write | Pro | Writes or updates translation values for a resource in a locale. |\n| `delete_translations` | Write | Pro | Removes translation overrides for given keys in a locale. |\n\n### Publication tools: exact contracts\n\n#### `list_publications`\n\nUse this read-only tool before publishing to obtain publication IDs and the channel names and handles that belong to the connected store. The user or agent must choose one returned `publicationId` explicitly; Shopigent does not select a target by matching a channel name.\n\nInputs:\n\n| Field | Required | Rules |\n|---|---|---|\n| `first` | No | Number of publications per page; defaults to 25 and is capped at 50. |\n| `after` | No | Opaque pagination cursor from the previous `pageInfo.endCursor`. |\n| `catalogType` | No | Exact filter: `APP`, `COMPANY_LOCATION`, or `MARKET`. |\n\nThe result contains `publications[]` with each publication's ID, automatic/future-publishing flags, catalog identity, and `channels[]` (`id`, `name`, `handle`, `specificationHandle`, and app identity when available), plus `pageInfo.hasNextPage` and `pageInfo.endCursor`. It requires publication read access and performs no write or confirmation flow.\n\n#### `publish_product_to_channel`\n\nThis compound write establishes one publication edge for one product. It requires an authoritative live grant for both `writeProducts` and `writePublications`; a configured or cached scope is not enough. If either capability is missing or cannot be verified, the call fails closed before any write. `write_publications` is optional and can be enabled or revoked from **Scopes & Permissions** without affecting the rest of the catalog.\n\nInputs:\n\n| Field | Required | Rules |\n|---|---|---|\n| `productId` | Yes | Canonical `gid://shopify/Product/...` ID. |\n| `publicationId` | Yes | Canonical `gid://shopify/Publication/...` ID selected from `list_publications`. |\n| `activateProduct` | Yes | Explicit boolean. No default: the user decides whether a draft product may become active. |\n| `idempotencyKey` | Yes | Stable 8–128 character key using letters, numbers, `.`, `_`, `:`, or `-`. |\n| `stateFingerprint` | Confirmed call only | Server-issued state fingerprint from the preview; prevents execution of a stale plan. |\n\nBefore any mutation, the tool verifies that the product and publication belong to the connected store and reads the current product status and target publication edge. A `dryRun: true` call returns that product, the selected publication, the intended final state, and a state fingerprint, with zero mutations.\n\nEvery live call requires human confirmation even if a store-level confirmation toggle is off. The confirmation is bound to the store, tool, product ID, publication ID, activation choice, idempotency key, and state fingerprint. The confirmed call must resend the exact fields requested by the preview together with `confirmed` and the confirmation token. Expired, replayed, mismatched, or stale confirmations are rejected.\n\nIdempotency is scoped to the store and this tool. Reusing a key for a different target is rejected. A retry reads live state rather than trusting an earlier audit entry; if a merchant changed a previously successful target afterward, the caller must use a new key instead of silently restoring that state.\n\nThe workflow publishes the selected edge first when possible and activates the product only when the confirmed `activateProduct` choice requires it. Success is reported only after readback confirms the requested state. If a later step fails after this operation created the edge, compensation may remove **only that newly created target edge** and roll back a status change made by the same operation. It never removes a pre-existing edge. Partial or unknown final states return a structured error with the failed phase, final readback when available, mutations attempted, and compensation results; they are never reported as successful publication.\n\nThis tool does **not** change product media, prices, inventory, SEO, tags, templates, translations, or any other channel. It does not accept a channel name, a publish date, multiple publication IDs, or an \"all channels\" option.\n\n### `upload_product_media` — capability contract and retry semantics\n\n#### Prerequisites\n\nThis tool requires a **verified** live OAuth grant that includes\n`write_products`, `read_files` and `write_files` (see the [Scopes reference](/reference/scopes-and-permissions#file-scopes-for-media-upload)).\nNeither a configured scope string nor a stored offline session scope counts\nas proof — only an authoritative live-grant snapshot from Shopify is accepted.\nIf any of these prerequisites is missing from the live grant, the call fails *before* the\nupload payload is decoded, before any staged target is requested, and before a\nconfirmation token is issued.\n\n#### Capability response\n\nThe server's `get_connection_capabilities` tool returns `uploadProductMedia:\ntrue` only when a **verified** live grant contains both prerequisites. The\nresponse also includes a `capabilityGaps` object with per-tool detail:\n\n```json\n{\n  \"uploadProductMedia\": {\n    \"available\": true,\n    \"missingScopes\": [],\n    \"scopeSource\": \"live_grant\"\n  }\n}\n```\n\nWhen a scope is missing, `missingScopes` lists the exact handles\n(`write_products`, `read_files`, `write_files`) and `scopeSource` is `live_grant` — the\ninformation is authoritative. When the live grant cannot be read (network\nfailure, Shopify unavailable), `scopeSource` is `fallback`, `missingScopes`\nis empty, and `available` is `false` — the tool never pretends a scope is\ngranted when it cannot verify. Configured or declared scopes in the app's\nenvironment are never reported as proof of authorization.\n\n#### Confirmation gate\n\n`upload_product_media` always requires human confirmation. The dry-run\npreview (`dryRun: true`) validates the input and returns the upload plan\n(files, staging targets per file, order) without executing anything. Every\nlive call that passes the capability gate issues a signed, single-use\nconfirmation token bound to:\n- the shop\n- the tool\n- an args-hash of the complete payload (product ID, files, featured index)\n\nThe initial confirmation response includes a `content.resendRequired` field\nset to `\"full_identical_payload\"`. The agent must present the **complete\nidentical payload** together with the confirmation token; a token alone is\nnot enough to resume after expiry. This is an explicit design choice\n(SH-014 Option A was chosen over Option B): the server does not store upload\npayloads, so every retry after a 25-minute token TTL must re-send the full\nfiles and arguments. The confirmation gate accepts a previously used token\nfor retry purposes as long as the args hash matches, the shop matches, and\nthe token is not expired — this allows the agent to retry the identical call\nafter a partially completed workflow without re-confirming.\n\n#### Retry contract with idempotency\n\nThe upload workflow uses idempotency keys across the multi-step pipeline:\n\n- **Idempotency is key-based.** Reusing the same idempotency key on a\n  previously successful call returns the prior result without creating\n  duplicate files. The server caches completed results for one hour.\n- **A mismatched payload on the same key** is rejected before any upload.\n- **A key used on a different store** is independent (idempotency is\n  scoped to the store + key).\n- **Partial/failed idempotent retries** resume from the last safe\n  checkpoint. If files were already created by a prior attempt, the retry\n  skips stagedUploadsCreate, binary upload, and fileCreate — it goes\n  directly to file-status polling and attachment. Duplicate files are\n  prevented.\n- **When the upload completes but the product attachment step (productSet)\n  fails**, the response includes `reconciliationRequired: true` and the\n  created file IDs, so the agent can re-attach them with the same\n  idempotency key.\n\n#### Observability stages\n\nEach upload emits a structured JSON log entry at every pipeline stage:\n\n1. `stagedUploadsCreate` — requesting signed targets\n2. `confirmation_issued` — token created with args-hash binding\n3. `binary_upload` — PUT'ing each file (per-file reporting)\n4. `fileCreate` — registering uploaded files as MediaImage records\n5. `file_status_polling` — waiting for READY status (with bounded timeout)\n6. `productSet` — attaching to product gallery in order\n7. `final_readback` — confirming the expected gallery state\n\nThese logs carry the stage name, shop ID, operation ID, product ID, file\ncount, and (on error) a sanitized diagnostic excerpt and Shopify request ID.\nThey never contain tokens, headers, confirmation tokens, base64 payloads,\nor staged target parameters. See [Security & Trust](/guides/security-and-trust)\nfor the logging rules.\n\n## Content (16)\n\n| Tool | Type | Plan | What it does |\n|------|------|------|--------------|\n| `list_pages` | Read | Free | Lists all pages with id, title, handle, and status. |\n| `get_page_by_id` | Read | Free | Fetches a single page by its GID, including body and SEO metadata. |\n| `create_page` | Write | Growth | Creates a new online store page. |\n| `update_page` | Write | Growth | Updates a page's title, body, and/or handle. |\n| `delete_page` | Write | Growth | Deletes a page by its GID. |\n| `list_blogs` | Read | Free | Lists all blogs with id, title, handle, and comment policy. |\n| `get_blog_by_id` | Read | Free | Fetches a single blog by its GID, including its articles and metadata. |\n| `create_blog` | Write | Growth | Creates a new blog. |\n| `update_blog` | Write | Growth | Updates a blog's title and/or handle. |\n| `delete_blog` | Write | Growth | Deletes a blog by its GID. |\n| `list_articles` | Read | Free | Lists all blog articles for a blog, with optional filters. |\n| `get_article_by_id` | Read | Free | Fetches a single blog article by its GID, including body, summary, tags, author. |\n| `create_article` | Write | Growth | Creates a new blog post (article) under a blog. |\n| `update_article` | Write | Growth | Updates a blog post's title, body, summary, handle, tags, author. |\n| `delete_article` | Write | Growth | Deletes a blog post by its GID. |\n| `update_article_image` | Write | Growth | Adds, updates, or deletes a blog article's featured image. |\n\n## Metaobjects / Custom Data (15)\n\nAccess to **Custom Data** (metaobjects & metafield definitions) requires a dedicated scope category in **Scopes & Permissions**.\n\n| Tool | Type | Plan | What it does |\n|------|------|------|--------------|\n| `list_metaobjects` | Read | Free | Lists metaobjects of a given type. |\n| `list_metaobject_definitions` | Read | Free | Lists metaobject definitions. |\n| `get_metaobject` | Read | Free | Fetches a single metaobject by its GID. |\n| `create_metaobject` | Write | Growth | Creates a new metaobject. |\n| `update_metaobject` | Write | Growth | Updates an existing metaobject. |\n| `delete_metaobject` | Write | Growth | Deletes a metaobject. Destructive. |\n| `get_metaobject_definition` | Read | Free | Fetches a single metaobject definition. |\n| `create_metaobject_definition` | Write | Growth | Creates a metaobject definition. |\n| `update_metaobject_definition` | Write | Growth | Updates a metaobject definition. |\n| `delete_metaobject_definition` | Write | Growth | Deletes a metaobject definition. Destructive. |\n| `list_product_metafield_definitions` | Read | Free | Lists metafield definitions scoped to products. |\n| `get_metafield_definition` | Read | Free | Fetches a single metafield definition. |\n| `create_metafield_definition` | Write | Growth | Creates a metafield definition. |\n| `update_metafield_definition` | Write | Growth | Updates a metafield definition. |\n| `delete_metafield_definition` | Write | Growth | Deletes a metafield definition. Destructive. |\n\n\n## Orders (6)\n\n| Tool | Type | Plan | What it does |\n|------|------|------|--------------|\n| `list_orders` | Read | Free | Paginated list of orders, filterable by status/date/tags. |\n| `search_orders` | Read | Free | Full-text search across orders by number, customer name, or email. |\n| `get_order` | Read | Free | Fetches a single order by its GID (line items, addresses, tags, status). |\n| `create_order` | Write | Growth | Creates a draft order with line items and customer info. |\n| `update_order` | Write | Growth | Updates editable order fields: tags, note, and/or email. |\n| `refund_order` | Write | Growth | Issues a refund on an order. Irreversible financial action. |\n\n## Customers (5)\n\n| Tool | Type | Plan | What it does |\n|------|------|------|--------------|\n| `list_customers` | Read | Free | Lists store customers with optional filters. |\n| `search_customers` | Read | Free | Full-text search across customers by name, email, or phone. |\n| `get_customer` | Read | Free | Fetches a single customer by GID (name, email, phone, tags, note). |\n| `create_customer` | Write | Growth | Creates a new customer. |\n| `update_customer` | Write | Growth | Updates a customer's tags or note. |\n\n## Discounts (4)\n\n| Tool | Type | Plan | What it does |\n|------|------|------|--------------|\n| `list_discounts` | Read | Free | Lists store discounts (discount nodes). |\n| `get_discount` | Read | Free | Fetches a single discount by its GID node id. |\n| `create_discount` | Write | Growth | Creates a new discount code or automatic discount. |\n| `delete_discount` | Write | Growth | Deletes a discount by its GID. |\n\n## Fulfillments (4)\n\n| Tool | Type | Plan | What it does |\n|------|------|------|--------------|\n| `list_fulfillment_orders` | Read | Free | Lists store fulfillment orders. |\n| `get_fulfillment_order` | Read | Free | Fetches a single fulfillment order by its GID. |\n| `close_fulfillment_order` | Write | Growth | Closes a fulfillment order (marks it fulfilled/complete). |\n| `open_fulfillment_order` | Write | Growth | Re-opens a closed fulfillment order. |\n\n## Inventory (1)\n\n| Tool | Type | Plan | What it does |\n|------|------|------|--------------|\n| `update_inventory_quantity` | Write | Growth | Sets the available inventory quantity for an item at a location. |\n\n## Theme Pull Requests (4)\n\nThe **Theme Pull Requests** category connects a designated theme repository through the **Shopigent Connector** Public GitHub App (operated by Shopigent and limited to the selected repository) or an optional merchant-supplied fine-grained PAT. Shopigent reads only explicitly requested files. After MCP dry-run and human confirmation, `github_create_theme_pr` creates a branch, commits the declared changes, and opens a pull request. Valid paths include `locales/*.json`, `templates/*.json`, `sections/snippets/blocks/*.liquid`, assets, and `config/settings_data.json`. Shopigent never merges the PR, deploys or publishes a theme, or edits Shopify theme code through the Admin Theme API. The merchant reviews and merges. Shopify's native GitHub theme integration then synchronizes the connected branch to the merchant-selected theme. Reviewer demonstrations use an unpublished connected theme so the live storefront remains unchanged; publication remains merchant-controlled.\n\n| Tool | Type | Plan | What it does |\n|------|------|------|--------------|\n| `github_theme_connection` | Read | Free | Returns the designated repository connection (owner/repo/defaultBranch) without exposing tokens. |\n| `github_list_theme_branches` | Read | Free | Lists branches on the connected repository. Read-only. |\n| `github_theme_file` | Read | Free | Reads one explicitly named repository file at a ref and returns path, branch, SHA, and content. |\n| `github_create_theme_pr` | Write | Growth | Creates a branch, commits the declared file changes, and opens a PR on the connected theme repo. PR-only — never merges, deploys, or publishes. Confirmation required (approved in your AI client); dry-run available. |\n\n## Runtime utilities (not counted in the 86-tool catalog)\n\n`get_connection_identity` and `get_connection_capabilities` are registered directly by the MCP server (not seeded as catalog tools) and provide connection metadata only. They are excluded from the published catalog count. (`get_store_info` is a seeded catalog tool and is counted above.)\n\n## Cross-cutting features\n\n- **Dry-run** — every write tool accepts `dryRun: true` to preview the exact mutation without executing.\n- **Confirmation gate** — write and destructive calls return a signed, single-use `confirmation_pending` result; the human approves **in their AI client**, and the agent re-calls the tool with the confirmation token before anything executes. General translation writes and `github_create_theme_pr` are gated.\n- **Audit log** — every call is recorded with input, result, and latency.\n- **Scope-based** — each category maps to its own OAuth scope category; enable only what your agent needs (least privilege)."},{"slug":"terms-of-service","title":"Terms of Service","tags":["legal","terms"],"body":"\n# Shopigent — Terms of Service\n\n**Last updated:** 2026-07-24 | **Provider:** Greek Nous | **Contact:** shopigent@greeknous.com\n\n## 1. Acceptance\nBy installing or using Shopigent (\"the App\") you agree to these Terms. The App is provided as-is, without warranty, for use with your Shopify store.\n\n## 2. Plans and billing\nThe App offers Free, Growth, and Pro plans. Plan limits (e.g. daily tool-call allowances, available tools) are enforced as described in the App. Paid plans are billed through Shopify's billing API; cancelling reverts the store to the Free plan. We do not store card details. An Agency (multi-store) plan is planned but not yet available.\n\n## 3. Use of tools\nThe App exposes operations over your Shopify store. You are responsible for the actions your agents perform. Destructive operations (create/delete/refund/etc.) require an explicit confirmation step before execution. You should review audit logs regularly.\n\n## 4. Scope authorization\nThe App only performs operations your store has authorized via Shopify OAuth scopes. Enabling a tool does not grant new Shopify scopes; it only makes an already-authorized operation available to your agents.\n\n## 5. Acceptable use\nYou agree not to use the App to violate Shopify's Acceptable Use Policy, applicable law, or the rights of others. We may suspend access for abuse.\n\n## 6. Limitation of liability\nThe App is provided \"as is.\" To the maximum extent permitted by law, Greek Nous is not liable for indirect or consequential damages arising from use of the App, including merchant actions performed via AI agents.\n\n## 7. Termination\nEither party may terminate use by uninstalling the App. Upon uninstall, store data handling follows our Privacy Policy.\n\n## 8. Contact\nQuestions: shopigent@greeknous.com\n"}]}