Shopify · Admin API · Agent security
Shopify AI agent API key: scoping Admin API access so a stuck agent can't touch every order
Shopify's Admin API is powerful — an agent with full access can cancel orders, zero inventory, change prices, and issue refunds. Shopify's access scopes let you restrict a key to specific resource types, but they don't stop a stuck loop from touching every order in that category. This page covers what Shopify gives you natively, the three gaps that matter for autonomous agents, and the vault-key pattern for per-agent credential isolation.
TL;DR
Shopify's Custom App credentials support access scope restriction (e.g., read_orders only, not write_orders). That's a meaningful first layer. But for AI agents you also need a per-agent rate cap, a mid-run revoke without rotating the store token, and an audit log with agent context. A vault-key proxy fills those gaps: issue one vault key per agent run, attach a resource cap, and revoke it in one click if the agent goes rogue — without touching the underlying store credential.
How agents use the Shopify Admin API
The most common patterns are order processing agents (look up orders, cancel or fulfill them), inventory agents (read stock levels, restock recommendations), and customer service agents (look up order history, issue refunds). Using Shopify's official Node or Python client:
import { shopifyApi, ApiVersion } from '@shopify/shopify-api';
const shopify = shopifyApi({
apiKey: process.env.SHOPIFY_ACCESS_TOKEN,
apiSecretKey: process.env.SHOPIFY_API_SECRET,
scopes: ['read_orders', 'write_orders'],
hostName: 'your-store.myshopify.com',
apiVersion: ApiVersion.January25,
});
async function cancelOrderTool({ orderId, reason }) {
const client = new shopify.clients.Rest({ session });
await client.post({
path: `orders/${orderId}/cancel`,
data: { reason },
});
return `Cancelled order ${orderId}`;
}
The access token is scoped to write_orders, so the agent can cancel orders. The scope restriction prevents it from issuing refunds or modifying products. That's useful — but a stuck loop can still cancel every open order before the rate limiter fires, because Shopify's rate limit is per-shop, not per agent.
Shopify's native access scopes and what they protect
Shopify's Custom App credentials support granular access scopes across resources. The read/write split gives you meaningful control:
| Scope | What it allows | Recommended for agent? |
|---|---|---|
read_orders | Read order data, line items, fulfillment | Yes — read-only is safe |
write_orders | Cancel, update, fulfill orders | Only with per-agent cap |
write_products | Update prices, inventory, product details | Only with per-run expiry |
write_customers | Update customer records, merge accounts | Only with allowlist of allowed operations |
write_draft_orders | Create and modify draft orders | Moderate risk — draft orders can convert |
What scopes don't give you: a cap on how many orders the agent can touch in one run, the ability to revoke access mid-run without rotating the store token, or an audit log that joins Shopify API calls to agent_run_id.
Three failure modes specific to agent deployments
1. The bulk-cancellation loop. An agent is told to cancel orders with status "payment pending" older than 30 days. A bug in the date filter causes it to match all pending orders. The agent cancels 847 orders across 40 minutes — within Shopify's rate limit, which is per-shop, not per-agent. Access scopes don't help; a per-run cancellation cap would have stopped it at, say, 10.
2. The price-update drift. An agent with write_products is updating prices based on a competitor scrape. The scrape returns malformed data; the agent multiplies all prices by 100 instead of updating them. No scope prevents this — write_products is required for the task. A vault key with a per-run modification cap would have limited the blast radius.
3. The refund loop. A customer service agent issues a refund for a disputed order. Due to a state machine bug, the same dispute triggers the agent twice. Two refunds are issued. Shopify's API allows duplicate refunds if they're below the order total. An audit log showing both calls with the same dispute_id and agent_run_id is the only way to catch this in real time.
The vault-key pattern for Shopify agents
The vault-key pattern issues a scoped, time-limited proxy credential per agent run. The proxy holds the real Shopify access token and enforces the policy:
import { shopifyApi, ApiVersion } from '@shopify/shopify-api';
// Point the API host at the proxy
const shopify = shopifyApi({
apiKey: process.env.VAULT_KEY, // vault_key_xxx
apiSecretKey: process.env.SHOPIFY_API_SECRET,
scopes: ['read_orders', 'write_orders'],
hostName: 'proxy.keybrake.com/shopify/your-store',
apiVersion: ApiVersion.January25,
});
The vault key policy:
{
"vendor": "shopify",
"store": "your-store.myshopify.com",
"allowed_endpoints": [
"GET /admin/api/*/orders*",
"POST /admin/api/*/orders/*/cancel"
],
"max_write_operations_per_run": 10,
"expires_in": "2h",
"agent_run_id": "order_cleanup_run_abc"
}
With this policy, the agent can cancel at most 10 orders per run and the vault key expires after 2 hours. Every API call is logged with agent_run_id so post-run forensics are a single SQL query.
How Keybrake fits
Keybrake proxies Shopify Admin API calls the same way it proxies Stripe and Twilio: one vault key per agent run, a policy with endpoint allowlists and operation caps, and a queryable audit log. The Free tier covers 1,000 proxied requests/month; the Hobby tier ($29/month) adds all vendors and 30-day log retention.
Related questions
Does this work with Shopify's GraphQL Admin API as well as REST?
Yes. The proxy intercepts HTTP requests regardless of whether they're REST or GraphQL — both use the same access token and the same X-Shopify-Access-Token header. The endpoint allowlist in the vault key policy accepts GraphQL paths (e.g., POST /admin/api/*/graphql.json) or you can use the broader POST /admin/api/* pattern with a mutation-type allowlist.
What's the difference between a Custom App token and a Public App token for agent use?
Custom App tokens are simpler for agent deployments: they're issued per-store, have no OAuth redirect flow, and are revocable from the Shopify Partner dashboard. Public App tokens require OAuth installation per merchant and are harder to scope per-agent. For internal agents (your own store), Custom App tokens are the right primitive. Keybrake works with both — the vault key wraps either token type.
Can I set a per-run cap on the number of orders the agent can modify, not just the time window?
Yes. The vault key policy supports max_write_operations_per_run, which is a count of any state-changing API call (POST, PUT, DELETE, PATCH) in the vault key's lifetime. You can combine this with expires_in for a time-and-count dual cap. When the count is reached, the proxy returns a 429 with the remaining cap in the response headers.
Further reading
- AI agent kill switch patterns — four ways to stop a runaway agent mid-run and their real latencies.
- AI agent audit trail schema — the fields you need in a call log to reconstruct what an agent did in a given run.
- AI agent API key best practices — the complete checklist for scoping, rotating, and auditing every SaaS key your agent holds.
- AI agent cost management — decomposing the cost of an autonomous agent across LLM calls, SaaS API calls, and infrastructure.