Stitchwork API · v1
API guide
For tailors with their own website. Your web developer can show your catalogue at your selling prices, send enquiries, clients and orders into your Stitchwork account, and have your website told when an order moves on.
- Prices in every answer are your selling prices. Your costs are never sent.
- Pictures are served by Stitchwork, so they can go straight onto your pages.
- Orders from your website wait for your approval unless you decide otherwise, key by key.
- You still place each order with the maker yourself.
The API is at https://api.stitchworkai.com/v1.
curl "https://api.stitchworkai.com/v1/styles?department=MEN&garment=Jacket" \
-H "Authorization: Bearer swk_your_key"Keys and permissions
API access is part of some plans. If you do not see “API” in your portal menu, your plan does not include it.
Make a key in your portal under API and tick only what that key needs to do. One key can be read-only for a brochure site while another takes orders. The key is shown once; you can change what it may do, or revoke it, at any time.
- Read the catalogue
- Styles, fabrics, pictures and your selling prices.
- Send in enquiries
- Contact and quote requests from the website.
- Add clients and measurements
- Create or update a client, and add their measurements.
- Read order progress
- Where each order has got to.
- Send in orders
- Orders from the website, for you to approve.
- Orders skip your approval
- Complete orders sent with this key are confirmed straight away.
Keep the key on your website's server. Never put it in a web page or an app that visitors download: anyone who reads it can use it.
Authorization: Bearer swk_your_keyRequests and answers
Everything is JSON over https. Answers put what you asked for under data.
Money is given in the smallest unit of the currency, so { "amount": 89500, "currency": "GBP" } is £895.00. The currency is the one in your pricing settings.
Lists come a page at a time. Ask for ?page=2, and compare total with page_size to know when to stop.
Limits. Each key may make a set number of requests a minute, decided by your plan. Beyond that the answer is 429 with a Retry-After header.
{
"data": [
"…"
],
"page": 2,
"page_size": 24,
"total": 643
}Errors
When something is wrong the status says what kind of problem it is, and the body carries a code your developer can test for and a message in plain English.
| 400 | bad_json | The request body is not a JSON object. |
| 401 | no_key / bad_key | No key was sent, or it is wrong or revoked. |
| 403 | not_permitted / not_in_plan | The key lacks the permission, or the plan does not include the feature. |
| 404 | not_found | No such style, client or order. |
| 409 | idempotency_key_reused / in_progress | The Idempotency-Key was used for a different request, or the same request is still being handled. |
| 413 | too_large | The request body is larger than 64 KB. |
| 422 | invalid | Something in the request is not valid. The message says what. |
| 429 | rate_limited | Too many requests this minute. Wait for the seconds given in Retry-After. |
{
"error": {
"code": "not_permitted",
"message": "This key does not have the \"orders:write\" permission."
}
}Sending something twice
Networks fail. If your website sends an order and never hears back, it cannot know whether the order was made. Add an Idempotency-Key header with a value of your own, such as the basket number, and it is safe to send the same request again: you get the first answer back, with the header Idempotent-Replay: true, and nothing is made twice.
Using the same key for a different request is refused with 409.
Idempotency-Key: basket-8841Catalogue
The styles and fabrics you can sell, at your own selling prices. Pictures are served by Stitchwork.
List styles
GET/v1/styles
The key needs: Read the catalogue
The styles in your catalogue, 24 to a page. Each has one picture and a price: the price with the style's usual fabric and construction.
A price is null until your supplier account is connected and its prices checked.
Query
departmentstring- MEN, WOMEN, KIDS or ACCESSORIES.
garmentstring- A garment type exactly as the API returns it, such as Jacket, Pants, Shirt or Overcoat.
qstring- Part of a style code or name.
pagenumber- Which page of results. Starts at 1.
curl "https://api.stitchworkai.com/v1/styles?department=MEN&garment=Jacket" \
-H "Authorization: Bearer swk_your_key"{
"data": [
{
"id": "8456",
"code": "26AWMJK210",
"name": "26AWMJK210",
"department": "MEN",
"garment": "Jacket",
"gender": "M",
"image": "https://app.stitchworkai.com/media/kt/d6/d6ef2447cadb2a8e8b6f93bd1c26d88d.jpg",
"price": {
"amount": 64500,
"currency": "GBP"
}
}
],
"page": 1,
"page_size": 24,
"total": 643
}Get a style
GET/v1/styles/{id}
The key needs: Read the catalogue
One style: every picture, and its price at each construction available on your account.
ready_made is true for items sold as they are, which have one price and no fabric or construction to choose.
In the address
idstringrequired- The style's id, from the list.
curl "https://api.stitchworkai.com/v1/styles/8456" \
-H "Authorization: Bearer swk_your_key"{
"data": {
"id": "8456",
"code": "26AWMJK210",
"name": "26AWMJK210",
"department": "MEN",
"garment": "Jacket",
"gender": "M",
"ready_made": false,
"images": [
"https://app.stitchworkai.com/media/kt/d6/d6ef2447cadb2a8e8b6f93bd1c26d88d.jpg",
"https://app.stitchworkai.com/media/kt/3a/3a91c0f2b7e84d15a6c2e9f04b7d1c58.jpg"
],
"default_fabric": "DBV6564",
"fabric_count": 3,
"price": {
"amount": 64500,
"currency": "GBP"
},
"constructions": [
{
"code": "000B",
"name": "Half canvas",
"default": true,
"price": {
"amount": 64500,
"currency": "GBP"
}
},
{
"code": "000A",
"name": "Full canvas",
"default": false,
"price": {
"amount": 74500,
"currency": "GBP"
}
}
]
}
}List a style's fabrics
GET/v1/styles/{id}/fabrics
The key needs: Read the catalogue
The fabrics a style comes in, 50 to a page, each with its details and pictures.
price is the price of the whole garment in that fabric, at the construction you ask for.
In the address
idstringrequired- The style's id.
Query
constructionstring- A construction code from the style, such as 000A. The style's usual one if left out.
pagenumber- Which page of results. Starts at 1.
curl "https://api.stitchworkai.com/v1/styles/8456/fabrics?construction=000A" \
-H "Authorization: Bearer swk_your_key"{
"data": [
{
"code": "DBV6564",
"composition": "65%Wool, 35%Polyester",
"weight": "280g/m2",
"mill": null,
"colour": "Navy",
"pattern": "Plain",
"collection": "2409 Uomo",
"images": [
"https://app.stitchworkai.com/media/kt/7c/7c40e19a2d5b4f3e8a61c0d9b2e7f435.jpg"
],
"price": {
"amount": 74500,
"currency": "GBP"
}
}
],
"construction": "000A",
"page": 1,
"page_size": 50,
"total": 3
}Enquiries
Send in an enquiry
POST/v1/enquiries
The key needs: Send in enquiries · accepts an Idempotency-Key
A contact or quote request from your website. It appears under Enquiries in your portal. Nothing is answered automatically.
Body (JSON)
namestringrequired- Who is asking.
messagestringrequired- What they wrote, up to 6,000 characters.
emailstring- An email or a phone number is required, so you can reply.
phonestring- An email or a phone number is required.
style_idstring- The style they were looking at, if any.
curl -X POST "https://api.stitchworkai.com/v1/enquiries" \
-H "Authorization: Bearer swk_your_key" \
-H "Idempotency-Key: basket-8841" \
-H "Content-Type: application/json" \
-d '{
"name": "James Carter",
"email": "james@example.com",
"message": "Do you make morning suits? The wedding is in June.",
"style_id": "8456"
}'{
"data": {
"id": "9f3c2b1a-64d8-4e0b-8a3f-52b7c1d0e9a4",
"received_at": "2026-10-01T11:20:00.000Z"
}
}Clients and measurements
Add or update a client
POST/v1/clients
The key needs: Add clients and measurements · accepts an Idempotency-Key
Adds a client and answers 201. If you already have a client with that email, they are updated and the answer is 200, so the same customer ordering twice does not become two clients.
Consent can be switched on through the API but never off: that is done in the portal.
Body (JSON)
namestringrequired- The client's name.
emailstring- If you already have a client with this email, they are updated instead of added again.
phonestring- Phone number.
notesstring- Anything the tailor should know.
consent_measurementsboolean- Send true only if the customer agreed to their measurements being stored. Measurements are refused without it.
consent_marketingboolean- Send true only if the customer agreed to marketing.
curl -X POST "https://api.stitchworkai.com/v1/clients" \
-H "Authorization: Bearer swk_your_key" \
-H "Idempotency-Key: basket-8841" \
-H "Content-Type: application/json" \
-d '{
"name": "James Carter",
"email": "james@example.com",
"phone": "07700 900123",
"consent_measurements": true,
"consent_marketing": false
}'{
"data": {
"id": "5d1b8a52-7c3e-4a57-b1c9-0a4f2f6f3c21",
"name": "James Carter",
"email": "james@example.com",
"phone": "07700 900123",
"consent_measurements": true,
"consent_marketing": false
}
}Add measurements
POST/v1/clients/{id}/measurements
The key needs: Add clients and measurements · accepts an Idempotency-Key
A set of measurements for a client. Each set is kept; an order uses the newest unless told otherwise.
Refused with 422 if the client has not agreed to their measurements being stored.
In the address
idstringrequired- The client's id.
Body (JSON)
kindstring- body (the default), finished (garment measurements) or standard (a size).
unitstring- cm (the default) or in.
valuesobjectrequired- body: height, weight, neck, chest, waist, seat, shoulder, sleeve, bicep, wrist, jacket_length, trouser_waist, outseam, inseam, thigh, knee, cuff. finished: chest, waist, shoulder, sleeve, jacket_length, trouser_waist, seat, thigh, knee, outseam, cuff. standard: size, fit, sleeve_adjust, length_adjust.
notesstring- A note to keep with the measurements.
taken_ondate- When they were taken, like 2026-10-01. Today if left out.
curl -X POST "https://api.stitchworkai.com/v1/clients/5d1b8a52-7c3e-4a57-b1c9-0a4f2f6f3c21/measurements" \
-H "Authorization: Bearer swk_your_key" \
-H "Idempotency-Key: basket-8841" \
-H "Content-Type: application/json" \
-d '{
"kind": "body",
"unit": "cm",
"values": {
"height": 181,
"chest": 102,
"waist": 88,
"sleeve": 64
}
}'{
"data": {
"id": "c7a1e3f0-2b4d-4c6e-9f81-3d5a7b9c1e02",
"client_id": "5d1b8a52-7c3e-4a57-b1c9-0a4f2f6f3c21",
"kind": "body",
"unit": "cm",
"values": {
"height": 181,
"chest": 102,
"waist": 88,
"sleeve": 64
},
"taken_on": "2026-10-01"
}
}Orders
Your website sends the customer's choices. Stitchwork works out the prices from your own rates, and you place the order with the maker yourself.
Send in an order
POST/v1/orders
The key needs: Send in orders · accepts an Idempotency-Key
Creates an order. By default it arrives in your portal marked "From your website: to approve": its status is received and awaiting_approval is true.
If the key has "Orders skip your approval" and the order has measurements, it is confirmed straight away.
If any item cannot be priced, nothing is saved and the answer is 422 with the reason, naming the line.
Body (JSON)
linesarrayrequired- Between 1 and 20 items. Each has style_id (required), fabric_code, construction, suit ("2pc" or "3pc", jackets only), quantity (1 to 50) and options (free text for the maker).
client_idstring- An existing client. Send this or client.
clientobject- A client to add or update, with the same fields as Add or update a client. Send this or client_id.
measurementsobject- Measurements to add for this order, with the same fields as Add measurements.
measurement_set_idstring- Use one of the client's existing sets. Their newest is used if neither this nor measurements is sent.
referencestring- Your website's own order number. You can find the order by it later.
occasionstring- What it is for, such as Wedding.
due_datedate- When it is needed by, like 2027-06-01.
notesstring- Notes for the tailor.
curl -X POST "https://api.stitchworkai.com/v1/orders" \
-H "Authorization: Bearer swk_your_key" \
-H "Idempotency-Key: basket-8841" \
-H "Content-Type: application/json" \
-d '{
"reference": "WEB-8841",
"client": {
"name": "James Carter",
"email": "james@example.com",
"consent_measurements": true
},
"measurements": {
"kind": "body",
"unit": "cm",
"values": {
"chest": 102,
"waist": 88
}
},
"occasion": "Wedding",
"due_date": "2027-06-01",
"lines": [
{
"style_id": "8456",
"fabric_code": "DBV6564",
"construction": "000B",
"suit": "2pc",
"quantity": 1,
"options": "Peak lapel, two buttons"
}
]
}'{
"data": {
"id": "0b6f1c0e-3a52-4f0e-9d0c-6f2f6c1a7e11",
"number": "SW-0007",
"reference": "WEB-8841",
"status": "received",
"awaiting_approval": true,
"client_id": "5d1b8a52-7c3e-4a57-b1c9-0a4f2f6f3c21",
"occasion": "Wedding",
"due_date": "2027-06-01",
"total": {
"amount": 89500,
"currency": "GBP"
},
"lines": [
{
"style_id": "8456",
"style_code": "26AWMJK210",
"garment": "2 pcs Suit",
"fabric_code": "DBV6564",
"construction": "000B",
"suit": "2pc",
"quantity": 1,
"options": "Peak lapel, two buttons",
"unit_price": {
"amount": 89500,
"currency": "GBP"
}
}
],
"created_at": "2026-10-01T11:20:00.000Z",
"shipped_at": null,
"delivered_at": null
}
}Get an order
GET/v1/orders/{id}
The key needs: Read order progress
One order and where it has got to. status is one of received, confirmed, in_production, shipped, delivered or cancelled.
In the address
idstringrequired- The order's id.
curl "https://api.stitchworkai.com/v1/orders/0b6f1c0e-3a52-4f0e-9d0c-6f2f6c1a7e11" \
-H "Authorization: Bearer swk_your_key"{
"data": {
"id": "0b6f1c0e-3a52-4f0e-9d0c-6f2f6c1a7e11",
"number": "SW-0007",
"reference": "WEB-8841",
"status": "shipped",
"awaiting_approval": false,
"client_id": "5d1b8a52-7c3e-4a57-b1c9-0a4f2f6f3c21",
"occasion": "Wedding",
"due_date": "2027-06-01",
"total": {
"amount": 89500,
"currency": "GBP"
},
"lines": [
{
"style_id": "8456",
"style_code": "26AWMJK210",
"garment": "2 pcs Suit",
"fabric_code": "DBV6564",
"construction": "000B",
"suit": "2pc",
"quantity": 1,
"options": "Peak lapel, two buttons",
"unit_price": {
"amount": 89500,
"currency": "GBP"
}
}
],
"created_at": "2026-10-01T11:20:00.000Z",
"shipped_at": "2026-10-28T09:12:00.000Z",
"delivered_at": null
}
}List orders
GET/v1/orders
The key needs: Read order progress
Your orders, newest first, 50 to a page. This includes orders made in the portal.
Query
referencestring- Only the order with this reference of yours.
client_idstring- Only one client's orders.
pagenumber- Which page of results. Starts at 1.
curl "https://api.stitchworkai.com/v1/orders?reference=WEB-8841" \
-H "Authorization: Bearer swk_your_key"{
"data": [
{
"id": "0b6f1c0e-3a52-4f0e-9d0c-6f2f6c1a7e11",
"number": "SW-0007",
"reference": "WEB-8841",
"status": "confirmed",
"awaiting_approval": false,
"client_id": "5d1b8a52-7c3e-4a57-b1c9-0a4f2f6f3c21",
"occasion": "Wedding",
"due_date": "2027-06-01",
"total": {
"amount": 89500,
"currency": "GBP"
},
"lines": [
{
"style_id": "8456",
"style_code": "26AWMJK210",
"garment": "2 pcs Suit",
"fabric_code": "DBV6564",
"construction": "000B",
"suit": "2pc",
"quantity": 1,
"options": "Peak lapel, two buttons",
"unit_price": {
"amount": 89500,
"currency": "GBP"
}
}
],
"created_at": "2026-10-01T11:20:00.000Z",
"shipped_at": null,
"delivered_at": null
}
],
"page": 1,
"page_size": 50,
"total": 1
}Webhooks
Being told about changes
Add an address under API in your portal and Stitchwork will POST to it when something changes, so your website does not have to keep asking. Tick which of these each address should hear about:
- order.created
- An order is created, in your portal or by your website.
- order.status_changed
- An order moves on. The order is included, exactly as Get an order returns it.
- catalogue.updated
- The catalogue or your prices changed. Refresh anything your website has stored.
- ping
- A test you sent from your portal.
Answer with any 2xx status within ten seconds. Anything else is tried again after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours, then given up.
The same message can arrive more than once, so use its id to ignore repeats. An address that keeps failing is switched off; send a test from your portal to switch it back on.
{
"id": "evt_412",
"type": "order.status_changed",
"created_at": "2026-10-28T09:12:10.000Z",
"data": {
"order": {
"id": "0b6f1c0e-3a52-4f0e-9d0c-6f2f6c1a7e11",
"number": "SW-0007",
"reference": "WEB-8841",
"status": "shipped",
"awaiting_approval": false,
"client_id": "5d1b8a52-7c3e-4a57-b1c9-0a4f2f6f3c21",
"occasion": "Wedding",
"due_date": "2027-06-01",
"total": {
"amount": 89500,
"currency": "GBP"
},
"lines": [
{
"style_id": "8456",
"style_code": "26AWMJK210",
"garment": "2 pcs Suit",
"fabric_code": "DBV6564",
"construction": "000B",
"suit": "2pc",
"quantity": 1,
"options": "Peak lapel, two buttons",
"unit_price": {
"amount": 89500,
"currency": "GBP"
}
}
],
"created_at": "2026-10-01T11:20:00.000Z",
"shipped_at": "2026-10-28T09:12:00.000Z",
"delivered_at": null
}
}
}Checking the signature
Anyone can send a POST to your address, so check each message really came from Stitchwork before trusting it. Every address has its own signing secret, shown once when you add it.
- Read the
Stitchwork-Signatureheader. It has two parts:t, the time it was sent, andv1, the signature. - Join
t, a full stop and the exact body you received, and compute an HMAC-SHA256 of that with your signing secret. - The result, as hex, must equal
v1. Refuse the message if it does not, or iftis more than five minutes old.
Use the body exactly as it arrived. Parsing it and writing it out again changes it, and the check fails.
# A webhook arrives at your website; there is nothing to send.
# The request Stitchwork makes looks like this:
POST /stitchwork-webhook HTTP/1.1
Content-Type: application/json
Stitchwork-Event: order.status_changed
Stitchwork-Delivery: evt_412
Stitchwork-Signature: t=1792746730,v1=5f2b6c...
v1 = HMAC-SHA256(signing secret, t + "." + raw body), as hex