Skip to content
toolboxPOD
  • Shirts
  • Pricing
  • For AI
  • Shopify
  • Developers
  • Sign in
  • Sign up
Sign inSign upOrder a shirt

Developers

Developer guides

Connect your store, website or AI agent to artwork, designs, orders, tracking and signed webhooks. Orders cost the same as on the website, with no API fee.

API reference →Manage API keys

On this page

  1. Getting started
  2. Artwork to order
  3. Webhooks
  4. Import a Shopify store
  5. AI agents and MCP
  6. API reference

Resources

  • API reference
  • OpenAPI JSON
  • MCP setup (Markdown)
  • Manage API keys
On this page
  1. Getting started
  2. Artwork to order
  3. Webhooks
  4. Import a Shopify store
  5. AI agents and MCP
  6. API reference

Getting started

The account Owner makes API keys under Developers in the dashboard. Each key has scopes and is bound to stores, and a key is shown once: only its hash is stored. Keep it in your secret manager, never in an agent’s instructions. To rotate one, press Rotate next to it under Developers: a new key with the same name, scopes and stores replaces it, and the old one stops working at once.

Start with a sandbox key (sandbox keys start with pod_test_). It runs the same API, but nothing is charged, printed or emailed, and it never changes a live Shopify store. A production key (pod_live_…) does real work. Check what a key carries before you send orders:

Check the key
curl https://toolboxpod.com/api/v1/me \
  -H "Authorization: Bearer $TOOLBOX_POD_KEY"

Sandbox orders

Purchase a sandbox order with testOutcome (succeed, decline or uncertain) to choose the result. Nothing ships it on its own: POST /api/v1/orders/{orderId}/simulate with ship, deliver or close gives a paid sandbox order a TEST package and the same status changes and webhooks a production order gets. Activating a product mapping or publishing a product needs a production key (403 practice_mode_live_store).

Buying with a production key

A production purchase also needs the Owner to turn on purchasing for the integration and store, under a spending limit. Keys never manage cards, staff or spending limits.

Stores for an agent

An Owner can issue a stores:setup bootstrap key. POST /api/v1/stores with an Idempotency-Key creates an API store and returns its own key once; an exact replay returns the IDs without the secret, so if that answer is lost the Owner rotates the new key. It cannot grant scopes it does not have.

Errors and limits

StatusMeans
401The key is missing, unknown or revoked.
403A scope is missing, or a sandbox key tried to change a live store.
404Not found, or not visible to this key.
409The request conflicts with the current state.
422The input is invalid, or names a field or list filter the call does not take (unknown_field, invalid_query).
429Too many requests: wait as long as Retry-After says.

Every error carries a code and a message, and every response an x-request-id to quote to support. Per key and minute: 600 reads, 120 writes and 20 purchases.

Artwork to order

  1. GET /api/v1/catalog/garmentsThe garments, colors and sizes: use the codes it returns. GET /api/v1/catalog/rates has the prices and where we ship.
  2. POST /api/v1/artworkUpload a PNG, JPEG or WebP: the raw bytes, a multipart file, or JSON with an HTTPS url or base64. Same quality checks as the website.
  3. POST /api/v1/designsPlace it on the shirt. With approve: true (scope designs:activate) it is approved in the same call. Wait for production.state to be registered (usually seconds) before you buy.
  4. POST /api/v1/ordersOne recipient, a store the key may use and your own externalReference. It comes back quoted, with the offer to accept. The same reference with a different body is refused (409).
  5. POST /api/v1/orders/{orderId}/purchasePay it: send the offer back as accepted, with an Idempotency-Key. After an unclear answer (timeout, 5xx), retry with the same key and body. A refusal before any payment (a 409 such as stale_quote, which carries the fresh offer to pay, or a 422) frees the key, so you may send the corrected request with it. Once a payment was tried, the key replays its result: retry a held order with a new key.
  6. GET /api/v1/orders/{orderId}Status, packages and tracking, or let the webhooks below tell you.
From artwork to a paid sandbox order
AUTH="Authorization: Bearer $TOOLBOX_POD_KEY"

# 1. Upload the artwork: the answer carries its id (art_…)
curl https://toolboxpod.com/api/v1/artwork -H "$AUTH" \
  -H "Content-Type: image/png" --data-binary @artwork.png

# 2. Place it on the shirt and approve it in one call
curl https://toolboxpod.com/api/v1/designs -H "$AUTH" \
  -H "Content-Type: application/json" -H "Idempotency-Key: design-1" -d '{
  "sides": { "front": { "artworkId": "art_…", "placementModel": "collar-v1" } },
  "approve": true
}'

# 3. Order it: the answer carries the order id (ord_…) and its offer
curl https://toolboxpod.com/api/v1/orders -H "$AUTH" \
  -H "Content-Type: application/json" -d '{
  "storeId": "sto_…", "externalReference": "web-1001",
  "recipient": { "name": "Ada Lovelace", "street1": "1 Analytical Way",
    "city": "Springfield", "state": "OR", "postal": "97477", "country": "US" },
  "lines": [{ "designId": "rev_…", "size": "L", "color": "BLK",
    "quantity": 1, "title": "Sunset tee" }]
}'

# 4. Pay it: "accepted" is the offer from step 3, exactly as it came back
curl https://toolboxpod.com/api/v1/orders/ord_…/purchase -H "$AUTH" \
  -H "Content-Type: application/json" -H "Idempotency-Key: pay-web-1001" \
  -d '{ "accepted": { …the offer… }, "testOutcome": "succeed" }'

Lists that page (GET /orders, /events, /artwork, /designs, /products, /billing/charges, /billing/refunds and the AI job lists) take cursor and limit: send the returned nextCursor back as cursor until it is null. Pages run newest first and never repeat or skip a row. A field or query parameter a call does not take is refused with a 422 that names it, never ignored.

Webhooks

Register an HTTPS endpoint with POST /api/v1/webhook-endpoints (scope webhooks:manage) or under Developers in the dashboard. You can have several endpoints: an integration keeps up to 10 active in each mode, each at a different URL. Every endpoint lists the events it wants, has its own signing secret (shown once) and gets only its own mode’s events, so sandbox events go to sandbox endpoints. Each delivery is a JSON POST with three headers:

Delivery headers
Pod-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256>
Pod-Event-Id: evt_…
Pod-Event-Type: order.paid

Verify Pod-Signature against the raw body before you parse it: HMAC-SHA256 of t + "." + rawBody with that endpoint’s secret, compared in constant time, refusing a t more than five minutes old. With several endpoints, each one checks its own secret. Store the event, then answer 2xx within 10 seconds, and skip repeats by Pod-Event-Id: a redelivery keeps its ID.

Verify a delivery (Node.js)
import { createHmac, timingSafeEqual } from "node:crypto";

// rawBody: the request body exactly as received, before JSON.parse.
export function verifyWebhook(rawBody, header, secret) {
  const parts = String(header || "").split(",").map((s) => s.trim());
  const t = parts.find((s) => /^t=\d+$/.test(s))?.slice(2);
  if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = createHmac("sha256", secret)
    .update(t + ".").update(rawBody).digest();
  return parts.filter((s) => /^v1=[0-9a-f]{64}$/.test(s)).some((s) =>
    timingSafeEqual(expected, Buffer.from(s.slice(3), "hex")));
}

A failed delivery is retried after 1 minute, 5 minutes, 30 minutes, 2 hours, 12 hours and 24 hours; 20 failures in a row disable the endpoint. Test a receiver with POST /api/v1/webhook-endpoints/{endpointId}/ping and send an event again with POST /api/v1/events/{eventId}/redeliver. Events can arrive out of order: read the order for its current state.

design.registeredorder.quotedorder.paidorder.heldorder.shippedorder.closedorder.cancelledpackage.shippedrefund.sentreplacement.createdsupport_request.receivedrate_card.noticeping

Import a Shopify store

Connect the products a Shopify store already sells, so Toolbox POD prints and ships their orders. Their titles, photos, prices and descriptions stay as they are in Shopify. Selling on Shopify is invite-only for now (request access at toolboxpod.com/shopify).

  1. POST /api/v1/stores/{storeId}/shopify-products/syncRead the store’s products from Shopify again (202). A big store is read in the background: GET the same path until state is complete. Nothing is written to Shopify.
  2. GET /api/v1/stores/{storeId}/shopify-productsThe products with their photo and connection. tab=not_connected (the default) is what is left to import; q searches titles, vendors and SKUs. Page with cursor.
  3. POST /api/v1/artworkUpload each product’s print file and keep its art_… id.
  4. POST /api/v1/stores/{storeId}/shopify-imports/previewFor up to 25 products: the shirt, each variant’s color and size match, and the print warnings. Show them to a person before you connect.
  5. POST /api/v1/stores/{storeId}/shopify-importsConnect up to 25 products per request, each with { "assetId": "art_…" } or an existing { "designId": "rev_…" }. Every item answers done or failed on its own, and sending the same request again changes nothing.
Connect a batch of Shopify products
AUTH="Authorization: Bearer $TOOLBOX_POD_KEY"

# 0. The Shopify store's id: GET /me lists them in shopifyStores
STORE=$(curl -s https://toolboxpod.com/api/v1/me -H "$AUTH" | jq -r '.shopifyStores[0].id')

# 1. What is not connected yet (the answer's nextCursor pages on)
curl "https://toolboxpod.com/api/v1/stores/$STORE/shopify-products?tab=not_connected&limit=100" -H "$AUTH"

# 2. Connect a batch of up to 25: each with its uploaded print file or a design
curl https://toolboxpod.com/api/v1/stores/$STORE/shopify-imports -H "$AUTH" \
  -H "Content-Type: application/json" -d '{
  "items": [
    { "shopifyProductId": "gid://shopify/Product/8123456789", "design": { "assetId": "art_…" } },
    { "shopifyProductId": "gid://shopify/Product/8123456790", "design": { "designId": "rev_…" } }
  ]
}'

The key needs products:write. An item that makes or approves a design (an uploaded print file, or a design that is not approved yet) also needs designs:activate; without it the whole request is refused (403 scope_missing) and nothing is written. A sandbox key is refused (403 practice_mode_live_store). A failed item names its reason: warnings_unacknowledged lists the print warnings to accept in acknowledgedWarnings, and no_variants_matched asks for matches with each variant’s color and size. Connected products show in GET /api/v1/products with origin: "shopify_import"; follow each one’s live and pending variants on the connected tab.

AI agents and MCP

Add https://mcp.toolboxpod.com/mcp as a connector in Claude, ChatGPT or any MCP client (Streamable HTTP); connectors added with https://toolboxpod.com/mcp keep working. The client finds the OAuth details and opens the Toolbox POD consent page: sign in, choose the account and approve only the scopes it needs.

A connection is live but pays for nothing until the Owner sets a spending limit, and buying or approving designs each need the Owner to turn them on. Creating stores and issuing keys is REST only. Client by client setup: MCP setup (Markdown).

Prompt for an agent
Connect to https://mcp.toolboxpod.com/mcp with the client's OAuth flow, or use an Owner-issued sandbox API key from a secret manager. Read https://toolboxpod.com/api/v1/openapi.json first. Check the account, mode, scopes and store IDs with GET /api/v1/me. Use only the stores you are given. Set up a webhook receiver, verify its signatures and ping it. Report the store ID, the key's mode and the delivery result without revealing any secret. Do not make real purchases or widen spending permissions.

API reference

Every endpoint with its request and response fields, examples and a request console, generated from the schemas the API runs on.

Open the API reference →Download OpenAPI 3.1

Questions?

Email support@toolboxpod.com with the x-request-id of the call. We reply on business days.

Resources

  • API reference
  • OpenAPI JSON
  • MCP setup (Markdown)
  • Manage API keys
toolboxPOD

Custom shirts printed and shipped from our own shop in Utah, for you, your store or your AI. Made by Toolbox Brands LLC.

Shop

  • Order a shirt
  • Shirts and colors
  • Pricing
  • Blog

Connect

  • Claude, ChatGPT and more
  • Shopify app (coming soon)
  • Developers

Help

  • support@toolboxpod.com
  • Returns and refunds
  • Copyright policy

Account

  • Sign up
  • Sign in

© 2026 Toolbox Brands LLC, Utah.

TermsPrivacyDPAReturnsCopyright