ThreadReadyThreadReady
PricingHelpBlogContact

Operator Handbook

Help Center

Guides for setting up and running your ThreadReady kiosk, from your first template to taking orders at the counter.

Help & Guides

Step-by-step guides for setup, templates, the kiosk, orders, and billing. Can't find what you need? Contact us.

ThreadReadyThreadReady

Embroidery personalization for modern shops — from live stitch preview and customer approval to a clean production handoff. Starting with the kiosk, built to grow with you.

KioskAll productsPricingHelpBlogContact

© 2026 Lambda Coffie LLC. ThreadReady is built for modern machine embroidery shops.

Terms of ServicePrivacy PolicyRefund Policy
Help CenterOrders & FulfillmentAPI and Integrations

API and Integrations

Connect your own tools: API keys and who can make them, a first request, paging and search, moving a status safely, machine-file downloads, every error, the rate limit, and the changelog.

The ThreadReady API lets your own tools read your shop's orders, download their machine files, move an order's status and keep its staff note, for example to show orders on a production board or to mark them picked up from your POS. This guide covers the basics. The full reference, with every field, is at /api/docs.

What the API can and can't do

  • List orders, with paging, filters and search, and read one order, including the approved price and what to embroider (each line's text, font, size and thread).
  • Download an order's machine file as DST, PES, JEF or EXP.
  • Move an order's status, one step at a time, the same as the order page.
  • Set or clear an order's staff note, the same note staff see on the order page.

Moving a status and changing the staff note need a read-and-write key; everything else works with a read-only key.

The API can't create orders: orders come from the kiosk. It also can't change designs, prices, customers or settings.

Each order carries placedFrom: kiosk for a shop kiosk, phone for an order a customer placed on their own phone (see Orders from customers' phones). It also carries isTest, true for a test order; the API and webhooks list test orders like any other, and marking or unmarking one sends an Order Updated webhook with isTest in changedFields.

Creating and revoking keys

Owners and admins manage keys in Settings → API Keys. Members and viewers see a note there instead of the keys, and keys can't be made in the demo workspace.

  1. Give the key a name you'll recognise later, such as "Production board".
  2. Choose its permission:
    • Read only (the default): list and read orders and download machine files. Right for a production board or a report.
    • Read and write: also move an order's status and change its staff note, for example from your POS.
  3. Press Create API key, and copy the key straight away. It starts with sk_live_ and is shown only once; ThreadReady keeps only a fingerprint of it. If you lose it, revoke it and make a new one.
  4. Put it in the tool's settings or server environment, never in a web page or shared code.

Every key can read customer names, emails and phone numbers. A read-and-write key can also change order status and staff notes. A key's permission can't be changed later: make a new key instead. The key list shows each key's permission. Keys made before permissions existed (November 5, 2026) are read and write. Keys don't expire yet. Make one key per tool, so you can turn one off without breaking the others.

To revoke a key, press Revoke next to it in Settings → API Keys. It stops working at once, and that can't be undone. The list shows when each key was last used, so you can spot keys nobody needs.

Your first request

Send the key in the Authorization header of every request:

curl "https://threadready.com/api/v1/orders?limit=5" \
  -H "Authorization: Bearer sk_live_your_key_here"

A successful answer looks like this (shortened):

{
  "success": true,
  "data": [
    {
      "id": "6f1c…",
      "orderNumber": "TR-1042",
      "status": "paid",
      "customer": { "name": "Jane Smith", "email": "jane@example.com", "phone": null },
      "totals": { "subtotal": 24, "total": 24, "currency": "USD" },
      "staffNote": null,
      "production": { "stitchFiles": { "available": true, "unavailableReason": null, "downloads": { "dst": "…" } } }
    }
  ],
  "pagination": { "total": 37, "page": 1, "limit": 5, "hasMore": true }
}

Errors come back as { "error": "…", "code": "…" }, with a message you can show to staff. We may add fields to answers over time, so ignore the ones you don't use; removing or changing a field is always announced in the changelog at the end of this page.

Paging, filtering and search

GET /api/v1/orders takes these query parameters:

ParameterWhat it does
pageThe page to return, from 1.
limitOrders per page: 20 unless you say, at most 100.
sortcreatedAt, updatedAt or orderNumber; put - in front for newest or highest first. The default is -createdAt.
statusOnly orders in this status, for example status=ready_for_pickup.
searchOrders whose number, customer name or customer email contains this text, in any case.

Keep asking for the next page while pagination.hasMore is true.

Status values are unpaid (awaiting payment; older orders may say submitted), paid, ready_for_production (in production), ready_for_pickup, completed (picked up) and cancelled, plus saved for drafts. The same values appear in webhooks and the CSV export.

To read one order with everything needed to sew it, use GET /api/v1/orders/{id}.

Moving a status safely

Send the new status, and the status you last read as expectedStatus:

curl -X PATCH https://threadready.com/api/v1/orders/ORDER_ID/status \
  -H "Authorization: Bearer sk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"status": "ready_for_production", "expectedStatus": "paid"}'

If someone at the counter moved the order in the meantime, nothing changes and the API answers 409 Conflict. Read the order again and decide again; this is the same protection the order page has. If the order is already in the status you asked for, the answer is a success with "changed": false.

Orders move one step at a time: Awaiting payment → Paid → In production → Ready for pickup → Picked up. Any open order can be cancelled. Cancelling an order that has been paid needs a cancelReason, which is kept in the order's history; refund the customer at your POS, as ThreadReady takes no payments. Every move made with a key is recorded in the order's history, where it shows as a System change.

Staff notes

Each order has a staffNote: the note staff keep on the order page, which the customer never sees. It is null when there is none. The customer's own words from the kiosk are in comment, which the API never changes.

To set or clear it, use a read-and-write key:

curl -X PATCH https://threadready.com/api/v1/orders/ORDER_ID/staff-note \
  -H "Authorization: Bearer sk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"staffNote": "Customer will collect after 3pm."}'

Send "" or null to clear it; a note can be up to 2000 characters. The change is recorded in the order's history (as a System change) and sends an Order Updated webhook, the same as an edit on the order page. Sending the note the order already has changes nothing and answers "changed": false.

Downloading machine files

Each order's production.stitchFiles tells you whether a machine file can be made:

  • available: true: downloads has a link for each format. Fetch it with the same Authorization header. The file comes back as a download named with the order's six-character code and the customer's name, like every machine file (for example 8F8B19_Olivia-Rose.dst; see Machine files for production).
  • available: false: unavailableReason says why in plain words. If staff corrected the order and the customer hasn't approved the new proof yet, the download answers 409 until they approve. Otherwise (a line with no font on the design, a letter the font can't stitch, and so on) fix it in the app; the download answers 404 until then.
curl -OJ https://threadready.com/api/v1/orders/ORDER_ID/stitch/dst \
  -H "Authorization: Bearer sk_live_your_key_here"

The formats are dst, pes, jef and exp (upper case works too). The order list doesn't rebuild designs, so there unavailableReason may only say that no stitch data is stored; reading the single order gives the full reason. Downloads are recorded in the order's history.

Errors and what to do

Every error has a status, a code and a plain-words error message.

  • 400 VALIDATION_ERROR: The request is wrong: an unknown status or format, a blank order ID, a body that isn't JSON, cancelling a paid order without a cancelReason, or a staff note that isn't text or is over 2000 characters. What to do: Fix the request; the message says what's wrong. Retrying won't help.
  • 401 UNAUTHORIZED: No key, a key that doesn't start with sk_live_, or a key that was revoked. What to do: Check the header. If the key was revoked, make a new one.
  • 402 PAYMENT_REQUIRED: The workspace is locked for billing. What to do: An owner restores access in Settings → Billing; the same key works again afterwards.
  • 403 FORBIDDEN_SCOPE: A read-only key tried to change an order (move a status or set a staff note). What to do: An owner or admin creates a read-and-write key in Settings → API Keys for this tool.
  • 403 FORBIDDEN: The workspace was deleted, so its keys no longer work. What to do: If that was a mistake, an owner can contact support within 30 days.
  • 404 NOT_FOUND: No such order in your workspace (another shop's order is a 404 too), or the order has no machine file. What to do: Check the order ID; for machine files, read unavailableReason.
  • 409 CONFLICT: The move isn't allowed, the order is no longer in expectedStatus, or staff corrected the order and the customer hasn't approved the new proof yet. What to do: Read the order again. A correction waiting on the customer clears when they approve.
  • 429 RATE_LIMIT: More than 60 requests in a minute with this key. What to do: Wait the number of seconds in the Retry-After header, then carry on.
  • 500 INTERNAL_ERROR: Something went wrong on our side. What to do: Try again shortly; contact support if it keeps happening.

Rate limit

Each key can make 60 requests per minute, across all endpoints. Over that, the API answers 429 with a Retry-After header. To stay under it, ask for up to 100 orders per page rather than reading orders one by one, and use webhooks instead of asking every few seconds whether something changed.

Webhooks

Instead of asking the API over and over, a webhook tells your system when an order is created or changes status. Set them up in Settings → Webhooks (owners and admins). See Webhooks for the events, their bodies, the headers, checking the signature, retries and Resend.

Changelog

Changes that could break an integration, newest first.

Webhook headers, signature and status event (November 5, 2026)

  • Webhooks are signed over a timestamp and carry new headers (x-threadready-delivery, -event, -timestamp), and failed deliveries are retried for about 9 hours. See Breaking change: webhook headers and signature.
  • Status changes are order.status.changed, with status and previousStatus; order.stage.changed is no longer sent or accepted.

Key permissions, staff notes and fewer totals (November 5, 2026)

  • Keys are read only or read and write. A read-only key gets 403 (FORBIDDEN_SCOPE) when it moves a status or sets a staff note. Keys made before this change are read and write, so nothing that already works stops.
  • Orders include staffNote, and PATCH /api/v1/orders/{id}/staff-note sets or clears it.
  • totals.shipping, totals.tax and totals.discount are gone. They were always 0, as ThreadReady takes no payment. totals now has subtotal, total and currency.

Always-empty fields removed (November 5, 2026)

Order answers no longer include items, notes, trackingUrl, estimatedDelivery, publicTrackingId, parentOrder or customer.shippingAddress. Orders haven't had these since ThreadReady stopped handling shipping, so they were always empty, and they were never in the reference. Nothing replaces them. totals.currency is now always present when there is a price, and a contact detail the customer left blank (customer.name, email or phone) is null instead of an empty string.

Deleted workspaces (November 2, 2026)

A key whose workspace was deleted gets 403 (FORBIDDEN) with a message saying so, instead of the billing lock's 402.

Rate limit (October 30, 2026)

Every endpoint can answer 429 (RATE_LIMIT) after 60 requests per minute per key. Wait for Retry-After seconds.

Cancel reasons and corrections waiting on the customer (October 29, 2026)

  • Cancelling a paid order (paid, ready_for_production, ready_for_pickup) needs a cancelReason; without one the API answers 400.
  • When staff corrected an order and the customer hasn't approved the updated proof yet, moving it into production, ready for pickup or picked up answers 409, and so does its machine file, until the customer approves.
  • Order answers no longer include stage, orderType, trackingCode or isArchived. They were always empty and never in the reference.

Ready for pickup (October 27, 2026)

If you built an integration before the Ready for pickup step existed, update it:

  • New status ready_for_pickup. It can appear in order answers, the status filter and Order Status Changed webhooks, between ready_for_production and completed.
  • ready_for_production → completed no longer works. The API answers 409 Conflict. Move the order to ready_for_pickup first, then to completed. (An owner or admin can still skip the step from the order page with Change status….)
  • Webhook status names changed. In Order Status Changed webhooks, ready_for_production is now named "In production" (was "Ready for Production") and completed is named "Picked up" (was "Completed"). The status id values didn't change, so match on id, not name.
Previous
Correcting an Order After Approval
Next
Webhooks

More in Orders & Fulfillment

  • Managing Orders
  • The Order Queue and CSV Export
  • Order Statuses and Telling the Customer
  • Correcting an Order After Approval
  • Webhooks