10-minute quickstart
Product → designer → a first test order, in six calls. Every call on this page is a real route.
What you need
- A PrintWisp organisation with a product that has at least one size and a price (Catalogue).
- A Custom Website (API) store that offers the product: add it on the store's Products tab.
- A test key, made on the store's Overview → API keys. Copy it when it is shown: it is shown once.
- Use the test key: the order you place in step 4 is then a test order. It is kept apart from real orders, is never charged, and goes with Delete test data.
- A page of yours served over https at an origin you own, say
https://shop.example: the designer may be framed only by the origin the session names.
1 · Pick a size code
Ask for the store's catalogue. Each size has a code, for example canvas-40x30: that code is what you send as profile. The store's Products tab shows the same codes.
curl "https://printwisp.com/v1/products" \
-H "Authorization: Bearer $PRINTWISP_KEY"
# 200
{
"store": { "code": "web-au", "name": "Harbour Prints AU", "currency": "AUD" },
"products": [
{
"code": "canvas",
"name": "Photo canvas",
"sizes": [
{
"code": "canvas-40x30",
"name": "40 × 30 cm",
"price": "89.00",
"currency": "AUD",
"packed_kg": 2.431,
"packed_kg_extra": 2.431
},
{
"code": "canvas-60x40",
"name": "60 × 40 cm",
"price": "149.00",
"currency": "AUD",
"packed_kg": 4.576,
"packed_kg_extra": 4.576
}
],
"options": [
{
"code": "edge",
"name": "Edge",
"values": [
{ "code": "mirror", "name": "Mirrored", "price_delta": "0.00" },
{ "code": "white", "name": "White", "price_delta": "0.00" }
]
}
]
}
]
}<?php
$ch = curl_init('https://printwisp.com/v1/products');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('PRINTWISP_KEY'), 'Content-Type: application/json'],
]);
$answer = json_decode(curl_exec($ch), true);// Node (your server). The key never reaches a browser.
const r = await fetch('https://printwisp.com/v1/products', {
headers: { Authorization: 'Bearer ' + process.env.PRINTWISP_KEY },
});
const answer = await r.json();import os, requests
r = requests.get(
"https://printwisp.com/v1/products",
headers={"Authorization": f"Bearer {os.environ['PRINTWISP_KEY']}"},
)
answer = r.json()2 · Create a session
From your server, with the key. origin is the scheme and host of the page that will show the designer; the link then lasts 24 hours and may be framed only there. customer_ref is your own customer id, so the same shopper can reopen the design later. metadata is anything you want back with Add to cart, as {{metadata.<key>}} in the store's JSON: a Custom Website passes its own cart id, {"cart": "c_8f3c41"} (see Custom Website: Add to cart). Every parameter →
curl -X POST "https://printwisp.com/v1/sessions" \
-H "Authorization: Bearer $PRINTWISP_KEY" \
-H "Content-Type: application/json" \
-d '{"profile":"canvas-40x30","origin":"https://shop.example","customer_ref":"cust_8812","qty":1}'
# 201
{
"session": "dss_3f9c1a7e5b2d8c40",
"token": "7b1e5c0a9d3f2e8b4c6a1d7e9f0b3c5a2e4d6f8a1b3c5e7d",
"url": "https://printwisp.com/d/7b1e5c0a9d3f2e8b4c6a1d7e9f0b3c5a2e4d6f8a1b3c5e7d",
"expires_at": "2026-10-06T06:12:00+00:00",
"origin": "https://shop.example",
"product": "canvas",
"profile": "prf_9a21c4d8e0f17b35",
"design": null
}<?php
$ch = curl_init('https://printwisp.com/v1/sessions');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode([
'profile' => 'canvas-40x30',
'origin' => 'https://shop.example',
'customer_ref' => 'cust_8812',
'qty' => 1
]),
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('PRINTWISP_KEY'), 'Content-Type: application/json'],
]);
$answer = json_decode(curl_exec($ch), true);// Node (your server). The key never reaches a browser.
const r = await fetch('https://printwisp.com/v1/sessions', {
method: 'POST',
headers: { Authorization: 'Bearer ' + process.env.PRINTWISP_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ profile: 'canvas-40x30', origin: 'https://shop.example', customer_ref: 'cust_8812', qty: 1 }),
});
const answer = await r.json();import os, requests
r = requests.post(
"https://printwisp.com/v1/sessions",
json={
"profile": "canvas-40x30",
"origin": "https://shop.example",
"customer_ref": "cust_8812",
"qty": 1
},
headers={"Authorization": f"Bearer {os.environ['PRINTWISP_KEY']}"},
)
answer = r.json()3 · Open the designer on your page
Load embed.js and open the url. The overlay shows a spinner until the designer says ready. Make something and press Add to cart: the designer saves, then sends your page the add-to-cart message with design, sig, qty and options (the built-in payload, when the store has no Add-to-cart connector; with one, see Messages).
Before you go live: keep the designer through a refresh, so a shopper who reloads the page comes back to their work.
<!doctype html>
<meta charset="utf-8">
<title>Design yours</title>
<script src="https://printwisp.com/studio/js/embed.js"></script>
<button id="design">Design yours</button>
<pre id="out"></pre>
<script>
document.getElementById('design').onclick = async function () {
// your server made the session with the key (step 2) and hands the page its url
const s = await (await fetch('/printwisp/session')).json();
const d = StudioEmbed.open({ url: s.url, title: 'Photo canvas 40 × 30 cm' });
d.on('add-to-cart', function (p) {
document.getElementById('out').textContent = JSON.stringify(p, null, 2); // design, sig, qty, options
d.close();
});
};
</script>4 · Record the order
Pretend the shopper paid: post the order once with your own number as order_ref and the line's design + sig from step 3, with amount, what the shopper paid for the line. You get the order id and a line id (oln_t… for a test order) with print_status: "queued". Post the same order_ref again and you get 200 with "created": false: nothing is printed twice. An order_ref is unique within the store.
curl -X POST "https://printwisp.com/v1/orders" \
-H "Authorization: Bearer $PRINTWISP_KEY" \
-H "Content-Type: application/json" \
-d '{"order_ref":"WEB-10021","placed_at":"2026-10-05T04:31:00Z","currency":"AUD","customer":{"name":"Jane Citizen","email":"jane@example.com"},"lines":[{"line_ref":"1","qty":1,"amount":"89.00","design":"dsn_5c2a9e01b7d4f638","sig":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}]}'
# 201
{
"order": "ord_7d1e4b9a2c6f0583",
"order_ref": "WEB-10021",
"created": true,
"lines": [
{
"line": "oln_41aa8c3e9d2b7f16",
"line_ref": "1",
"design": "dsn_5c2a9e01b7d4f638",
"qty": 1,
"print_status": "queued",
"components": [],
"fields": []
}
]
}<?php
$ch = curl_init('https://printwisp.com/v1/orders');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode([
'order_ref' => 'WEB-10021',
'placed_at' => '2026-10-05T04:31:00Z',
'currency' => 'AUD',
'customer' => ['name' => 'Jane Citizen', 'email' => 'jane@example.com'],
'lines' => [
[
'line_ref' => '1',
'qty' => 1,
'amount' => '89.00',
'design' => 'dsn_5c2a9e01b7d4f638',
'sig' => 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
]
]
]),
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('PRINTWISP_KEY'), 'Content-Type: application/json'],
]);
$answer = json_decode(curl_exec($ch), true);// Node (your server). The key never reaches a browser.
const r = await fetch('https://printwisp.com/v1/orders', {
method: 'POST',
headers: { Authorization: 'Bearer ' + process.env.PRINTWISP_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
order_ref: 'WEB-10021',
placed_at: '2026-10-05T04:31:00Z',
currency: 'AUD',
customer: { name: 'Jane Citizen', email: 'jane@example.com' },
lines: [
{
line_ref: '1',
qty: 1,
amount: '89.00',
design: 'dsn_5c2a9e01b7d4f638',
sig: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
}
]
}),
});
const answer = await r.json();import os, requests
r = requests.post(
"https://printwisp.com/v1/orders",
json={
"order_ref": "WEB-10021",
"placed_at": "2026-10-05T04:31:00Z",
"currency": "AUD",
"customer": { "name": "Jane Citizen", "email": "jane@example.com" },
"lines": [
{
"line_ref": "1",
"qty": 1,
"amount": "89.00",
"design": "dsn_5c2a9e01b7d4f638",
"sig": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
}
]
},
headers={"Authorization": f"Bearer {os.environ['PRINTWISP_KEY']}"},
)
answer = r.json()5 · Fetch the print file
Ask GET /v1/print?line= until print_status is ready (a canvas takes seconds; a book longer), then download the url within 10 minutes. In production you would not poll: the design.print_ready webhook brings the same link. Webhooks →
curl "https://printwisp.com/v1/print?line=oln_41aa8c3e9d2b7f16" \
-H "Authorization: Bearer $PRINTWISP_KEY"
# 200
{
"line": "oln_41aa8c3e9d2b7f16",
"order_ref": "WEB-10021",
"design": "dsn_5c2a9e01b7d4f638",
"print_status": "ready",
"components": [],
"fields": [],
"url": "https://printwisp.com/v1/file?l=oln_41aa8c3e9d2b7f16&e=1759640400&s=9f2c4e1a7b3d8f05c6e2a9d1b4f7c3e8a5d2b9f6c1e4a7d3b8f5c2e9a6d1b4f7",
"expires_at": "2026-10-05T04:51:00+00:00"
}
curl "https://printwisp.com/v1/file?l=oln_41aa8c3e9d2b7f16&e=1759640400&s=9f2c4e1a7b3d8f05c6e2a9d1b4f7c3e8a5d2b9f6c1e4a7d3b8f5c2e9a6d1b4f7" \
-o WEB-10021-1.pdf<?php
$ch = curl_init('https://printwisp.com/v1/print?line=oln_41aa8c3e9d2b7f16');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('PRINTWISP_KEY'), 'Content-Type: application/json'],
]);
$answer = json_decode(curl_exec($ch), true);// Node (your server). The key never reaches a browser.
const r = await fetch('https://printwisp.com/v1/print?line=oln_41aa8c3e9d2b7f16', {
headers: { Authorization: 'Bearer ' + process.env.PRINTWISP_KEY },
});
const answer = await r.json();import os, requests
r = requests.get(
"https://printwisp.com/v1/print?line=oln_41aa8c3e9d2b7f16",
headers={"Authorization": f"Bearer {os.environ['PRINTWISP_KEY']}"},
)
answer = r.json()6 · See it in the portal
Turn the Test mode switch on: the order is under the store's Orders, with its print file. Delete test data removes it. From here: add a webhook for order.created and design.print_ready under Organisation → API keys & webhooks, move the five steps into your real product page, and use a live key when the store is Open. Endpoint reference →