Skip to content
littleworksdocs

Explore the documentation

Meet LittleworksA little backend for what you’re building on Shopify.Connect to LittleworksChoose the CLI, a plugin, or a remote MCP connection.CLIConnect from your terminal with Shopify approval and no manual tokens.Claude pluginThe Littleworks MCP connection and agent guidance in one package.OpenAI pluginThe Littleworks MCP connection and agent guidance in one package.MCP with OAuthConnect a compatible client directly, without a marketplace plugin.Build with an agentThe operating guide for agents building on Shopify with Littleworks.Write a workA JavaScript handler, a small manifest, and a version you test and then publish.Keep secretsEncrypted credentials, shared across your store’s works.Call external servicesMake public HTTPS API requests from a work using http.fetch().Store dataDocument collections with a small API, scoped automatically to the work that uses them.Call ShopifyCall Shopify’s Admin and Storefront GraphQL APIs with credentials held by Littleworks.Expose an endpointConnect an existing frontend to a work through a small JSON API.Customer access and invitationsRequire a signed-in shopper or a narrow, expiring invitation before a work runs.RecipesUseful things to build for your store, with the backend already taken care of.Product reviewsCollect customer reviews, verify purchases, and publish approved content directly into your Shopify theme.Customer wishlistsGive signed-in customers a persistent list of products they can revisit across devices.Customer quote requestsCollect a customer’s products, quantities, and requirements without turning a request into an order.Build a merchant pageDescribe your records and what merchants do with them; Littleworks renders a native Shopify admin page.Run works on their ownRun a work when something happens in the store, on a schedule, or from a Shopify Flow workflow.MCP tool referenceTools to inspect, deploy, run, and organize the backend for a connected store.Usage and allowancesSee what your works use, how much capacity remains, and when allowances reset.Inspect and troubleshootFind the relevant run, understand the failure, and make the next change deliberately.Limits and securityThe current runtime boundaries, data isolation model, and execution allowances.
Shopify admin
Build
Markdown

Run works on their own

Run a work when something happens in the store, on a schedule, or from a Shopify Flow workflow.

Most works run when something calls them: a storefront request, a button on a merchant page, or an agent. Automations are the other half of most builds, such as “when this happens” or “every morning”. A published work can run when a Shopify event happens, on a schedule in the store’s time zone, or from a merchant’s Shopify Flow workflow.

TriggerRunsExample
{"type": "event", "topic": …, "when"?: …}when something happens in the storeemail a waiting list when a product is back in stock
{"type": "schedule", "cron": …}on a schedule, in the store’s time zonea weekday 8:00 digest of new quote requests
{"type": "flow"}from the “Run a Littleworks work” action in Shopify Flowaward loyalty points in a merchant’s order workflow

Shopify events

An event work names a Shopify topic and, optionally, a when filter on the event’s payload. Events that don’t match are skipped before a run starts and cost nothing.

Manifest
{
  "name": "back_in_stock.notify",
  "feature": "back_in_stock",
  "title": "Notify signups when back in stock",
  "trigger": { "type": "event", "topic": "inventory_levels/update", "when": { "available": { "gt": 0 } } },
  "permissions": { "shopify": true }
}
Source
export default async ({ input, db, shopify, log }) => {
  const { payload } = input;
  // Inventory events carry the inventory item, not the product: look it up.
  const found = await shopify.admin.graphql(
    `query ($id: ID!) { inventoryItem(id: $id) { variant { product { id title } } } }`,
    { id: "gid://shopify/InventoryItem/" + payload.inventory_item_id });
  const product = found.data?.inventoryItem?.variant?.product;
  if (!product) return { notified: 0 };
  const signups = db.collection("signups");
  const waiting = await signups.list({ where: { productId: product.id, status: "waiting" }, limit: 100 });
  for (const signup of waiting.items) {
    // Send the email through the merchant's provider with http.fetch, then mark the signup
    // so a repeated delivery never emails anyone twice.
    await signups.patch(signup.id, { set: { status: "notified", notifiedAt: new Date().toISOString() } }, { revision: signup.revision });
  }
  log.info("Notified", waiting.items.length, "people that", product.title, "is back in stock");
  return { product: product.title, notified: waiting.items.length };
};
TopicWhenShopify permission
inventory_levels/updateinventory changes at a locationread_inventory
products/create, products/updatea product is created or changesread_products
collections/updatea collection changesread_products
orders/create, orders/paid, orders/fulfilled, orders/cancelled, refunds/createorder eventsread_orders
fulfillments/createa fulfillment is createdread_fulfillments
customers/createa customer is createdread_customers
  • Permissions. Publishing checks that the store granted the topic’s permission, and links to Shopify permissions if not.
  • Protected customer data. Order, fulfillment, refund and customer events carry protected customer data. They become available once Littleworks has Shopify’s approval to handle it; until then, publishing them explains why it can’t.
  • `when`. One to five conditions on payload fields, all of which must hold. Each is a value to equal, or an operator: in, gt, gte, lt, lte, ne or exists.
  • What the work receives. input is {event: {topic, id, triggeredAt, shop, attempt, previousRunIds}, payload}, where payload is Shopify’s event body. context.trigger is "event".
  • Subscriptions. Littleworks subscribes the store when the first published work for a topic appears, keeps the subscription healthy, and removes it when no work needs it.

How delivery works

  • Once per work. Littleworks records each Shopify delivery once and runs each matching published work at most once for it. Shopify can still send separate deliveries for the same change, so mark what a run has processed, such as notifiedAt above, and skip it next time.
  • Retries. A run that fails retries after 1 minute, 10 minutes, 1 hour and 6 hours. Each retry carries event.attempt and the earlier previousRunIds, so the work can check what already happened before repeating a change. A deliberate error response counts as handled.
  • Order. Events can arrive out of order. Compare event.triggeredAt or the payload’s updated_at with what you stored.
  • Paused works. Events that arrive while a work is paused are dropped and counted, not queued, so resuming never replays a burst of stale events.
  • Bursts and allowances. Runs count against the store’s run allowance, and skipped events are free. A burst of events, such as an inventory import, drains at most four runs at a time per store. If the allowance runs out, events wait up to 24 hours, then expire with a notice.

Schedules

Every weekday at 8:00, store time
"trigger": { "type": "schedule", "cron": "0 8 * * 1-5" }
  • Format. Five cron fields (minute, hour, day of month, month, day of week) in the store’s time zone. A schedule can run at most every 5 minutes; a 5-minute schedule uses 288 runs a day, so choose the least frequent one that does the job.
  • What the work receives. input is {schedule: {scheduledFor, timezone, cron}}, and each slot runs once.
  • Downtime and the clocks. After downtime, the latest missed slot runs once. When the clocks go forward, a skipped time runs at the next valid minute; when they go back, a repeated time runs once.

Shopify Flow

Shopify Flow is the merchant’s own automation tool, available on every paid plan. Littleworks adds one action to it, Run a Littleworks work. Agents can’t create Flow workflows, so the merchant adds the action in Flow.

A work Flow can run
"trigger": { "type": "flow" }
  • Run a Littleworks work. The action runs a published work whose trigger is {"type": "flow"}. The merchant enters the work’s name in Work and its fields in Input. The work receives those fields plus flow: {actionRunId}. It runs once per Flow action run, even when Flow sends the action again, and its result returns to Flow.
  • Input. Write one field per line, such as points: 50, using Flow variables as you like. Pass the workflow’s Shopify objects as fields: order_id: {{order.id}}, product_id: {{product.id}} or customer_id: {{customer.id}}. true, false, null and numbers keep their type, values starting with [ or { are JSON, a value in double quotes stays text, and dotted keys such as customer.email nest. Blank lines and lines starting with # are ignored. A JSON object works too. Flow fills in variables first, so a product title with quotes in it is just text.
  • Checked when you save. Littleworks checks the action when the workflow is saved: the work must exist, be published and run from Flow, and Input must have fields that fit what the work takes. Problems show on the Work or Input field in the Flow editor. Values from variables are checked when the workflow runs.
  • Setting it up. Agents that build a Flow work tell the merchant exactly what to add: the Run a Littleworks work action, the Work name, and example Input lines, such as points: 50 and order_id: {{order.id}}. Littleworks → Automations lists the works Flow can run, with each name to copy.
  • Starting workflows. Littleworks has no Flow triggers, so works can’t start Flow workflows. Start a workflow from one of Shopify’s triggers, such as Order created, and run a work from it.

Test, publish and watch

  • Test as a draft. invoke_function with trigger: {event: {topic, payload?}} or {schedule: {scheduledFor?}} builds the input exactly as a real delivery would. A missing payload uses a realistic sample for the topic. From the CLI: littleworks invoke back_in_stock.notify --event inventory_levels/update --payload restock.json or --schedule --at 2026-10-05T08:00:00-04:00. Test runs are recorded as tests, but Shopify calls and external requests are real.
  • Publish. publish_function subscribes the store or schedules the next run. get_function shows the subscription and the last seven days of events, or the next scheduled run.
  • Watch. list_events (CLI: littleworks events) shows each delivery and what it did for each work. A work can run, be skipped by when, be dropped while paused, wait for a retry, fail after retries, or expire. In Shopify admin, Littleworks → Automations lists every automation and its recent activity, and Runs shows what started each run.