Em cinco passos
- Peça ao estúdio uma conta de parceiro: recebe uma chave e as suas condições — em conta ou pré-pagamento, um limite de crédito, um desconto.
- Envie cada imagem (
POST /uploads) e guarde o id que recebe. - Orçamente a encomenda (
POST /quote): cada linha, as opções de envio, o IVA, o total — e se entraria logo em produção. - Faça-a (
POST /orders) com a sua referência e umaIdempotency-Key. É orçamentada de novo aqui; envieexpected_totalpara que um preço que mudou seja recusado, nunca cobrado. - Acompanhe-a no seu webhook, ou pergunte
GET /orders?updated_since=de vez em quando.
Uma conta de parceiro, uma chave, uma pergunta: info@xyz-prints.com.
Autenticação
Cada pedido leva a sua chave de parceiro no cabeçalho Authorization: Bearer <chave>. A chave só abre esta API, e só as suas encomendas e ficheiros. Guarde-a no seu servidor — nunca num navegador ou numa aplicação. O estúdio cria e revoga chaves: peça uma nova se ela for exposta. Pode também restringir a sua chave aos endereços de onde os seus servidores chamam, para que uma chave exposta não sirva em mais lado nenhum.
curl \
-H "Authorization: Bearer $XYZ_KEY" \
https://www.xyz-prints.com/api/v1/partnerOs valores são em EUR com IVA incluído, como na loja; a taxa segue o país de entrega e o seu número de IVA, verificado no VIES. Os preços são sempre calculados aqui — o seu sistema nunca calcula valores.
Ficheiros
Envie cada imagem uma vez, como campo file de multipart/form-data. Formatos: tiff, jpg, png, pdf, psd, heic, bmp. Até 2048 MB por ficheiro; um pedido único leva até 8 MB, por isso envie o que for maior em partes. Um PDF dá um id por página. Um ficheiro não encomendado em 72 horas é apagado.
curl \
-H "Authorization: Bearer $XYZ_KEY" \
-F "file=@harbour-at-dusk.tif" \
https://www.xyz-prints.com/api/v1/partner/uploads201 — Resposta
{
"files": [
{
"id": "k3Fq9w2LxP0aZt7c",
"name": "harbour-at-dusk.tif",
"bytes": 88213504,
"width_px": 7200,
"height_px": 9000,
"dpi": 300,
"dpi_assumed": false,
"colour": {
"mode": "RGB",
"bit_depth": 16,
"profile": true,
"assigned": null
},
"expires_at": "2026-09-28T10:00:00.000Z"
}
]
}Em partes: corte o ficheiro em partes do mesmo tamanho (a última pode ser menor) e envie cada uma por POST em multipart com session (o seu id para o ficheiro: até 30 letras, algarismos, - e _), index (a partir de 0), total, chunk_size, size (o ficheiro inteiro, em bytes), name e chunk. Cada parte responde 202; a última responde 201 com o ficheiro.
A resposta dá os píxeis da imagem, a resolução que declara e o seu perfil de cor. A resolução na impressão depende do tamanho encomendado: o orçamento avisa abaixo de 100 DPI, o que o estúdio considera uma impressão razoável.
O que se pode encomendar
GET /catalogue lista os ids de hoje para cada tipo de linha. Abaixo, a mesma lista, lida agora.
curl \
-H "Authorization: Bearer $XYZ_KEY" \
https://www.xyz-prints.com/api/v1/partner/catalogueImpressões fine-art kind: "print"
5682 | Hahnemühle German Etching 310g | rolo, até 110 × 1200 cm · 310 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5683 | Hahnemühle Museum Etching 350g | rolo, até 110 × 1200 cm · 350 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5684 | Hahnemühle PhotoRag 308g | rolo, até 110 × 1200 cm · 308 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5698 | Hahnemühle PhotoRag Baryta 315g | rolo, até 110 × 1200 cm · 315 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5685 | Hahnemühle William Turner 310g | rolo, até 110 × 1200 cm · 310 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5686 | Canson Infinity Edition Etching Rag 310g | rolo, até 110 × 1200 cm · 310 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5687 | Canson Infinity Platine Fibre Rag 310g | rolo, até 110 × 1200 cm · 310 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5937 | Canson Infinity Baryta Photographique 310g | rolo, até 110 × 1200 cm · 310 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5934 | Canson Infinity Rag Photographique II 310g | rolo, até 61 × 1200 cm · 310 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5688 | Hahnemühle Photo Pearl 310g | rolo, até 110 × 1200 cm · 310 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5689 | Hahnemühle Photo Luster 260g | rolo, até 110 × 1200 cm · 260 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5871 | Canson Infinity PhotoGloss Premium RC 270g | rolo, até 61 × 1200 cm · 270 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5690 | XYZ White Velvet 270g | rolo, até 110 × 1200 cm · 270 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5691 | Hahnemühle Studio Enhanced 210g | rolo, até 110 × 1200 cm · 210 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5692 | Hahnemühle Art Canvas Smooth 370g | rolo, até 110 × 1200 cm · 370 g/m² |
5872 | Canson Museum ProCanvas WC | rolo, até 110 × 1200 cm · 385 g/m² |
5699 | Awagami Murakumo Kozo Select Natural 42g | rolo, até 91 × 1200 cm · 42 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5694 | Awagami Kozo White 70g | rolo, até 110 × 1200 cm · 70 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5702 | Transparent film 165µ | rolo, até 61 × 1200 cm · 100 g/m² · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5696 | Fedrigoni Arena White Smooth 350g | folhas 51 × 72 51 × 72, 72 × 102 cm 72 × 102 cm · 350 g/m² · frente e verso · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
5697 | Fedrigoni Arena White Rough 300g | folhas 51 × 72 51 × 72, 72 × 102 cm 72 × 102 cm · 300 g/m² · frente e verso · montagens: pvc-4mm-white, pvc-5mm-white, dibond-3mm, museum-board-1-6mm, museum-board-2-2mm, pvc-5mm-black |
Opções
Uma linha “print”
Todas as linhas têm kind e qty (1–999); estes são os restantes.
| Campo | Tipo | O que é |
|---|---|---|
paper_idobrigatório | integer | O papel, pelo seu id no catálogo. |
width_cmobrigatório | number | Largura da impressão tal como fica pendurada, em cm. Num papel de folha cortada, um dos seus formatos (em qualquer sentido). |
height_cmobrigatório | number | Altura da impressão tal como fica pendurada, em cm. |
fileobrigatório | string | A imagem: um id de upload de POST /uploads. Um PDF dá um id por página. |
fit | "fit" | "fill" por omissão "fit" | fit = a imagem inteira, o maior possível, com papel à vista onde as proporções diferem. fill = a impressão coberta de ponta a ponta, a imagem recortada a partir do centro. |
border_cm | number por omissão 0 | Margem branca a toda a volta, em cm. Uma folha cortada mantém sempre pelo menos a sua margem não imprimível. |
rotate | 0 | 90 | 180 | 270 por omissão 0 | Rodar a imagem no sentido dos ponteiros do relógio antes de a colocar, em graus. |
crop | object | Manter parte da imagem: {"x", "y", "w", "h"} em frações 0–1 da largura e altura (após a orientação EXIF). Cortado antes de fit ou fill. |
back_file | string | Frente e verso, num papel de folha cortada que imprime as duas faces: o id de upload do verso. Mesmo fit, margem e rotação. |
back_blank | boolean por omissão false | Frente e verso com o verso em branco (a última página ímpar de um documento). |
mount | string | Montar a impressão numa placa, pelo id (options.mounts). Não com frente e verso. |
subframe | string | Uma grade de suspensão atrás da montagem, pelo id (options.subframes). Requer mount. |
subframe_pct | number por omissão 60 | O tamanho da grade em percentagem da impressão (o catálogo dá o intervalo). |
frame | string | Emoldurar a impressão, pelo id (options.frames). Não com frente e verso. |
glazing | string | O vidro da moldura, pelo id (options.glazings), ou "none". Por omissão: o primeiro oferecido. |
matt | string | Um passe-partout dentro da moldura, pelo id (options.matts). |
matt_cm | number por omissão 5 | A largura do passe-partout a toda a volta, em cm (0–20). |
note | string | Uma palavra para o estúdio sobre esta impressão (até 500 caracteres). |
Exemplo
{
"kind": "print",
"qty": 2,
"paper_id": 101,
"width_cm": 40,
"height_cm": 50,
"file": "upl_…",
"fit": "fill",
"border_cm": 2
}Produtos kind: "product"
gift-card-50 | Gift card — €50 | €50.00 |
film-scan-35mm | Film scanning — 35 mm frame | €6.00 |
Uma linha “product”
Todas as linhas têm kind e qty (1–999); estes são os restantes.
| Campo | Tipo | O que é |
|---|---|---|
productobrigatório | string | O artigo, pelo seu slug (ou SKU) no catálogo. |
variant | string | A opção, pelo seu id no catálogo — obrigatória quando o artigo tem opções. |
note | string | Uma palavra para o estúdio sobre esta linha (até 500 caracteres). |
Exemplo
{
"kind": "product",
"qty": 3,
"product": "the-slug"
}Orçamente
POST /quote aceita o corpo de uma encomenda, sem a referência, e não grava nada. Responde o preço de cada linha, as opções de envio, o IVA e o total, avisos sobre as imagens (resolução baixa, recorte) e would_be: o estado em que a encomenda começaria hoje, com as suas condições.
curl \
-H "Authorization: Bearer $XYZ_KEY" \
-H "Content-Type: application/json" \
-d @order.json \
https://www.xyz-prints.com/api/v1/partner/quoteorder.json — Exemplo
{
"lines": [
{
"kind": "print",
"qty": 2,
"paper_id": 101,
"width_cm": 40,
"height_cm": 50,
"file": "k3Fq9w2LxP0aZt7c",
"fit": "fill",
"border_cm": 2
}
],
"delivery": {
"mode": "ship"
},
"ship_to": {
"first_name": "Ana",
"last_name": "Silva",
"address_1": "Rua das Flores 12",
"city": "Porto",
"postcode": "4050-262",
"country": "PT",
"phone": "+351 912 345 678"
},
"note": "Gift — no invoice in the parcel."
}Resposta
{
"quote": {
"currency": "EUR",
"lines": [
{
"kind": "print",
"name": "Hahnemühle Photo Rag 308",
"qty": 2,
"unit_price": 54.12,
"total": 108.24,
"vat_rate": 23,
"details": [
{
"name": "File",
"value": "harbour-at-dusk.tif"
},
{
"name": "Sheet",
"value": "40 × 50 cm"
},
{
"name": "Image",
"value": "36 × 46 cm"
}
]
}
],
"warnings": [
{
"line": 0,
"code": "cropped",
"message": "fill cuts 3.2% of the picture away to cover the print; send fit to keep all of it."
}
],
"delivery": {
"mode": "ship",
"service": "ctt_express",
"label": "CTT Expresso",
"options": [
{
"id": "ctt_express",
"label": "CTT Expresso",
"price": 12.05,
"days": [
1,
2
]
}
]
},
"totals": {
"goods": 108.24,
"discount": 0,
"shipping": 12.05,
"vat": 22.49,
"total": 120.29
},
"vat": {
"rate": 23,
"exempt": false,
"reason": null,
"number": "PT509999999",
"status": "valid_domestic"
},
"would_be": {
"state": "in_production",
"holds": []
}
}
}Encomende
POST /orders exige o cabeçalho Idempotency-Key: repetir com a mesma chave devolve o primeiro resultado e nunca cria uma segunda encomenda. A sua referência também é única — uma segunda encomenda com ela é recusada e a primeira vem na resposta. Envie expected_total, o total que o /quote lhe deu, e um preço que entretanto mudou é recusado (409 price_changed) em vez de cobrado.
curl \
-H "Authorization: Bearer $XYZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: SHOP-10482-1" \
-d @order.json \
https://www.xyz-prints.com/api/v1/partner/ordersorder.json — Exemplo
{
"reference": "SHOP-10482",
"lines": [
{
"kind": "print",
"qty": 2,
"paper_id": 101,
"width_cm": 40,
"height_cm": 50,
"file": "k3Fq9w2LxP0aZt7c",
"fit": "fill",
"border_cm": 2
}
],
"delivery": {
"mode": "ship"
},
"ship_to": {
"first_name": "Ana",
"last_name": "Silva",
"address_1": "Rua das Flores 12",
"city": "Porto",
"postcode": "4050-262",
"country": "PT",
"phone": "+351 912 345 678"
},
"note": "Gift — no invoice in the parcel.",
"expected_total": 120.29
}201 — Resposta
{
"order": {
"number": 6214,
"reference": "SHOP-10482",
"state": "in_production",
"holds": [],
"status": "processing",
"created_at": "2026-09-25T10:04:11.000Z",
"updated_at": "2026-09-25T10:04:11.000Z",
"currency": "EUR",
"payment": {
"terms": "account",
"state": "unpaid",
"paid_at": null
},
"totals": {
"goods": 108.24,
"discount": 0,
"shipping": 12.05,
"vat": 22.49,
"total": 120.29,
"refunded": 0
},
"vat": {
"rate": 23,
"exempt": false,
"reason": null,
"number": "PT509999999"
},
"delivery": {
"mode": "ship",
"service": "CTT Expresso",
"ship_to": {
"first_name": "Ana",
"last_name": "Silva",
"address_1": "Rua das Flores 12",
"city": "Porto",
"postcode": "4050-262",
"country": "PT",
"phone": "+351 912 345 678"
},
"tracking": null
},
"invoice": null,
"note": "Gift — no invoice in the parcel.",
"lines": [
{
"kind": "print",
"name": "Hahnemühle Photo Rag 308",
"qty": 2,
"unit_price": 54.12,
"total": 108.24,
"vat_rate": 23,
"details": [
{
"name": "File",
"value": "harbour-at-dusk.tif"
},
{
"name": "Sheet",
"value": "40 × 50 cm"
},
{
"name": "Image",
"value": "36 × 46 cm"
}
],
"file": "k3Fq9w2LxP0aZt7c"
}
]
},
"warnings": [
{
"line": 0,
"code": "cropped",
"message": "fill cuts 3.2% of the picture away to cover the print; send fit to keep all of it."
}
]
}ship_to é o destinatário: first_name e last_name, ou company; address_1, city, postcode e country (duas letras); telefone e e-mail ajudam a transportadora. A fatura é emitida à sua empresa — o estúdio guarda-a na sua conta. delivery.service escolhe uma das opções de envio do /quote; sem ela, a primeira. O destinatário não recebe nada do estúdio, a não ser que o peça.
Pagamento e aceitação
Em conta: uma encomenda que passa todas as verificações entra logo em produção. É faturada a si e paga por transferência contra a fatura; o estúdio regista o pagamento.
Pré-pagamento: a encomenda espera pelo valor. payment.pay_url é a sua página de pagamento (cartão, MB WAY, PayPal…); paga, entra em produção sozinha.
Uma retenção mantém a encomenda fora de produção até o estúdio a libertar; holds diz porquê:
review— A sua conta está configurada para uma pessoa ver cada encomenda primeiro.credit_limit— Esta encomenda leva o saldo em conta além do seu limite de crédito.no_credit_limit— A sua conta é a crédito, mas ainda não foi acordado um limite de crédito — o estúdio define-o e depois liberta a encomenda.
O estado de uma encomenda
| Estado | Significado |
|---|---|
awaiting_payment | Pré-pagamento: à espera do valor através de `payment.pay_url`. Paga, entra em produção sozinha. |
held | Fora de produção até o estúdio a libertar — ver `holds`. |
in_production | Aceite: a ser impressa, acabada e embalada. |
shipped | Entregue à transportadora; `delivery.tracking` quando há número. |
completed | Entregue ou levantada, e encerrada. |
cancelled | Cancelada; nada mais acontece. |
refunded | Reembolsada na totalidade. |
failed | Um pagamento falhou e a encomenda parou. |
Uma encomenda retida, ou ainda à espera do pagamento, pode ser cancelada: POST /orders/{number}/cancel. Já em produção, escreva ao estúdio.
Acompanhe
GET /orders/{number} lê uma encomenda; GET /orders?reference= encontra a sua pela sua referência. Para manter o seu sistema a par sem webhook, pergunte GET /orders?updated_since=<o último updated_at que viu>: todas as encomendas alteradas desde então, da alteração mais antiga.
curl \
-H "Authorization: Bearer $XYZ_KEY" \
"https://www.xyz-prints.com/api/v1/partner/orders?updated_since=2026-09-25T10:04:11.000Z"Webhooks
Dê ao estúdio um endereço https e cada alteração às suas encomendas é enviada por POST para lá, em JSON, com a encomenda tal como está. Responda com um 2xx em 8 segundos. Cada mensagem é enviada uma vez: se esteve em baixo, GET /orders?updated_since= põe-no a par. As mensagens podem chegar fora de ordem — compare data.order.updated_at.
| Evento | Quando |
|---|---|
order.created | A encomenda foi feita — `order.state` diz se entrou em produção, ficou retida ou aguarda pagamento. |
order.accepted | Uma encomenda retida ou pré-paga entrou em produção. |
order.paid | O pagamento foi registado. |
order.shipped | Saiu do estúdio; `tracking` quando há número. |
order.ready | Pronta a levantar no estúdio. |
order.invoiced | A fatura foi emitida; `invoice` é o seu número. |
order.completed | Encerrada. |
order.cancelled | Cancelada. |
order.refunded | Reembolsada. |
order.updated | Outra alteração (`from` e `to` para o estado). |
O «Enviar um teste» do estúdio envia o evento ping, assinado da mesma forma, sem encomenda.
order.shipped — Exemplo
{
"id": "evt_6f1c0a9b2d3e4f5a6b7c8d9e",
"event": "order.shipped",
"created_at": "2026-09-27T15:31:02.000Z",
"data": {
"tracking": "EA123456789PT",
"order": {
"number": 6214,
"reference": "SHOP-10482",
"state": "shipped",
"holds": [],
"status": "processing",
"created_at": "2026-09-25T10:04:11.000Z",
"updated_at": "2026-09-25T10:04:11.000Z",
"currency": "EUR",
"payment": {
"terms": "account",
"state": "unpaid",
"paid_at": null
},
"totals": {
"goods": 108.24,
"discount": 0,
"shipping": 12.05,
"vat": 22.49,
"total": 120.29,
"refunded": 0
},
"vat": {
"rate": 23,
"exempt": false,
"reason": null,
"number": "PT509999999"
},
"delivery": {
"mode": "ship",
"service": "CTT Expresso",
"ship_to": {
"first_name": "Ana",
"last_name": "Silva",
"address_1": "Rua das Flores 12",
"city": "Porto",
"postcode": "4050-262",
"country": "PT",
"phone": "+351 912 345 678"
},
"tracking": "EA123456789PT"
},
"invoice": null,
"note": "Gift — no invoice in the parcel.",
"lines": [
{
"kind": "print",
"name": "Hahnemühle Photo Rag 308",
"qty": 2,
"unit_price": 54.12,
"total": 108.24,
"vat_rate": 23,
"details": [
{
"name": "File",
"value": "harbour-at-dusk.tif"
},
{
"name": "Sheet",
"value": "40 × 50 cm"
},
{
"name": "Image",
"value": "36 × 46 cm"
}
],
"file": "k3Fq9w2LxP0aZt7c"
}
]
}
}
}Cada mensagem é assinada: X-WebOffice-Signature: t=<tempo unix>,v1=<HMAC-SHA256 de «t.corpo» com o seu segredo de assinatura, em hexadecimal>. Verifique-a contra o corpo tal como chegou, e recuse um t a mais de cinco minutos. O estúdio dá-lhe o segredo e pode renová-lo.
import crypto from 'node:crypto'
// raw: the request body exactly as it arrived (a string, before any JSON parsing)
// header: the X-WebOffice-Signature header; secret: your signing secret (whsec_…)
export function verified(raw, header, secret) {
const parts = Object.fromEntries(String(header).split(',').map((kv) => kv.trim().split('=')))
const t = Number(parts.t)
if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > 300) return false
const want = crypto.createHmac('sha256', secret).update(t + '.' + raw).digest('hex')
const got = String(parts.v1 || '')
return got.length === want.length && crypto.timingSafeEqual(Buffer.from(got), Buffer.from(want))
}Erros
Um erro responde um estado HTTP e { error: { code, message, fields } }; fields indica cada problema como o corpo o escreve (lines[0].width_cm). Os códigos são estáveis, as mensagens são para pessoas.
422 — Exemplo
{
"error": {
"code": "invalid_lines",
"message": "Hahnemühle Photo Rag 308: That size is too large for this paper — the largest print it can make is 111.8 × 1500 cm.",
"fields": [
{
"field": "lines[0].width_cm",
"code": "size_not_available",
"message": "Hahnemühle Photo Rag 308: That size is too large for this paper — the largest print it can make is 111.8 × 1500 cm."
}
]
}
}| Código | Significado |
|---|---|
unauthorised | Sem chave, ou não é uma chave de parceiro (401). |
partner_inactive | O parceiro da chave está desativado, ou a marca deixou de aceitar encomendas de parceiros (403). |
address_not_allowed | A sua conta só aceita pedidos dos endereços que o estúdio indicou, e este não é um deles (403). |
rate_limited | Acima de um limite — pedidos, linhas orçamentadas, encomendas por hora, ou chaves erradas de um endereço: aguarde os segundos de Retry-After (429). |
internal | Algo falhou do nosso lado; nada do que enviou estava errado. Tente de novo (500). |
storage_full | Demasiados ficheiros seus à espera de encomenda: encomende-os ou deixe-os expirar primeiro (507). |
unknown_call | Pedido inexistente (404). |
invalid_query | Um parâmetro de consulta não é o que o pedido aceita — updated_since é uma data-hora ISO 8601 (400). |
invalid_body | O corpo não é o que o pedido aceita; `fields` indica cada problema (422). |
invalid_lines | Uma linha não pode ser feita como pedida — papel desconhecido, tamanho impossível, acabamento não oferecido, ficheiro que não é seu; `fields` indica a linha e o campo (422). |
no_shipping | Nenhuma transportadora leva esta encomenda a esta morada, ou o seu transporte é orçamentado à mão (422). |
unknown_service | delivery.service não é uma das opções para esta encomenda (422). |
destination_refused | O estúdio não envia para esse país (422). |
pickup_not_offered | O levantamento no estúdio não está disponível (422). |
idempotency_key_required | POST /orders exige o cabeçalho Idempotency-Key (400). |
in_progress | Outro pedido com esta Idempotency-Key ainda está a correr (409). |
duplicate_reference | Já existe uma encomenda com esta referência; vem em `order` (409). |
price_changed | O total não é o seu expected_total; o `total` atual vem na resposta — orçamente de novo (409). |
paused | O estúdio não aceita encomendas até `until` (503). |
unknown_order | Nenhuma encomenda sua com esse número (404). |
not_cancellable | A encomenda já está em produção, enviada ou concluída (409). |
unknown_file | Nenhum upload seu com esse id — expirou, ou nunca foi enviado (404). |
no_file | O upload não trazia ficheiro (400). |
format_not_accepted | Esse tipo de ficheiro não é aceite (415). |
too_large | Um ficheiro, um pedido de upload único ou o corpo de uma encomenda é grande demais: envie o ficheiro em partes, ou menos linhas (413). |
unreadable | O ficheiro não pôde ser lido como imagem ou PDF (415). |
upload_failed | Uma parte não correspondia ao upload a que dizia pertencer (400). |
Por chave, a cada dez minutos: 600 pedidos, 2000 linhas orçamentadas (um orçamento ou uma encomenda conta as suas linhas) e 8192 MB de uploads. Por conta: 120 encomendas por hora, 20 GB de ficheiros à espera de encomenda e um corpo até 1024 KB. Acima de um limite a resposta é 429 com Retry-After (507 para os ficheiros). Pedidos com uma chave errada são limitados por endereço.
Todos os pedidos
GET /partner
A quem pertence a chave: as suas condições, o saldo em conta, os limites.
GET /partner/catalogue
O que se pode encomendar hoje, tipo a tipo: os ids que uma linha indica.
POST /partner/uploads
Enviar um ficheiro. Até ao limite de um pedido como campo multipart `file`; ficheiros maiores em partes. Um PDF dá um ficheiro por página.
no_file format_not_accepted too_large unreadable upload_failed storage_full unauthorised partner_inactive address_not_allowed rate_limited unknown_call internal
GET /partner/uploads/{id}
Um ficheiro enviado: píxeis, resolução e cor, e até quando fica guardado.
unknown_file unauthorised partner_inactive address_not_allowed rate_limited unknown_call internal
POST /partner/quote
Orçamentar uma encomenda sem a fazer: linhas, opções de envio, IVA, total — e se entraria logo em produção.
too_large invalid_body invalid_lines no_shipping unknown_service destination_refused pickup_not_offered unauthorised partner_inactive address_not_allowed rate_limited unknown_call internal
POST /partner/orders
Fazer uma encomenda. Orçamentada aqui, depois aceite em produção, retida, ou à espera do pagamento — conforme as suas condições.
Idempotency-Key(obrigatório) — A sua chave única para esta tentativa (8–200 caracteres). Repetir com a mesma chave devolve a primeira resposta e nunca cria uma segunda encomenda.
idempotency_key_required in_progress too_large invalid_body invalid_lines duplicate_reference price_changed no_shipping unknown_service destination_refused pickup_not_offered paused unauthorised partner_inactive address_not_allowed rate_limited unknown_call internal
GET /partner/orders
As suas encomendas, das mais recentes — ou todas as alteradas desde um momento, da alteração mais antiga, para manter o seu sistema a par.
?updated_since=— Data-hora ISO 8601: encomendas alteradas depois dela, da mais antiga. Guarde o últimoupdated_ate pergunte de novo.?reference=— A sua referência: a encomenda que a tem.?limit=— 1–100, por omissão 50. `more: true` indica outra página.
invalid_query unauthorised partner_inactive address_not_allowed rate_limited unknown_call internal
GET /partner/orders/{number}
Uma das suas encomendas pelo número.
unknown_order unauthorised partner_inactive address_not_allowed rate_limited unknown_call internal
POST /partner/orders/{number}/cancel
Cancelar uma encomenda retida ou ainda à espera do pagamento. Já em produção, escreva ao estúdio.
unknown_order not_cancellable unauthorised partner_inactive address_not_allowed rate_limited unknown_call internal
GET /partner/openapi.json
Esta descrição em OpenAPI 3.1, para o seu gerador de código. Junte ?brand=<slug> para os campos de linha de uma marca.
O mesmo, em OpenAPI 3.1, para um gerador de código: https://www.xyz-prints.com/api/v1/partner/openapi.json?brand=xyz-prints
