Hand out a hosted designer for a template
const url = 'https://api.pixonaut.app/v1/templates/example/designer-links';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"blankId":"blank_poster_matte","layout":"steps","mockups":[{"label":"Oak frame","placementRectPx":{"h":380,"w":300,"x":115,"y":90},"url":"https://shop.acme.example/media/poster-oak.jpg"}],"placementId":"front","printSizes":[{"heightMm":400,"label":"30×40","widthMm":300},{"heightMm":700,"label":"50×70","widthMm":500}],"returnUrl":"https://shop.acme.example/cart","state":"cart-8f2c1a"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.pixonaut.app/v1/templates/example/designer-links \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "blankId": "blank_poster_matte", "layout": "steps", "mockups": [ { "label": "Oak frame", "placementRectPx": { "h": 380, "w": 300, "x": 115, "y": 90 }, "url": "https://shop.acme.example/media/poster-oak.jpg" } ], "placementId": "front", "printSizes": [ { "heightMm": 400, "label": "30×40", "widthMm": 300 }, { "heightMm": 700, "label": "50×70", "widthMm": 500 } ], "returnUrl": "https://shop.acme.example/cart", "state": "cart-8f2c1a" }'Operation ID: templates.designerLinks.create
A designer share link for the template’s live version that mounts the designer with what the store sells it on: the blank and placement every proof is fitted to, the store’s size menu and its colourway photos, and which size and photo start selected, exactly as the SDK takes them on a store’s own page. A front and a back are one link with sides: one hosted page with a step per side, each side its own menus and, when it names one, its own template. A link holds two to 10 sides; one with more than 4 is made, and answered with a sides_over_recommended warning, since each side is one more step on the page and one more designer in the shopper’s browser. The sides of a garment each name a placement on its blank; the sides of an item with no blank, such as a sign or a coaster, name neither blankId nor placementId, and each is proofed on its template alone. Every side names a blank and its placement or neither, and either every side is on a blank or none is. With a returnUrl, approving makes a proof and sends the shopper back to returnUrl?state=…&proofToken=… (with sides, returnUrl?state=…&proofToken[front]=…&proofToken[back]=…), cancelling to returnUrl?state=…. locale shows the page and the designer in one of en, sv, de, fr, es, nl, da, nb, fi, and the returned url then carries ?lang=<locale>; absent, they are shown in the workspace’s default language. layout fixes how every side’s form lays out its steps, page or steps; absent, each side’s form follows its template’s own form.layout, and is a page when the template names none. A link carrying state, which names one shopper’s visit, works for 24 hours; one without it works for the expiresInDays it names, or until withdrawn. Every size a side offers is judged as the shopper’s approval would judge it, against the side’s template and placement, and one it would refuse is refused print_size_illegal, naming the side, the size’s place in the menu and why. On a blank, the link holds a side for every placement its blank says an order must print: one leaving such a placement out could never be ordered, and is refused 422 placement_unfilled, naming it. A link through a blank’s panel layout is refused unknown_layout when the blank has no layout of that name, layout_out_of_date when the layout no longer fits the blank at the size the link sells, and layout_wrong_ratio when the template’s shape is not the layout’s canvas, which the template is drawn on. name names the link for the workspace, and designLimit limits the designs its page makes. The link’s address is kept, and the share-link list answers it again as url. A member needs what handing out a designer needs; a connected store’s integration key, templates:read and designs:update.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The template’s base id: the link follows whatever version is live.
The template’s base id: the link follows whatever version is live.
Request Bodyrequired
Section titled “Request Bodyrequired”object
The blank it is printed on; with placementId, or a panelLayout.
The brand the link’s page is drawn in: its name, logo and accent colour (GET /v1/brands). Refused brand_not_found unless it is one of the workspace’s. Absent, a link a connected store’s key hands out keeps the store’s brand, and any other is drawn in whichever brand is the workspace’s default when it opens. A brand a link that still opens names cannot be deleted.
How many designs the link’s page may make, in total or per rolling hour, day or week. Each side approved counts one. At the limit the page, and an approval, answer 429 link_design_limit. Absent, no limit.
object
How many designs the link may make in its period.
total counts every design the link made; hour, day and week the last 60 minutes, 24 hours or 7 days, rolling.
How long the link works, in days, up to 365. Absent, it works until withdrawn. Not with state, which names one shopper’s visit and fixes the link’s lifetime at 24 hours.
The variant the side starts on, by ref: one of variants when it names any.
The view shown first; absent, the side’s first with a photo.
How every side’s form lays out its steps: page, every step on one page, or steps, one step at a time. Absent, each side’s form follows its template’s own form.layout, and is a page when the template names none.
Which of the sides’ placements one design drives, such as a sweater’s sleeves: a preset, or groups of the sides’ placements, a group with a repeat of its own where it repeats apart from the link. The sides of one group print one template. Absent, the groups the blank suggests whose sides print one template; the link keeps the groups it was made with.
object
Whether the shopper may take a placement out of its group and design it on its own. Absent, no.
Groups of your own in place of a preset, each a list of placements, or { placements, repeat } for a group that repeats apart from the link. A mirror left out is the blank’s suggestion, else none.
Placements one design drives, two at least.
object
Whether the placement’s print is mirrored left to right.
The id of one of the blank’s placements.
Placements one design drives, with a repeat of their own: a proof or commit of one of them is held to it.
object
Placements one design drives, two at least.
object
Whether the placement’s print is mirrored left to right.
The id of one of the blank’s placements.
How the group’s design is laid as a repeat, in place of the link’s repeat; null places it once beside a link that repeats.
object
The layouts the shopper may pick, one at least, each once.
Whether the shopper may pick another of modes and another size. Otherwise every design prints as start.
Whether the shopper may place the design once instead (repeat: null). Only with shopperMayChange.
What the design starts as: a repeat in one of modes, or null for placed once, which needs shopperMayTurnOff. A request through the link that names no repeat is made with it.
object
How the tiles are laid: grid lines them up, brick moves every other row along by half a tile, halfDrop moves every other column down by half a tile, and scatter strews them at random places, turns and sizes, arranged by seed.
Which arrangement a scatter draws: another seed is another arrangement of the same tile. Read by scatter only.
The tile’s width in percent of the print area’s width, above 0 and at most 100; the tile keeps the template’s shape. A tile that would print under 10 mm on a side is drawn at 10 mm.
each: every placement is designed on its own. suggested: the groups the blank suggests, such as its sleeves. all: one design drives every placement. Absent with no groups, suggested.
The language the page is shown in: one of en, sv, de, fr, es, nl, da, nb, fi. Absent, the page is shown in the workspace’s default language. The link’s url carries ?lang=<locale> when it names one.
The store’s own product photos the design is shown on, in place of the blank’s views.
object
How far the photo’s folds move the design, above 0 and at most 1; absent or null, not at all.
What the menu calls the photo.
The label per customer-facing language, by code: only the languages it has one in. A designer shown in a language left out reads label.
object
The size of the photo the rect is measured in, when it is not the size of the image the url serves; absent, the image’s own.
object
Its height, in pixels.
Its width, in pixels.
Where the print sits in the photo, in the photo’s pixels.
object
Its height, in the photo’s pixels.
Its width, in the photo’s pixels.
From the photo’s left edge, in its pixels.
From the photo’s top edge, in its pixels.
How strongly the photo’s light and shade carry onto the design, from 0 (flat) to 1; absent, the default.
The photo’s address, http or https.
The store’s own name for the way the product is photographed: photos sharing one are one view.
How the design wraps round the product in the photo, a mug or a bottle; absent or null, flat.
object
How far round the product the rect reaches, above 0 and at most 1.
How dark the design turns toward the product’s silhouette, 0 to 1.
The one kind of wrap: an upright round product.
The workspace’s own name for the link (Spring market stand), at most 80 characters, never shown on its page. Trimmed, inner spaces made one; empty is no name. Unique among the workspace’s working links, case aside: one another holds is refused share_link_name_taken naming the holder, a longer one share_link_name_too_long. A withdrawn or expired link frees its name.
The name of a panel layout of the link’s blankId, in place of placementId: the page draws one design across the layout’s canvas, and each placement it lays out gets its print cut from it, so art runs across the seams. Not with sides or printSizes.
Whether the link’s page draws the placement frame, the ring and corner handles around the shopper’s picture, at rest, as the SDK’s showPlacementFrame does. Absent, the frame shows only while the picture is dragged or sized on the preview.
The blank’s placement it is printed in; with blankId.
Whether the link’s page draws a thin frame around the print area on the product photo, as the SDK’s showPrintAreaFrame does. Absent, no frame.
The sizes the shopper picks from, for a print within its area.
One size in the size menu.
object
The print’s height, in mm.
What the menu calls the size.
The label per customer-facing language, by code: only the languages it has one in. A designer shown in a language left out reads label.
object
The print’s width, in mm.
Whether every side’s design is laid as a repeat of its template, which layouts the shopper may pick, what it starts as, and whether they may change it or turn it off; a linked group with a repeat of its own takes that instead. Absent, each design is placed once and a request through the link naming a repeat is refused. Not with panelLayout.
object
The layouts the shopper may pick, one at least, each once.
Whether the shopper may pick another of modes and another size. Otherwise every design prints as start.
Whether the shopper may place the design once instead (repeat: null). Only with shopperMayChange.
What the design starts as: a repeat in one of modes, or null for placed once, which needs shopperMayTurnOff. A request through the link that names no repeat is made with it.
object
How the tiles are laid: grid lines them up, brick moves every other row along by half a tile, halfDrop moves every other column down by half a tile, and scatter strews them at random places, turns and sizes, arranged by seed.
Which arrangement a scatter draws: another seed is another arrangement of the same tile. Read by scatter only.
The tile’s width in percent of the print area’s width, above 0 and at most 100; the tile keeps the template’s shape. A tile that would print under 10 mm on a side is drawn at 10 mm.
Where the hosted designer sends the shopper back to: with state and the approved proof’s proofToken, which the store commits with its key, or with state alone when they cancel. A link with sides returns each side’s proof under its key, proofToken[<key>], and only once every side is approved. Without it, the page commits the design of every side itself and shows their ids. On one of the origins the tenant’s publishable keys are allowed on.
The photo that starts selected, by its place in mockups.
The size that starts selected, by its place in printSizes.
Several sides of one item, a front and a back, each its own template and placement, designed one after the other; then the one-side fields go on each side instead.
object
The blank it is printed on; with placementId, or a panelLayout.
The variant the side starts on, by ref: one of variants when it names any.
The view shown first; absent, the side’s first with a photo.
The side’s own short name, such as front: lowercase letters, digits, - and _, unique within the link.
What the side’s step is called, such as Front.
The label per customer-facing language, by code: only the languages it has one in. A designer shown in a language left out reads label.
object
The store’s own product photos the design is shown on, in place of the blank’s views.
object
How far the photo’s folds move the design, above 0 and at most 1; absent or null, not at all.
What the menu calls the photo.
The label per customer-facing language, by code: only the languages it has one in. A designer shown in a language left out reads label.
object
The size of the photo the rect is measured in, when it is not the size of the image the url serves; absent, the image’s own.
object
Its height, in pixels.
Its width, in pixels.
Where the print sits in the photo, in the photo’s pixels.
object
Its height, in the photo’s pixels.
Its width, in the photo’s pixels.
From the photo’s left edge, in its pixels.
From the photo’s top edge, in its pixels.
How strongly the photo’s light and shade carry onto the design, from 0 (flat) to 1; absent, the default.
The photo’s address, http or https.
The store’s own name for the way the product is photographed: photos sharing one are one view.
How the design wraps round the product in the photo, a mug or a bottle; absent or null, flat.
object
How far round the product the rect reaches, above 0 and at most 1.
How dark the design turns toward the product’s silhouette, 0 to 1.
The one kind of wrap: an upright round product.
The blank’s placement it is printed in; with blankId.
The sizes the shopper picks from, for a print within its area.
One size in the size menu.
object
The print’s height, in mm.
What the menu calls the size.
The label per customer-facing language, by code: only the languages it has one in. A designer shown in a language left out reads label.
object
The print’s width, in mm.
The photo that starts selected, by its place in mockups.
The size that starts selected, by its place in printSizes.
The template’s base id; the link’s own when absent.
The size the side sells, as a value of each option its blank’s print areas change with ({"Size": "XL"}): its proofs and designs are made at that size, and a request naming another is refused. Only on a blank whose print areas change with its size; absent, the shopper’s request names the size.
object
The blank’s variants offered, by ref; empty or absent, all.
The blank’s views the side is shown in; empty or absent, all.
Carried back to returnUrl untouched, for the store to match the customer to its own session. Only with returnUrl.
The size the side sells, as a value of each option its blank’s print areas change with ({"Size": "XL"}): its proofs and designs are made at that size, and a request naming another is refused. Only on a blank whose print areas change with its size; absent, the shopper’s request names the size.
object
The blank’s variants offered, by ref; empty or absent, all.
The blank’s views the side is shown in; empty or absent, all.
Examples
Example
{ "blankId": "blank_poster_matte", "layout": "steps", "mockups": [ { "label": "Oak frame", "placementRectPx": { "h": 380, "w": 300, "x": 115, "y": 90 }, "url": "https://shop.acme.example/media/poster-oak.jpg" } ], "placementId": "front", "printSizes": [ { "heightMm": 400, "label": "30×40", "widthMm": 300 }, { "heightMm": 700, "label": "50×70", "widthMm": 500 } ], "returnUrl": "https://shop.acme.example/cart", "state": "cart-8f2c1a"}Front and back on one item: On the hosted designer, one link for both sides
{ "locale": "sv", "returnUrl": "https://shop.example/cart", "sides": [ { "blankId": "blank_tshirt", "key": "front", "label": "Front", "placementId": "front", "printSizes": [ { "heightMm": 360, "label": "Large", "widthMm": 280 }, { "heightMm": 257, "label": "Medium", "widthMm": 200 } ], "selectedPrintSizeIndex": 1, "templateId": "tshirt-front" }, { "blankId": "blank_tshirt", "key": "back", "label": "Back", "placementId": "back", "templateId": "tshirt-back" } ], "state": "cart-10482"}Naming, keeping and limiting share links: A designer link's design limit
{ "designLimit": { "count": 50, "period": "day" }, "name": "Market stall, 50 a day"}Sending the customer back to the store: The hosted designer
{ "blankId": "blank_tshirt", "locale": "sv", "placementId": "front", "printSizes": [ { "heightMm": 360, "label": "Large", "widthMm": 280 }, { "heightMm": 257, "label": "Medium", "widthMm": 200 } ], "returnUrl": "https://shop.acme.example/cart?add=tshirt-basic", "state": "cart-10482"}Responses
Section titled “Responses”The new link
object
The brand the link’s page is drawn in; null for the workspace’s default, whichever that is when it opens.
How many designs a designer link may make; null for none.
object
How many designs the link may make in its period.
total counts every design the link made; hour, day and week the last 60 minutes, 24 hours or 7 days, rolling.
When the link stops working: 24 hours after it was handed out for a link carrying state, expiresInDays days after for one that names them, and null for one that names neither, which works until withdrawn.
The link’s id, as the share-link list names it.
The language the link’s page is shown in, which its url names as ?lang=<locale>; null when it names none, and the page is shown in the workspace’s default language.
The workspace’s name for the link.
Whether a designer link’s page draws the placement frame around the shopper’s picture at rest; false for every other link.
Whether a designer link’s page draws the print area’s frame; false for every other link.
The link’s token. Shown in this response only.
The hosted designer the link opens, with ?lang=<locale> when the link names a locale.
What the link was made with that it is not built for, for whoever builds it; the shopper is shown none. sides_over_recommended: the link holds more than 4 sides. Each side is one more step on the hosted page, one more designer, canvas and photo set in the shopper’s browser, and one more proofToken[<key>] on the return address. Absent when there is nothing to warn of.
object
The most sides a designer is built for.
How many sides the link holds.
Examples
Example
{ "brandId": null, "designLimit": null, "expiresAt": 1791972000000, "id": "shl_9a8b7c6d5e4f3a2b1c0d9e8f", "locale": null, "name": null, "placementFrame": false, "printAreaFrame": false, "token": "EXAMPLE_designer_link_token_not_a_real_one", "url": "https://app.pixonaut.example/h/design/EXAMPLE_designer_link_token_not_a_real_one"}Front and back on one item: On the hosted designer, one link for both sides
{ "brandId": null, "designLimit": null, "expiresAt": 1791972000000, "id": "shl_9a8b7c6d5e4f3a2b1c0d9e8f", "locale": "sv", "name": null, "placementFrame": false, "printAreaFrame": false, "token": "EXAMPLE_designer_link_token_not_a_real_one", "url": "https://app.pixonaut.example/h/design/EXAMPLE_designer_link_token_not_a_real_one?lang=sv", "warnings": [ { "code": "sides_over_recommended", "recommended": 4, "sides": 5 } ]}Sending the customer back to the store: The hosted designer
{ "brandId": null, "designLimit": null, "expiresAt": 1790086400000, "id": "shl_9a8b7c6d5e4f3a2b1c0d9e8f", "locale": "sv", "name": null, "placementFrame": false, "printAreaFrame": false, "token": "EXAMPLE_designer_link_token_not_a_real_one", "url": "https://app.pixonaut.example/h/design/EXAMPLE_designer_link_token_not_a_real_one?lang=sv"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: return_url_not_https, return_url_off_store, invalid_input
object
Always sent with invalid_input.
Examples
invalid_input
{ "error": "invalid_input", "reason": "string"}return_url_not_https
{ "error": "return_url_not_https"}return_url_off_store
{ "error": "return_url_off_store"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: unauthorized
object
Examples
unauthorized
{ "error": "unauthorized"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: plan_limit_reached, origin_forbidden, feature_disabled
object
The feature the tenant does not have. Always sent with feature_disabled.
The limit the tenant is at: templates, connectedStores, apiKeys, shareLinks, customDomains, printsMadePerMonth (prints made without an order this month), members, orders (this month’s orders, which getting a print’s files without an order counts as), or a sandbox’s own caps: sandboxPrintsPerDay, sandboxPrintsPerMonth, sandboxOrdersPerMonth. A sandbox shares every other limit with its live workspace. Always sent with plan_limit_reached.
How many the plan allows. Always sent with plan_limit_reached.
The plan whose limit it is. Always sent with plan_limit_reached.
Examples
feature_disabled
{ "error": "feature_disabled", "feature": "api"}origin_forbidden
{ "error": "origin_forbidden"}plan_limit_reached
{ "error": "plan_limit_reached", "limit": "templates", "max": 0, "plan": "free"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: subject_not_found, brand_not_found
object
Examples
brand_not_found
{ "error": "brand_not_found"}subject_not_found
{ "error": "subject_not_found"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: share_link_name_taken, layout_out_of_date
object
The link holding the name. Always sent with share_link_name_taken.
Always sent with layout_out_of_date.
Examples
layout_out_of_date
{ "error": "layout_out_of_date", "reason": "string"}share_link_name_taken
{ "error": "share_link_name_taken", "holderId": "string"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: unknown_placement, print_size_illegal, placement_unfilled, variant_row_invalid, unknown_layout, layout_wrong_ratio, linked_templates_differ, share_link_name_too_long, payload_too_large
object
Sent with payload_too_large.
The size’s place in the side’s menu. Always sent with print_size_illegal.
Always sent with payload_too_large.
The longest name a link may have. Always sent with share_link_name_too_long.
Always sent with placement_unfilled.
With print_size_illegal: too_large: larger than the placement takes. print_size_not_area: smaller than a placement printed across its whole area. wrong_ratio: further from the template’s shape than its tolerance allows. Always sent with print_size_illegal, placement_unfilled, variant_row_invalid, layout_wrong_ratio. With print_size_illegal: one of too_large, print_size_not_area, wrong_ratio.
The side’s key; null on a link with one side. Always sent with print_size_illegal.
Examples
layout_wrong_ratio
{ "error": "layout_wrong_ratio", "reason": "string"}linked_templates_differ
{ "error": "linked_templates_differ"}payload_too_large
{ "error": "payload_too_large", "maxBytes": 0}placement_unfilled
{ "error": "placement_unfilled", "placement": "string", "reason": "string"}print_size_illegal
{ "error": "print_size_illegal", "index": 0, "reason": "too_large", "side": "string"}share_link_name_too_long
{ "error": "share_link_name_too_long", "maxLength": 0}unknown_layout
{ "error": "unknown_layout"}unknown_placement
{ "error": "unknown_placement"}variant_row_invalid
{ "error": "variant_row_invalid", "reason": "string"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: rate_limited
object
Examples
rate_limited
{ "error": "rate_limited"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: db_error. A request that failed unexpectedly answers as text instead.
object
Examples
db_error
{ "error": "db_error"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Refused: lock_timeout
object
Examples
lock_timeout
{ "error": "lock_timeout"}Headers
Section titled “Headers”Every response names the request it answers in X-Request-Id: the id the request was sent with in that header, when it is well formed, else one the API gave it. Quote it when reporting a refusal or a failure: the API’s log lines for that request carry it.
Questions? Write to [email protected].