Orders & print files
When a customer pays in your checkout, tell us which designs they bought and in what quantities. We render the production files and hand you download links. You send design references and quantities only — no customer names, no addresses, no prices. Money and customer data stay entirely in your system: this API has no fields for them, so nothing can leak by accident.
Producing in-house is what this API models. If you later want IdealFactory to arrange production and shipping for you, that is a separate, explicit integration — it necessarily includes a shipping address, and this endpoint will never quietly start carrying one.
Both endpoints authenticate with your API token
(Authorization: Bearer …) — server to server, never from a page.
Create the order
Call once when your order is paid:
POSThttps://api.idealfactory.com/v1/shop/orders
{
"external_id": "your-order-1001",
"lines": [
{ "design_version_id": "01j9…", "quantity": 3, "external_id": "your-line-1" },
{ "design_version_id": "01j9…", "quantity": 1, "external_id": "your-line-2" }
]
}
external_id(order and line) are your references — you never store any IdealFactory order identifier; all later calls use your own.- Idempotent: resending the same order
external_idreturns the existing order (200instead of201) — retry freely on timeouts. - All-or-nothing: if any line cites an unknown design, nothing is
created and the
422names the bad line (lines.1.design_version_id), so a corrected retry starts clean. - Every
design_version_idmust be a design saved through your shop's Customiser — ids from anywhere else are refused.
The response is the same shape as the status poll below (201 on create).
curl -X POST https://api.idealfactory.com/v1/shop/orders \
-H "Authorization: Bearer $IF_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"external_id":"your-order-1001","lines":[{"design_version_id":"01j9…","quantity":3}]}'
Poll status & collect files
GEThttps://api.idealfactory.com/v1/shop/orders/{your-order-ref}
{
"data": {
"reference_number": "IF2608-0042",
"external_id": "your-order-1001",
"lines": [
{
"external_id": "your-line-1",
"design_version_id": "01j9…",
"quantity": 3,
"prints": [
{
"id": "01j9…",
"status": "processing",
"files": [
{ "index": 0, "type": "single_file", "copies": 1,
"url": "https://…/print-files/01j9…/0?token=…" }
]
}
]
}
]
}
}
filesis empty until the render completes — poll until it isn't. A URL in a response always points at a real, ready file.reference_numberis what IdealFactory staff see on their side — quote it in support conversations. You don't need to store it.- Re-ordered designs usually render near-instantly (already-rendered artwork is served from cache).
- Poll at a relaxed interval — every 30–60 seconds is plenty.
Print statuses
prints[].status is one of exactly four values:
| Status | Meaning | Your move |
|---|---|---|
processing |
Queued or rendering — files is still empty |
Keep polling (or wait for the webhook) |
ready |
Files are rendered — files is populated |
Download |
failed |
The render failed or an operator flagged an issue | Contact IdealFactory with the reference_number |
cancelled |
The item was cancelled on our side | Stop polling this item |
Webhook: print_files.ready
Instead of polling on a timer, register a webhook URL (with your shop's connection) and we POST to it as each item's files finish rendering:
{
"event": "print_files.ready",
"order_external_id": "your-order-1001",
"line_external_id": "your-line-1",
"design_version_id": "01j9…",
"print_id": "01j9…",
"status": "ready",
"files": [ { "index": 0, "type": "single_file", "copies": 1, "url": "…" } ],
"sent_at": "2026-08-24T12:00:00+00:00"
}
Three rules to build against:
- Verify the signature. Every delivery carries
X-IdealFactory-Signature: sha256=<hex>— HMAC-SHA256 of the raw request body with your webhook secret. Reject anything that doesn't match:
$expected = 'sha256='.hash_hmac('sha256', $rawBody, $secret);
abort_unless(hash_equals($expected, $signatureHeader), 401);
- Expect at-least-once. Retries on failure mean you may see the same
event twice — handling it idempotently (keyed on
print_id) makes duplicates harmless. - Treat it as a nudge, not the truth. Respond
2xxquickly and confirm viaGET /v1/shop/orders/{ref}— the poll endpoint stays authoritative, so a missed delivery costs latency, never data.
Print-file URLs
The files[].url links are self-contained: a plain GET that redirects to
the file, authenticated by a token scoped to that one order. Properties
worth knowing:
- They work anywhere — a browser, a production system, a RIP queue. No headers, no API token.
- They can't reach any other order's files, and IdealFactory can revoke one order's links without touching your credentials.
- Don't construct or modify them — always use them exactly as returned, and re-poll if you've lost them.
- Every hand-out is logged on our side, which is what settles "we never got the file" conversations.
Files are also always available to your team in the IdealFactory brand panel under Fulfillment → Prints, with the same references — useful before any automation exists, and as the manual fallback ever after.