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 an immutable version each time you deploy.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 ShopifyUse Shopify’s GraphQL API directly, 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.MCP tool referenceTen tools to inspect, deploy, run, and manage the backend for a connected store.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

Customer access and invitations

Require a signed-in shopper or a narrow, expiring invitation before a work runs.

Choose the proof your build needs

Use auth: "customer" for signed-in storefront customers, or auth: "token" for an invitation that permits a specific action. Public works accept anonymous requests. Merchant auth is for merchants and connected agents. All customer-facing modes use automatic traffic protection; logging in does not exempt a caller from limits.

A signed-in storefront customer

Declare an HTTP trigger with auth: "customer", GET or POST, and the exact storefront origin. The shared Shopify app proxy forwards /apps/littleworks/preview/your.work or /apps/littleworks/production/your.work to Littleworks. One proxy serves every work. Shopify can customize the proxy path; verify the installed path before wiring the frontend. Littleworks requires write_app_proxy, separately from optional Shopify data permissions.

Littleworks verifies Shopify’s query signature, timestamp and store, then requires a nonempty customer ID. The work receives context.customer.id as a Shopify customer GID. The direct /f/... URL and invoke_function cannot supply customer identity. GET input excludes Shopify’s proxy parameters. POST accepts JSON.

Read only the signed-in customer’s records
export default async ({ context, db }) => {
  return db.collection("requests").list({
    where: { customerId: context.customer.id },
  });
};
Call from the signed-in storefront
const response = await fetch("/apps/littleworks/preview/customer.requests", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({}),
});
if (response.status === 401) {
  // Ask the shopper to sign in using this store's customer login flow.
}

This mode supports storefront sessions where Shopify supplies logged_in_customer_id. Test the store’s actual customer-account setup; if Shopify supplies no customer ID, the request fails closed. Customer-account UI extensions and headless clients require separate identity integration and cannot use this mode to impersonate a shopper. CORS and Origin are not proof of identity.

An invitation for a guest

First deploy the receiving HTTP work with auth: "token". Then use a private callable or merchant HTTP work to issue an invitation after checking eligibility. A public, customer or token work cannot mint invitations, even when invoked through an agent. The issuer stays in the same store and environment as the target.

Issue after validating the order and product
const invitation = await auth.issueToken({
  work: "reviews.submit",
  claims: { orderId: verifiedOrderId, productId: verifiedProductId },
  expiresInSeconds: 86400,
  singleUse: true,
});
// Deliver invitation.token only to its intended recipient through an
// authorized integration. Never log it or store it in a public record.

The result contains token and expiresAt. Tokens are opaque bearer credentials: anyone possessing one can perform its permitted action. Only a token hash and encrypted claims are stored by Littleworks. Defaults are one hour and single use; expiry may be 60 seconds to seven days. Claims are limited to 4 KiB and stores may have 1,000 unexpired tokens, including consumed tokens until expiry. Keep claims minimal, using IDs rather than personal details.

Use the verified claims in the receiving work
export default async ({ input, context, db }) => {
  const { orderId, productId } = context.action.claims;
  return db.collection("reviews").create({
    orderId,
    productId,
    rating: input.rating,
    status: "pending",
  });
};

Send the token in Authorization: Bearer <token> to the target URL returned by deployment. It is never accepted from an input field or query parameter. For an email invitation, link to the build’s frontend with the token in the URL fragment; the frontend should read it, remove it from the address bar and send it in the Authorization header. Littleworks does not host that frontend. Fragments still need care: avoid exposing them to analytics or other scripts.

Each token binds to the exact store, environment, work, method and deployed version. Deploying new code invalidates invitations for previous versions; restoring that exact version can make its unexpired, unused invitations valid again. Pause the work to stop all new executions. Choose a reusable token only for a build that needs repeated access, with a suitably short expiry.

Input and admission failures do not consume a single-use token. Admission and consumption are atomic, so concurrent requests cannot use it twice. Once execution starts, it stays consumed even if the work fails or returns an error, because earlier effects may have completed. Inspect the run before issuing another invitation. Tokens and customer login do not make external effects transactional.

Automatic protection

Littleworks limits bursts, simultaneous runs, per-work and store execution, stored data, and external requests. See Limits and security. Rejected admissions create no run and spend no run allowance. Littleworks HTTP 429 for a time-based allowance includes Retry-After and a retry time; storage needs space freed instead. Edge flood blocks may return a non-JSON response and appear only in Cloudflare security events. Back off and never automatically replay a mutation. Shopify shows traffic notices on affected works and explanations on failed runs.