Gå til innholdet
Help for printers and users

REST API and embed guide

A server-to-server quickstart, the public OpenAPI reference, and a secure browser embed.

Base URL, credentials and scopes

Call https://YOUR-PRINTER-HOST/api/v1 on the hostname assigned to your printer. The public reference is /api/v1/openapi.json on that host; the HeyMadeIt host also serves the route-derived reference. Create scoped keys under /portal/platform/credentials. Send Authorization: Bearer YOUR_API_KEY and Accept: application/json. Keys only work for their own printer host. Keep keys on your server, rotate them when needed, and revoke unused keys. Open the interactive developer portal at /developers for searchable Swagger documentation, copyable code examples, and an importable Postman collection. AI agents can read /llms.txt, /llms-full.txt and /developers/reference.md directly.

Find or create a customer

Use GET /customers?email=person%40example.com to find your mapped customer. POST /customers requires name and email; locale is optional. Store the returned data.id against your own authenticated customer. Never let the browser choose another customer_id. Customer creation does not assign a Business licence or send a sign-in email.

POST /api/v1/customers
{"name":"Example customer","email":"[email protected]","locale":"en"}

Find a template and create an editable design

GET /templates supports category, width_mm, height_mm, pages and fields=browse. It returns published HeyMadeIt templates and your own printer templates; another printer’s templates are excluded. GET /templates/{uuid} reads one. Create a design with customer_id, title and either a format preset or width_mm and height_mm. With template, supply the trim size; omit format. For the standard API, flat designs support up to eight pages.

POST /api/v1/designs
{"customer_id":123,"title":"Business card","width_mm":85,"height_mm":55,"bleed_mm":3,"pages":1,"template":"TEMPLATE_UUID"}

Issue a one-use editor session

Create an embed key and allow the exact webshop origin, including https and any port. Your backend calls POST /editor-sessions for the authenticated customer’s design. parent_origin must be allowed. finish is save or basket. The response contains session_token, expires_in (300 seconds) and redeem_url. The token can be redeemed once by POST; it must not be placed in a URL. Never return the API key to the browser.

POST /api/v1/editor-sessions
{"customer_id":123,"design":"DESIGN_UUID","embed_key":"PUBLIC_EMBED_KEY","parent_origin":"https://shop.example.com","finish":"basket"}

Open the browser SDK

Serve the SDK from your printer host. Your own /design-session endpoint must authenticate the shopper and request a fresh server-side session. The SDK opens an iframe and validates messages by origin and frame. onComplete means the design was saved; your backend must verify ownership, product, quantity and payment before placing an order. close() removes the iframe.

<script src="https://YOUR-PRINTER-HOST/embed/v1/sdk.js"></script>
<div id="design-editor"></div>
<script>
async function openDesigner() {
  const response = await fetch("/design-session", {method: "POST"});
  if (!response.ok) throw new Error("Could not start editor");
  const session = await response.json();
  window.HeyMadeIt.open({
    container: "#design-editor",
    sessionToken: session.session_token,
    onComplete: data => console.log("Saved design", data),
    onClose: reason => console.log("Closed", reason)
  });
}
</script>

Queue and download a print PDF

POST /designs/{uuid}/exports with format pdf_print returns HTTP 202 and data.uuid. Poll GET /exports/{uuid}; status done provides file_url. Download that relative URL from your server with the same bearer key. Other states include queued, rendering, encoding, failed and canceled; handle failures and expiry explicitly. layout can be pages or spreads. Use bleed:true for document bleed, and marks:true for crop marks.

POST /api/v1/designs/DESIGN_UUID/exports
{"format":"pdf_print","bleed":true,"marks":true,"layout":"pages"}

Products, shipping and idempotent orders

Products use width, height, unit and quantity prices in minor currency units (net_ore). Shipping uses /shipping-methods. POST /orders requires an Idempotency-Key header, customer_id, payment_method, shipping_method_id and lines with product, design and quantity. Reuse the key only for the same order body. Read GET /orders/{uuid} for production files. Use PATCH /orders/{uuid} with paid or cancelled only after your server has verified the payment or cancellation. For external payment, HeyMadeIt does not verify the provider for you.

POST /api/v1/orders
Idempotency-Key: shop-order-1042
{"customer_id":123,"payment_method":"external","shipping_method_id":7,"lines":[{"product":"PRODUCT_UUID","design":"DESIGN_UUID","quantity":100}]}

Business licence allocation

GET /client-licences returns allowance, allocated and company teams. POST /client-licences requires customer_id (the company owner), name and seats. Omit team to create a company team; send an existing team UUID to resize it. All teams draw from the same printer allowance. API keys need licences:read or licences:write. The owner and pending invitations count toward the company’s seats. DELETE /client-licences/{team} releases the company allocation without deleting its work.

POST /api/v1/client-licences
{"customer_id":123,"name":"Example company","seats":3}

Errors, pagination and rate limits

401 means a missing, revoked or wrong-host key. 403 means missing scope, a disabled integration or insufficient access. 404 also protects resources owned by another tenant. 409 signals a state or idempotency conflict. 422 returns validation errors. 429 means wait and retry with backoff. Lists expose data and pagination metadata; most catalogue lists accept per_page up to 100. Respect endpoint throttles in the OpenAPI reference. MCP uses user OAuth/access tokens, not these merchant API keys.