Appearance
REST API
Read your orders, customers and inventory, create orders, and advance stages. Available on Premium and above.
Base URL and authentication
https://yourshop.printersfriend.com/api/v1Create a token in Insight, then API tokens, and pass it as a bearer token:
bash
curl -H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
https://yourshop.printersfriend.com/api/v1/meEvery request is checked for four things: a valid token, an active user, the workspace it belongs to, and whether your plan allows API access. The plan check runs per request, so a downgrade stops access immediately even for existing tokens.
Rate limits
| Endpoint group | Limit |
|---|---|
| Reads | 60 requests per minute |
| Writes | 20 requests per minute |
Keyed per user. Throttle your side rather than retrying hard.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/me | The authenticated user |
| GET | /v1/customers | List customers |
| GET | /v1/customers/{id} | One customer, with contacts |
| GET | /v1/orders | List orders |
| GET | /v1/orders/{order} | One order, with lines, stage history, invoices, artwork |
| POST | /v1/orders | Create an order |
| POST | /v1/orders/{order}/advance | Advance an order's stage |
| GET | /v1/inventory | List SKUs with stock |
GET /v1/customers
| Query parameter | Effect |
|---|---|
search | Case-insensitive name match |
Paginated, 50 per page. Each row:
json
{
"id": 1,
"name": "Northside Football Club",
"slug": "northside-fc",
"price_list": "Club rate",
"discount": "12.00",
"orders_count": 4,
"open_orders": 2
}GET /v1/customers/
Adds lifetime value, payment terms, default carrier, the full price list and contacts:
json
{
"id": 1,
"name": "Northside Football Club",
"slug": "northside-fc",
"lifetime_value_cents": 924000,
"price_list": { "name": "Club rate", "discount_percent": "12.00" },
"payment_terms": "7 day from invoice",
"default_carrier": "DHL eParcel",
"contacts": [
{ "name": "Megan Cole", "email": "megan@northsidefc.au", "phone": "0408 221 559", "is_primary": true }
]
}GET /v1/orders
| Query parameter | Effect |
|---|---|
stage | Filter by stage code, for example in_production |
customer | Filter by customer slug |
Paginated, 50 per page.
GET /v1/orders/
The full order: lines with SKUs, stage history, invoices and artwork.
POST /v1/orders
json
{
"customer_id": 1,
"due_by": "2026-09-12",
"notes": "Rush job, confirmed with Megan",
"lines": [
{ "description": "Gildan 5000 black L, front print 1 colour", "quantity": 120, "unit_price_cents": 1412 }
]
}| Field | Rules |
|---|---|
customer_id | Required. Must be an existing organisation |
lines | Required, at least one |
lines[].description | Required, up to 255 characters |
lines[].quantity | Required, 1 to 10,000 |
lines[].unit_price_cents | Required, 0 or more |
due_by | Optional date |
notes | Optional, up to 2,000 characters |
The order is created in the Artwork stage, and tax is applied from your tax scheme.
API orders are priced by you, not by the engine
unit_price_cents is taken as given. The pricing rules that apply to a quote built in the workspace do not re-price an API-created line. If you want engine pricing, build a quote in the workspace and convert it. Use the API for orders whose prices are already decided by the system creating them.
A create that would exceed your plan's open-order limit returns 422 with the reason in message.
POST /v1/orders/{order}/advance
json
{ "to_stage": "in_production" }to_stage must be a valid stage code. This fires the same side effects as advancing in the workspace: customer comms, stock consumption, webhooks and stage history. It is not a quiet database update.
GET /v1/inventory
| Query parameter | Effect |
|---|---|
low | Only SKUs at or under their reorder point |
search | Case-insensitive code match |
Paginated, 100 per page:
json
{
"code": "GIL-5000-BLK-L",
"style": "5000 Heavy Cotton Tee",
"brand": "Gildan",
"colour": "Black",
"colour_hex": "#000000",
"size": "L",
"on_hand": 145,
"reserved": 24,
"available": 121,
"reorder_point": 60,
"status": "ok"
}Errors
| Code | Meaning |
|---|---|
| 401 | Missing or invalid token |
| 403 | Token valid, but the user is inactive or lacks permission |
| 404 | Not found, or belongs to another workspace |
| 422 | Validation failed, or a plan limit was hit. Read message |
| 429 | Rate limited. Back off |
Common integrations
| Want | Use |
|---|---|
| Push orders from your own website | POST /v1/orders |
| Advance stages from a warehouse system | POST /v1/orders/{order}/advance |
| Stock levels on another site | GET /v1/inventory |
| React to what happens in the shop | Webhooks, not polling |
For anything event-driven, use webhooks. Polling /v1/orders every minute burns your rate limit and still tells you late.