Skip to content

Sending the customer back to the store

A store can send its customer to a page Pixonaut hosts and get them back to its own: to make a design on the hosted designer, to correct one they already made, or to decide a proof. The store’s server hands out the page’s link, with its secret key or a connected store’s integration key, naming where the customer returns to and a state of its own. The page sends the customer back with that state, and with the proof they approved when there is one.

Page Handed out with Sends the customer back
Hosted designer POST /v1/templates/{id}/designer-links On approving, with state and proofToken; on cancelling, with state
Hosted correction page POST /v1/designs/{id}/correction-links On approving, with state and proofToken; on cancelling, with state
Proof page POST /v1/share-links Once the customer asks for changes, with state

The return address

returnUrl is where the page sends the customer, and state is carried back to it untouched: Pixonaut never reads it. Put in state whatever lets the store match the customer to its own session, a cart key or a signed nonce, and check it when the customer arrives. state is taken only with a returnUrl.

returnUrl must be on one of the origins the workspace’s publishable keys are allowed on, so a connected store returns to its own site, and in production it must be https. Otherwise the link is refused 400 return_url_off_store or 400 return_url_not_https. It is fixed when the link is handed out, so the page can be made to send the customer nowhere else.

The page adds its parameters to the store’s own query and keeps the rest of the address as it was: state, and proofToken when it brings back a proof. A proofToken already in returnUrl is dropped, and so is a state when the link carries none; the link’s own state replaces one already there.

The hosted designer

A store that does not run the designer on its own page hands out a hosted designer for one of its templates, with what it sells the template on: the blank and placement, its size menu and its photos, as the SDK takes them on a store’s page.

POST /v1/templates/tshirt-basic/designer-links
Authorization: Bearer ik_live_...
Content-Type: application/json
{
  "blankId": "blank_tshirt",
  "placementId": "front",
  "printSizes": [
    { "widthMm": 280, "heightMm": 360, "label": "Large" },
    { "widthMm": 200, "heightMm": 257, "label": "Medium" }
  ],
  "returnUrl": "https://shop.acme.example/cart?add=tshirt-basic",
  "state": "cart-10482",
  "locale": "sv"
}
{
  "id": "shl_9a8b7c6d5e4f3a2b1c0d9e8f",
  "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",
  "expiresAt": 1790086400000,
  "name": null,
  "brandId": null,
  "designLimit": null,
  "printAreaFrame": false,
  "placementFrame": false,
  "locale": "sv"
}

Send the customer to url. The link follows the template’s live version. A link carrying state names one shopper’s visit and works for 24 hours after it is handed out; one without state works until it is withdrawn.

When the customer approves their design, the page makes a proof and sends them to https://shop.acme.example/cart?add=tshirt-basic&state=cart-10482&proofToken=…. Nothing is stored yet: the store’s server checks state, keeps the proofToken with the cart line, and commits it with its key as a proof from its own page is committed (A connected store, from connect to delivery). If the customer cancels, they are sent to the same address with state alone.

A front and a back are one link with sides, which returns a proof for each side under its key, proofToken[front]=…&proofToken[back]=… (Front and back on one item). Without a returnUrl, the page commits the design itself and shows the customer its id, and nothing is sent back to the store.

Correcting a design from the store

A customer who wants to change a design they already made, from the cart or after asking for changes, corrects that design rather than making a new one. The store’s server hands out a correction link for it:

POST /v1/designs/6f1c8a2b-3d4e-4f5a-8b6c-7d8e9f0a1b2c/correction-links
Authorization: Bearer ik_live_...
Content-Type: application/json
{
  "returnUrl": "https://shop.acme.example/account/designs?edit=6f1c8a2b",
  "state": "edit-7c1e"
}
{
  "id": "shl_5d0c9e3b7a1f2e4d6c8b0a91",
  "token": "EXAMPLE_correction_link_token_not_a_real_one",
  "url": "https://app.pixonaut.example/h/correct/EXAMPLE_correction_link_token_not_a_real_one",
  "expiresAt": 1790007200000,
  "name": null,
  "brandId": null
}

A correction link works for 2 hours after it is handed out, for that one design only. A design that takes no correction, because it was rejected or one of its prints has an order, is refused 409 not_editable; duplicate an ordered one instead (Design to order).

The link opens the design in one of two places:

  • On the store’s own page. Hand out the link with no returnUrl, and mount the designer with its token, from an origin the store’s publishable key allows:

    const designer = await Pixonaut.mount('#pixonaut', {
      correctionLink: token,
      design: designId,
    });
    const { proofToken } = await designer.approve();

    url is then null: the link opens no page of its own.

  • On the hosted correction page. With a returnUrl, send the customer to url. When they approve, the page sends them to https://shop.acme.example/account/designs?edit=6f1c8a2b&state=edit-7c1e&proofToken=…; when they cancel, to the same address with state alone.

Either way, approving makes a proof of the correction and changes nothing. The store’s server makes it the design’s next revision with PATCH /v1/designs/{id}, sending the proof’s token with its key:

{ "proofToken": "EXAMPLE_correction_proof_token_not_a_real_one" }
{
  "revision": 2,
  "edited": true,
  "proofId": "prf_9c1e2d3f4a5b6c7d8e9f0a1b",
  "printFloorDpi": 150,
  "lowResolution": []
}

With edited: true, the store receives design.edited with the new revision. The design is back to committed, its approval cleared, so the store approves it again once the customer has agreed, with an edit consent and the new revision as expectedRevision:

{
  "consent": { "kind": "edit", "at": 1790000200000, "ref": "edit-7c1e" },
  "expectedRevision": 2
}

A customer who approves without changing anything leaves the design as it was: the answer is edited: false with the current revision and proof, no design.edited is sent, and an approval the design had stands. Branch on edited rather than waiting for the event.

A design corrected elsewhere since the customer opened it refuses the correction 409 revision_changed: open it again, and the customer starts from the design as it is now.

The proof page

A deciding proof page, handed out as the store’s server hands out any proof page (A connected store, from connect to delivery), can send the customer back to the store once they have asked for changes, so the store opens the design for them to correct. Name the return address, the state, and the language the page is shown in:

{
  "kind": "proof-page",
  "subjectId": "6f1c8a2b-3d4e-4f5a-8b6c-7d8e9f0a1b2c",
  "mayDecide": true,
  "returnUrl": "https://shop.acme.example/account/designs?edit=6f1c8a2b",
  "state": "edit-7c1e",
  "locale": "sv"
}

Once the customer’s request is taken, the page sends them to https://shop.acme.example/account/designs?edit=6f1c8a2b&state=edit-7c1e, with nothing else; design.changes_requested carries what they asked. The store then hands out a correction link, as above. Approving and rejecting keep the customer on the page. A link with a return keeps a proof page’s own lifetime: a customer may sit on a proof for weeks. Without returnUrl, the page keeps the customer and says their request was sent. locale is any customer-facing language, by its code, and the link’s url then carries ?lang=<locale>; absent, the page is in the workspace’s default language.

Questions? Write to [email protected].

Status · Terms of service · Privacy policy · Subprocessors