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.

Your first request
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.

The header every request needs
Authorization: Bearer swk_your_key

Requests 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.

A list answer
{
  "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.

400bad_jsonThe request body is not a JSON object.
401no_key / bad_keyNo key was sent, or it is wrong or revoked.
403not_permitted / not_in_planThe key lacks the permission, or the plan does not include the feature.
404not_foundNo such style, client or order.
409idempotency_key_reused / in_progressThe Idempotency-Key was used for a different request, or the same request is still being handled.
413too_largeThe request body is larger than 64 KB.
422invalidSomething in the request is not valid. The message says what.
429rate_limitedToo many requests this minute. Wait for the seconds given in Retry-After.
An error answer403
{
  "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.

On any POST
Idempotency-Key: basket-8841

Catalogue

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.
Example request
curl "https://api.stitchworkai.com/v1/styles?department=MEN&garment=Jacket" \
  -H "Authorization: Bearer swk_your_key"
Example answer200
{
  "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.
Example request
curl "https://api.stitchworkai.com/v1/styles/8456" \
  -H "Authorization: Bearer swk_your_key"
Example answer200
{
  "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.
Example request
curl "https://api.stitchworkai.com/v1/styles/8456/fabrics?construction=000A" \
  -H "Authorization: Bearer swk_your_key"
Example answer200
{
  "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.
Example request
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"
  }'
Example answer201
{
  "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.
Example request
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
  }'
Example answer201
{
  "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.
Example request
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
    }
  }'
Example answer201
{
  "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.
Example request
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"
      }
    ]
  }'
Example answer201
{
  "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.
Example request
curl "https://api.stitchworkai.com/v1/orders/0b6f1c0e-3a52-4f0e-9d0c-6f2f6c1a7e11" \
  -H "Authorization: Bearer swk_your_key"
Example answer200
{
  "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.
Example request
curl "https://api.stitchworkai.com/v1/orders?reference=WEB-8841" \
  -H "Authorization: Bearer swk_your_key"
Example answer200
{
  "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.

What your website receives
{
  "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.

  1. Read the Stitchwork-Signature header. It has two parts: t, the time it was sent, and v1, the signature.
  2. Join t, a full stop and the exact body you received, and compute an HMAC-SHA256 of that with your signing secret.
  3. The result, as hex, must equal v1. Refuse the message if it does not, or if t is 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.

Checking a message
# 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