API mockupów i packshotów 3D suplementów

Wyślij projekt etykiety (i kartonika) na wykrojniku naszego opakowania – od razu dostaniesz interaktywny podgląd 3D do osadzenia na stronie, a po chwili komplet packshotów 2000 × 2000 px, grafikę „Skład” i podgląd 3D na przezroczystym tle. Ten sam silnik, którym liczymy packshoty w kreatorze.

Kreator auralab360: konfigurator Omega-3 w kapsułkach z logo marki na słoiku i kartoniku w podglądzie 3D

Co daje API

Jedno zlecenie z plikiem etykiety – a wynik wygląda dokładnie tak jak packshoty, które klienci kupują w kreatorze.

WynikKiedyPostać
Interaktywny podgląd 3Dod razu w odpowiedzi na zlecenieadres strony do osadzenia w ramce (viewer.url, gotowy kod viewer.embed) – obraca się, przybliża, działa na telefonie
Packshotypo chwili (zwykle kilkanaście sekund)11–12 ujęć produktu (butelka 11, słoik i blister 12), bez kartonika mniej – JPEG 2000 × 2000 px: na bieli, na tle w kolorze etykiety, na ciemnym tle, trzy sztuki, otwarte opakowanie, zbliżenie…
Grafika „Skład”razem z packshotamiinfografika z produktem i tabelą składu w porcji dziennej (z receptury produktu albo z Twojej tabeli) – JPEG 2000 × 2000 px
Podgląd 3D na przezroczystym tlerazem z packshotamiPNG 1200 × 1200 px z cieniem w kanale alfa – do wstawienia na stronę
ZIPgdy jest choć jeden wynikwszystkie gotowe pliki pod jednym podpisanym adresem

Klucz API wydajemy partnerom – agencjom, sklepom i markom, które projektują etykiety u siebie. Napisz do nas albo na kontakt@auralab360.pl: ustalimy limit renderów i adres webhooka. Na próbę dostaniesz klucz próbny – wyniki mają wtedy znak wodny „auralab360 · podgląd” i najwyżej 1200 px, a podgląd 3D plakietkę „Podgląd”.

Jak to działa

Podgląd 3D rysuje przeglądarka oglądającego, a packshoty liczy węzeł renderujący – komputer z kartą graficzną, który pobiera zlecenia z kolejki.

  1. 1Wybierz opakowanie (GET /packagings) albo produkt z naszego katalogu (GET /products) i pobierz jego wykrojnik (PDF).
  2. 2Zaprojektuj etykietę na wykrojniku – strona ze spadem; samą etykietę bez spadu też przyjmiemy.
  3. 3Wyślij POST /renders z plikiem. Odpowiedź 202 przychodzi od razu: render w stanie queued i adres podglądu 3D (viewer.url) – możesz go pokazać klientowi, zanim powstaną packshoty.
  4. 4Węzeł renderujący liczy wyniki po kolei – stan i postęp w GET /renders/{id}; pole queue mówi, ile renderów czeka przed Twoim i czy węzeł jest w sieci.
  5. 5Gdy render się skończy, wyślemy webhook render.succeeded (albo czekaj zapytaniem GET /renders/{id}?wait=30).
  6. 6Pobierz pliki z podpisanych adresów (outputs[].url) albo cały ZIP (archive.url) – bez klucza, przez 7 dni.

Czas: komplet 12 wyników 2000 px to zwykle kilkanaście sekund od chwili, gdy węzeł weźmie zlecenie. Gdy węzeł jest wyłączony, render czeka w kolejce (queue.workersOnline: 0, estimatedSeconds: null) i zacznie się liczyć, gdy węzeł wróci – nic nie przepada, a podgląd 3D działa od razu.

Szybki start

Adres API: https://kreator.auralab360.pl/api/v1. Odpowiedzi i błędy to JSON (UTF-8); komunikaty są po polsku – można je pokazać użytkownikowi.

1. Opakowania i wykrojniki

curl
# klucz API trzymaj w zmiennej środowiska – nigdy w kodzie strony
export AURA_API_KEY=al_live_…

curl https://kreator.auralab360.pl/api/v1/packagings \
  -H "Authorization: Bearer $AURA_API_KEY"

# wykrojnik etykiety (adres z pola label.dieline)
curl -o wykrojnik-etykieta.pdf "https://kreator.auralab360.pl/files/dieline/2026/09/VeYazr5KhSSCwHNX98uu6g.pdf"
# wykrojnik kartonika (box.dieline)
curl -o wykrojnik-kartonik.pdf "https://kreator.auralab360.pl/files/dieline/2026/09/bfOy8gqTKcjkpf7eujPE8w.pdf"
odpowiedź 200 (fragment)
{
  "object": "list",
  "data": [
    {
      "id": "dropper-50",
      "name": "Butelka z pipetą 50 ml (szkło bursztynowe)",
      "model": "dropper",
      "volume": "50 ml",
      "label": {
        "size": [120, 55],
        "page": [126, 61],
        "trim": [120, 55],
        "dieline": "https://kreator.auralab360.pl/files/dieline/2026/09/VeYazr5KhSSCwHNX98uu6g.pdf"
      },
      "box": {
        "size": [38, 38, 117],
        "page": [171.32, 229.83],
        "trim": null,
        "dieline": "https://kreator.auralab360.pl/files/dieline/2026/09/bfOy8gqTKcjkpf7eujPE8w.pdf",
        "required": false
      },
      "caps": [
        { "id": "czarna", "name": "Czarna" },
        { "id": "biala", "name": "Biała" },
        { "id": "zlota", "name": "Złota" }
      ],
      "defaultCap": "czarna",
      "contents": {
        "kind": "liquid",
        "options": [
          { "id": "olej", "name": "Olej" },
          { "id": "ekstrakt", "name": "Ekstrakt (ciemny)" },
          { "id": "woda", "name": "Płyn wodny (jasny)" }
        ],
        "default": "olej"
      },
      "shots": {
        "withBox": ["hero", "color", "front", "left", "back", "duo", "trio", "open", "flatlay", "detail", "dark"],
        "withoutBox": ["color", "front", "left", "back", "trio", "open", "detail", "dark"]
      },
      "products": 39,
      "orderable": true
    }
  ]
}

2. Zlecenie renderu

curl – multipart
curl https://kreator.auralab360.pl/api/v1/renders \
  -H "Authorization: Bearer $AURA_API_KEY" \
  -H "Idempotency-Key: zh-50-etykieta-v1" \
  -F packaging=dropper-50 \
  -F name="Zielona herbata" \
  -F cap=zlota \
  -F label=@etykieta.pdf \
  -F box=@kartonik.pdf \
  -F 'metadata={"sku":"ZH-50"}'

Odpowiedź przychodzi od razu (202 Accepted, nagłówek Location). Idempotency-Key chroni przed podwójnym zleceniem, gdy ponawiasz zapytanie po zerwanym połączeniu – ten sam klucz zwraca ten sam render.

odpowiedź 202 (wyniki – fragment)
{
  "id": "rnd_7Gk2LmQ9TxWb3Hc5Rv1Z",
  "object": "render",
  "status": "queued",
  "createdAt": "2026-10-09T09:15:39.721Z",
  "startedAt": null,
  "finishedAt": null,
  "expiresAt": "2026-11-08T09:15:39.719Z",
  "purged": false,
  "packaging": {
    "id": "dropper-50",
    "name": "Butelka z pipetą 50 ml (szkło bursztynowe)",
    "volume": "50 ml",
    "model": "dropper"
  },
  "product": null,
  "input": {
    "label": {
      "name": "etykieta.pdf",
      "kind": "pdf",
      "fit": "page",
      "page": [126, 61],
      "dpi": null,
      "dielineRemoved": false,
      "warning": null
    },
    "box": {
      "name": "kartonik.pdf",
      "kind": "pdf",
      "fit": "page",
      "page": [171.32, 229.83],
      "dpi": null,
      "dielineRemoved": false,
      "warning": null
    },
    "cap": "zlota",
    "contents": "olej",
    "size": 2000,
    "watermark": false,
    "outputs": ["hero", "color", "front", "left", "back", "duo", "trio", "open", "flatlay", "detail", "dark", "preview"]
  },
  "progress": { "done": 0, "total": 12 },
  "queue": { "position": 1, "workersOnline": 1, "estimatedSeconds": 9 },
  "viewer": {
    "url": "https://kreator.auralab360.pl/podglad-3d/q3Xn8LpV0aT2bR6sKe1WmY9cHd4fJg7u",
    "embed": "<iframe src=\"https://kreator.auralab360.pl/podglad-3d/q3Xn8LpV0aT2bR6sKe1WmY9cHd4fJg7u\" title=\"Podgląd 3D\" width=\"100%\" height=\"560\" style=\"border:0\" allow=\"fullscreen\" loading=\"lazy\"></iframe>"
  },
  "outputs": [
    {
      "name": "hero",
      "kind": "shot",
      "label": "Butelka z kartonikiem",
      "status": "pending",
      "contentType": null,
      "width": null,
      "height": null,
      "bytes": null,
      "url": null,
      "downloadUrl": null,
      "error": null
    },
    {
      "name": "color",
      "kind": "shot",
      "label": "Na tle w kolorze etykiety",
      "status": "pending",
      "contentType": null,
      "width": null,
      "height": null,
      "bytes": null,
      "url": null,
      "downloadUrl": null,
      "error": null
    }
  ],
  "archive": null,
  "error": null,
  "warnings": [],
  "metadata": { "sku": "ZH-50" }
}

3. Czekanie na wynik i pliki

curl – stan renderu
# czeka do 30 s, aż render się skończy (powtarzaj, dopóki status to queued albo processing)
curl "https://kreator.auralab360.pl/api/v1/renders/rnd_7Gk2LmQ9TxWb3Hc5Rv1Z?wait=30" \
  -H "Authorization: Bearer $AURA_API_KEY"
curl – ZIP
# podpisany adres – działa bez klucza do terminu z parametru expires
curl -o packshoty.zip "https://kreator.auralab360.pl/api/v1/renders/rnd_7Gk2LmQ9TxWb3Hc5Rv1Z/archive.zip?expires=1792142540&signature=Jm7fQ2v9xKpL0aZr8sYbWc3nT5dE1gHu6iOkRqVwXyA"
odpowiedź 200 – gotowe (wyniki – fragment)
{
  "id": "rnd_7Gk2LmQ9TxWb3Hc5Rv1Z",
  "object": "render",
  "status": "succeeded",
  "createdAt": "2026-10-09T09:15:39.721Z",
  "startedAt": "2026-10-09T09:15:41.102Z",
  "finishedAt": "2026-10-09T09:15:47.659Z",
  "expiresAt": "2026-11-08T09:15:39.719Z",
  "purged": false,
  "packaging": {
    "id": "dropper-50",
    "name": "Butelka z pipetą 50 ml (szkło bursztynowe)",
    "volume": "50 ml",
    "model": "dropper"
  },
  "product": null,
  "input": {
    "label": {
      "name": "etykieta.pdf",
      "kind": "pdf",
      "fit": "page",
      "page": [126, 61],
      "dpi": null,
      "dielineRemoved": false,
      "warning": null
    },
    "box": {
      "name": "kartonik.pdf",
      "kind": "pdf",
      "fit": "page",
      "page": [171.32, 229.83],
      "dpi": null,
      "dielineRemoved": false,
      "warning": null
    },
    "cap": "zlota",
    "contents": "olej",
    "size": 2000,
    "watermark": false,
    "outputs": ["hero", "color", "front", "left", "back", "duo", "trio", "open", "flatlay", "detail", "dark", "preview"]
  },
  "progress": { "done": 12, "total": 12 },
  "queue": null,
  "viewer": {
    "url": "https://kreator.auralab360.pl/podglad-3d/q3Xn8LpV0aT2bR6sKe1WmY9cHd4fJg7u",
    "embed": "<iframe src=\"https://kreator.auralab360.pl/podglad-3d/q3Xn8LpV0aT2bR6sKe1WmY9cHd4fJg7u\" title=\"Podgląd 3D\" width=\"100%\" height=\"560\" style=\"border:0\" allow=\"fullscreen\" loading=\"lazy\"></iframe>"
  },
  "outputs": [
    {
      "name": "hero",
      "kind": "shot",
      "label": "Butelka z kartonikiem",
      "status": "ready",
      "contentType": "image/jpeg",
      "width": 2000,
      "height": 2000,
      "bytes": 280732,
      "url": "https://kreator.auralab360.pl/api/v1/renders/rnd_7Gk2LmQ9TxWb3Hc5Rv1Z/outputs/hero?expires=1792142540&signature=Jm7fQ2v9xKpL0aZr8sYbWc3nT5dE1gHu6iOkRqVwXyA",
      "downloadUrl": "https://kreator.auralab360.pl/api/v1/renders/rnd_7Gk2LmQ9TxWb3Hc5Rv1Z/outputs/hero?expires=1792142540&signature=Jm7fQ2v9xKpL0aZr8sYbWc3nT5dE1gHu6iOkRqVwXyA&download=1",
      "error": null
    },
    {
      "name": "front",
      "kind": "shot",
      "label": "Front",
      "status": "ready",
      "contentType": "image/jpeg",
      "width": 2000,
      "height": 2000,
      "bytes": 148891,
      "url": "https://kreator.auralab360.pl/api/v1/renders/rnd_7Gk2LmQ9TxWb3Hc5Rv1Z/outputs/front?expires=1792142540&signature=Jm7fQ2v9xKpL0aZr8sYbWc3nT5dE1gHu6iOkRqVwXyA",
      "downloadUrl": "https://kreator.auralab360.pl/api/v1/renders/rnd_7Gk2LmQ9TxWb3Hc5Rv1Z/outputs/front?expires=1792142540&signature=Jm7fQ2v9xKpL0aZr8sYbWc3nT5dE1gHu6iOkRqVwXyA&download=1",
      "error": null
    },
    {
      "name": "preview",
      "kind": "preview",
      "label": "Podgląd 3D (przezroczyste tło)",
      "status": "ready",
      "contentType": "image/png",
      "width": 1200,
      "height": 1200,
      "bytes": 529808,
      "url": "https://kreator.auralab360.pl/api/v1/renders/rnd_7Gk2LmQ9TxWb3Hc5Rv1Z/outputs/preview?expires=1792142540&signature=Jm7fQ2v9xKpL0aZr8sYbWc3nT5dE1gHu6iOkRqVwXyA",
      "downloadUrl": "https://kreator.auralab360.pl/api/v1/renders/rnd_7Gk2LmQ9TxWb3Hc5Rv1Z/outputs/preview?expires=1792142540&signature=Jm7fQ2v9xKpL0aZr8sYbWc3nT5dE1gHu6iOkRqVwXyA&download=1",
      "error": null
    }
  ],
  "archive": {
    "url": "https://kreator.auralab360.pl/api/v1/renders/rnd_7Gk2LmQ9TxWb3Hc5Rv1Z/archive.zip?expires=1792142540&signature=Jm7fQ2v9xKpL0aZr8sYbWc3nT5dE1gHu6iOkRqVwXyA"
  },
  "error": null,
  "warnings": [],
  "metadata": { "sku": "ZH-50" }
}

Wszystkie metody

MetodaŚcieżka (od https://kreator.auralab360.pl/api/v1)Opis
GET/meKlucz: nazwa, zużycie w miesiącu, limity, adres webhooka
GET/packagingsOpakowania z wykrojnikami, zakrętkami, zawartością i zestawem ujęć
GET/packagings/{id}Jedno opakowanie
GET/productsProdukty katalogu, które można narysować z Twoją etykietą (?q=, ?packaging=)
POST/rendersZlecenie renderu – odpowiedź 202 z podglądem 3D od razu
GET/rendersTwoje rendery, najnowsze najpierw (?limit=, ?after=, ?status=)
GET/renders/{id}Stan i wyniki renderu (?wait=1…30 – czekanie na koniec)
DELETE/renders/{id}Anulowanie renderu i usunięcie jego plików
GET/renders/{id}/outputs/{name}Plik wyniku – z kluczem albo z podpisanego adresu
GET/renders/{id}/archive.zipWszystkie gotowe wyniki w ZIP-ie
POST/webhooks/testPróbny webhook ping na adres klucza
GET/openapi.jsonOpis API w formacie OpenAPI 3.1 (bez klucza)

Klucz API i limity

  • Każde zapytanie: nagłówek Authorization: Bearer al_live_… (albo X-API-Key: al_live_…). Bez klucza – 401 z kodem API_KEY_MISSING, ze złym – API_KEY_INVALID.
  • API jest dla serwerów: nie wysyłamy nagłówków CORS, a klucza nie wolno umieszczać w kodzie strony ani aplikacji mobilnej. Klientowi pokazuj podgląd 3D i podpisane adresy plików – one klucza nie wymagają.
  • Jeden klucz na integrację. Klucz, który wyciekł, unieważniamy od razu i wydajemy nowy.
  • Bez klucza działają tylko: strona startowa i opis API (GET /api/v1, GET /openapi.json), podgląd 3D po adresie z renderu i pliki wyników z podpisanych adresów.
LimitWartość
Zapytania jednym kluczem120 na minutę (nagłówki X-RateLimit-Limit, X-RateLimit-Remaining)
Nowe rendery jednym kluczem30 na minutę
Rendery w kolejce i w trakcie liczenianajwyżej 50 na klucz
Pliki wysłane jednym kluczem2 GB na godzinę (liczone z Content-Length zlecenia)
Rendery w miesiącuwedług umowy (bez limitu albo ustalona liczba; miesiąc kalendarzowy, czas polski, nieudane się nie liczą)
Zapytania z jednego adresu IP300 na minutę (wszystkie klucze razem)
Plik etykiety albo kartonikado 25 MB, obraz do 20 000 px na dłuższym boku
Treść zapytania JSONdo 32 MB (plik w base64 jest o ⅓ większy) – większe pliki jako multipart albo adres URL
Przechowywanie plików renderu30 dni od zlecenia (expiresAt)
GET /me – klucz, zużycie i limity
{
  "object": "api_key",
  "name": "Agencja XYZ – sklep",
  "prefix": "al_live_7Gk2",
  "watermark": false,
  "maxSize": 2000,
  "usage": { "month": 148, "quota": 1000, "resetsAt": "2026-10-31T23:00:00.000Z", "open": 2 },
  "limits": { "requestsPerMinute": 120, "rendersPerMinute": 30, "openRenders": 50 },
  "webhook": { "url": "https://twoj-sklep.pl/aura/webhook", "signed": true }
}

Po przekroczeniu limitu odpowiadamy 429 z nagłówkiem Retry-After (sekundy). Limit miesięczny odnawia się pierwszego dnia miesiąca o północy czasu polskiego (usage.resetsAt).

Opakowania i wykrojniki

Lista z naszego katalogu – ta sama, którą zwraca GET /packagings. Identyfikator to rodzaj opakowania i wielkość; plik etykiety ma mieć stronę wykrojnika ze spadem (albo sam wymiar etykiety).

OpakowanieEtykietaKartonikOpcje
jar-glass-150Słoik mały (szkło bursztynowe)ujęć: 12 z kartonikiem, 9 bez
netto 150 × 55 mmplik: 156 × 61 mm ze spadem albo 150 × 55 mmPobierz wykrojnik (PDF)
50,5 × 50,5 × 90,5 mm – opcjonalnyplik: 219,31 × 228,31 mmPobierz wykrojnik (PDF)
zakrętka (cap)czarna (domyślna)zlotasrebrna
zawartość (contents)kapsulki (domyślnie)tabletkisoftgelproszek
jar-glass-250Słoik mały (szkło bursztynowe)ujęć: 12 z kartonikiem, 9 bez
netto 150 × 55 mmplik: 156 × 61 mm ze spadem albo 150 × 55 mmPobierz wykrojnik (PDF)
50,5 × 50,5 × 90,5 mm – opcjonalnyplik: 219,31 × 228,31 mmPobierz wykrojnik (PDF)
zakrętka (cap)czarna (domyślna)zlotasrebrna
zawartość (contents)kapsulkitabletkisoftgel (domyślnie)proszek
jar-glass-300Słoik duży (szkło bursztynowe)ujęć: 12 z kartonikiem, 9 bez
netto 185 × 65 mmplik: 191 × 71 mm ze spadem albo 185 × 65 mmPobierz wykrojnik (PDF)
62 × 62 × 113 mm – opcjonalnyplik: 266,31 × 273,81 mmPobierz wykrojnik (PDF)
zakrętka (cap)czarna (domyślna)zlotasrebrna
zawartość (contents)kapsulkitabletki (domyślnie)softgelproszek
blister-100Kartonik z blistrem – probiotyki – w sklepie chwilowo niedostępne (render działa)ujęć: 12
–
70 × 29,5 × 96 mm – wymaganyplik: 217,31 × 187,81 mmPobierz wykrojnik (PDF)
zawartość (contents)kapsulki (domyślnie)tabletkisoftgel
blister-150Kartonik z blistrem – duży – w sklepie chwilowo niedostępne (render działa)ujęć: 12
–
70 × 54 × 95 mm – wymaganyplik: 270,31 × 235,21 mmPobierz wykrojnik (PDF)
zawartość (contents)kapsulki (domyślnie)tabletkisoftgel
dropper-15Butelka z pipetą 15 ml (szkło bursztynowe)ujęć: 11 z kartonikiem, 8 bez
netto 93 × 32 mmplik: 99 × 38 mm ze spadem albo 93 × 32 mmPobierz wykrojnik (PDF)
30 × 30 × 95 mm – opcjonalnyplik: 171,15 × 223,01 mmPobierz wykrojnik (PDF)
zakrętka (cap)czarna (domyślna)bialazlota
zawartość (contents)olej (domyślnie)ekstraktwoda
dropper-50Butelka z pipetą 50 ml (szkło bursztynowe)ujęć: 11 z kartonikiem, 8 bez
netto 120 × 55 mmplik: 126 × 61 mm ze spadem albo 120 × 55 mmPobierz wykrojnik (PDF)
38 × 38 × 117 mm – opcjonalnyplik: 171,32 × 229,83 mmPobierz wykrojnik (PDF)
zakrętka (cap)czarna (domyślna)bialazlota
zawartość (contents)olej (domyślnie)ekstraktwoda
jar-hdpe-2000Słoik HDPE 2 l (biały)ujęć: 9
netto 415 × 115 mmplik: 421 × 121 mm ze spadem albo 415 × 115 mmPobierz wykrojnik (PDF)
–
zakrętka (cap)biala (domyślna)
zawartość (contents)proszek (domyślnie)
  • Wymiary w milimetrach; label.page i box.page to strona pliku, który wysyłasz (PDF – z tolerancją 2 mm i 2% proporcji, obraz – 2% proporcji). Wykrojnik to PDF tej strony: etykieta ze spadem 3 mm z każdej strony i linią cięcia.
  • Blister to sam kartonik: wysyłasz tylko plik box. Przy butelce i słoiku kartonik jest opcjonalny – bez niego nie ma ujęć z kartonikiem.
  • Tryb produktu: zamiast packaging podaj product (identyfikator albo SKU z GET /products) – opakowanie, zawartość (kapsułki, płyn) i grafika „Skład” z naszej receptury. Wykrojnik i strona pliku – z pól label i box produktu (mogą się różnić od opakowania).
  • Zawartość (contents) widać przez szkło i w ujęciach z otwartym opakowaniem: kapsułki, tabletki, kapsułki żelowe albo proszek w słoiku, a w butelce z pipetą – olej, ciemny ekstrakt albo jasny płyn wodny.

Plik etykiety i kartonika

  • PDF (pierwsza strona), PNG albo JPG, do 25 MB; rodzaj sprawdzamy po zawartości, nie po rozszerzeniu.
  • Strona pliku = strona wykrojnika ze spadem (page). Etykietę przyjmiemy też w samym wymiarze netto (trim) – spad dopełnimy, przedłużając krawędzie projektu (input.label.fit: "trim" i uwaga w warnings). Kartonik – tylko na stronie wykrojnika.
  • Obraz: co najmniej 300 dpi w rozmiarze arkusza. Od 150 do 299 dpi – przyjmiemy z uwagą w warnings (drobny tekst może być nieostry na zbliżeniach), poniżej 150 dpi – odrzucimy (OWN_ART_DPI). PDF z grafiką wektorową jest zawsze ostry.
  • Linie wykrojnika zostawione w pliku (cięcie, zagięcia, opis) ukrywamy na podglądzie – dielineRemoved: true. Plik pusty albo sam wykrojnik bez projektu odrzucamy (OWN_ART_EMPTY).
  • Treści etykiety (skład, ostrzeżenia, dane producenta, kod EAN) są Twoje – niczego w pliku nie zmieniamy ani nie sprawdzamy pod kątem przepisów.
Jak przesłaćKiedy
multipart: pliki w polach label i boxzalecane – najmniej danych, pliki do 25 MB
multipart: labelUrl, boxUrlpliki leżą na Twoim serwerze: publiczny adres https, do 25 MB, odpowiedź w 20 s, najwyżej 3 przekierowania
JSON: "label": { "url": "https://…" }to samo co wyżej, w treści JSON
JSON: "label": { "data": "<base64>", "filename": "…" }plik w treści – do ok. 23 MB (limit treści zapytania 32 MB)
curl – JSON z adresem pliku
curl https://kreator.auralab360.pl/api/v1/renders \
  -H "Authorization: Bearer $AURA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"packaging":"dropper-50","outputs":["front","color","preview"],"label":{"url":"https://twoj-serwer.pl/projekty/etykieta.pdf"}}'
curl – JSON z plikiem w base64
# plik w base64 w treści JSON (do ok. 23 MB – limit treści zapytania to 32 MB)
B64=$(base64 < etykieta.png | tr -d "\n")
curl https://kreator.auralab360.pl/api/v1/renders \
  -H "Authorization: Bearer $AURA_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"packaging\":\"dropper-50\",\"label\":{\"data\":\"$B64\",\"filename\":\"etykieta.png\"}}"

Zlecenie renderu – pola

POST /renders: multipart/form-data (pliki i pola tekstowe) albo application/json. Pola opcji są takie same w obu formach.

PoleTypWymaganeDomyślnieOpis
packagingtekstjedno z dwóch–Opakowanie z GET /packagings, np. dropper-50. Produkt zastępczy bez receptury – zawartość wybierasz polem contents.
producttekstjedno z dwóch–Produkt z katalogu (GET /products): identyfikator albo SKU. Opakowanie, zawartość i tabela „Skład” z receptury.
labelpliktak (poza blistrem)–Projekt etykiety: PDF, PNG albo JPG do 25 MB. Multipart – plik; JSON – { "data": "<base64>", "filename": "…" } albo { "url": "https://…" }.
boxplikblister – tak–Projekt kartonika (strona wykrojnika kartonika). Butelka i słoik: opcjonalny – bez niego nie ma ujęć z kartonikiem.
labelUrl, boxUrladres httpsnie–Tylko w multipart: adres pliku zamiast pliku. Pobieramy go sami (do 25 MB, 20 s, najwyżej 3 przekierowania).
captekstniezakrętka produktu albo defaultCapZakrętka z listy caps opakowania, np. czarna, zlota.
contentstekstniecontents.defaultTylko z packaging: forma (kapsulki, tabletki, softgel, proszek) albo płyn w butelce (olej, ekstrakt, woda).
outputslistaniewszystkie dostępneWybrane wyniki. Multipart: po przecinku (hero,front,back) albo powtórzone pole; JSON: tablica.
sizeliczbanie2000 (klucz próbny – 1200)Bok packshotów w px, kwadrat, od 800 do limitu klucza (domyślnie 2000, najwyżej 3000).
nametekst ≤ 120z `composition` – taknazwa produktu z kataloguNazwa produktu – tytuł grafiki „Skład” i początek nazw plików. Wymagana, gdy zamawiasz grafikę „Skład” z własnej tabeli (composition).
color#rrggbbniegłówny kolor etykietyKolor nagłówka tabeli na grafice „Skład”.
compositionobiektnie–Tylko z packaging: tabela grafiki „Skład” (schemat niżej). Multipart – JSON w polu tekstowym.
webhookUrladres httpsnieadres webhooka kluczaWebhook tylko dla tego renderu – podpisany sekretem webhooka klucza (każdy klucz go ma, także bez domyślnego adresu).
metadataobiektnie–Twoje dane (do 20 pól, razem do 4000 znaków; wartości: tekst do 500 znaków, liczba, prawda/fałsz, null) – wracają w renderze i webhooku. Multipart – JSON w polu tekstowym.
Idempotency-Keynagłóweknie–Do 100 znaków ASCII bez spacji. Ten sam klucz – ten sam render (bezpieczne ponowienie po zerwanym połączeniu); odpowiedź 200 z nagłówkiem Idempotent-Replayed: true.

Tabela „Skład” (composition)

  • rows – od 1 do 40 wierszy: name (do 120 znaków), amount (liczba albo tekst), unit (np. mg, µg), rws – %RWS (liczba albo tekst; liczba 100,6 → „101%”, 7,25 → „7,3%”), sub: true – wiersz „w tym”, wcięty.
  • portion – porcja dzienna („2 kapsułki”), ingredients – pełny skład (do 3000 znaków), usage – sposób użycia (do 1000 znaków).
  • Liczby zapisujemy po polsku (przecinek, spacja tysięcy); kolumna %RWS pojawia się, gdy choć jeden wiersz ją ma.
  • Tylko z packaging – produkt z katalogu ma tabelę z receptury. Bez tabeli wynik composition jest niedostępny (UNKNOWN_OUTPUT).
composition – JSON
{
  "portion": "2 kapsułki",
  "rows": [
    { "name": "Ekstrakt z ashwagandhy", "amount": 600, "unit": "mg" },
    { "name": "w tym witanolidy", "amount": 30, "unit": "mg", "sub": true },
    { "name": "Witamina B6", "amount": 1.4, "unit": "mg", "rws": 100 },
    { "name": "Magnez", "amount": 112.5, "unit": "mg", "rws": 30 }
  ],
  "ingredients": "Składniki: ekstrakt z korzenia ashwagandhy (Withania somnifera), cytrynian magnezu, otoczka kapsułki – hydroksypropylometyloceluloza, chlorowodorek pirydoksyny.",
  "usage": "Dorośli: 2 kapsułki dziennie, popijając wodą."
}
curl – tabela w multipart
curl https://kreator.auralab360.pl/api/v1/renders \
  -H "Authorization: Bearer $AURA_API_KEY" \
  -F packaging=dropper-50 \
  -F name="Spokojny sen" \
  -F outputs=front,composition \
  -F label=@etykieta.pdf \
  -F 'composition={"portion":"2 kapsułki","rows":[{"name":"Witamina B6","amount":1.4,"unit":"mg","rws":100}]}'

Wyniki

Nazwy wyników (pole outputs) – ujęcia w kolejności galerii, grafika „Skład” i podgląd 3D. Zestaw zależy od opakowania i od tego, czy wysłałeś kartonik.

WynikButelka z pipetąSłoikBlister w kartoniku
heroButelka z kartonikiem · wymaga pliku boxSłoik z kartonikiem · wymaga pliku boxKartonik z blistrem
colorNa tle w kolorze etykietyNa tle w kolorze etykietyNa tle w kolorze kartonika
frontFrontFrontKartonik – front
left¾ z góry¾ z góryKartonik ¾ z góry
backTył ze składemTył ze składemKartonik – tył ze składem
duoButelka obok kartonika · wymaga pliku boxSłoik obok kartonika · wymaga pliku boxKartonik obok blistra
trioTrzy butelkiTrzy słoikiTrzy kartoniki
flat––Blister na płasko
openZ wyjętą pipetąOtwarty słoik z kapsułkamiBlister z kapsułkami obok
top–Z góry – wnętrze słoika–
flatlayZ góry – na leżącym kartoniku · wymaga pliku boxZ góry – z leżącym kartonikiem · wymaga pliku boxZ góry – kartonik i blister
detailZbliżenie etykietyZbliżenie etykietyZbliżenie blistra
darkNa ciemnym tleNa ciemnym tleNa ciemnym tle
compositionSkład w porcji dziennejSkład w porcji dziennejSkład w porcji dziennej
previewPodgląd 3D (przezroczyste tło)Podgląd 3D (przezroczyste tło)Podgląd 3D (przezroczyste tło)
  • Ujęcia i grafika „Skład”: JPEG, kwadrat size × size (domyślnie 2000 px). Ujęcia „Kolor” i „Ciemne tło” są na tle studyjnym (w kolorze etykiety – z przeważającej barwy Twojego projektu), pozostałe na bieli.
  • Podgląd 3D: PNG z przezroczystym tłem i cieniem w kanale alfa, najwyżej 1200 px (przy size mniejszym niż 1200 – w tym rozmiarze).
  • Klucz próbny: wszystkie wyniki ze znakiem wodnym, najwyżej 1200 px, JPEG (także podgląd 3D – na bieli).
  • Otwarty słoik ma podpis według formy: z kapsułkami, z tabletkami albo z miarką proszku.
  • outputs[].url – podpisany adres pliku (Content-Disposition: inline), downloadUrl – to samo do pobrania. Działają bez klucza 7 dni (najdłużej do expiresAt); każde GET /renders/{id} daje świeże. Można ich użyć w <img> na Twojej stronie.
  • Z kluczem: GET /renders/{id}/outputs/{name} z nagłówkiem Authorization. Zmieniony albo przeterminowany podpis – 403 LINK_EXPIRED.
  • Nazwy plików: <nazwa>-<nr>-<wynik>.jpg, np. zielona-herbata-01-hero.jpg (nazwa z pola name, bez niej – identyfikator opakowania; podgląd 3D – .png).
  • archive.url – ZIP ze wszystkimi gotowymi wynikami (te same nazwy plików).

Stan renderu

statusZnaczenie
queuedW kolejce – czeka na węzeł renderujący. Pole queue: miejsce w kolejce, liczba węzłów w sieci, szacowany czas.
processingWęzeł liczy wyniki – progress.done rośnie, gotowe wyniki mają już adresy.
succeededGotowe. Pojedynczy wynik może mieć status: "failed" z opisem w error – pozostałe są do pobrania.
failedNie udało się po 3 próbach – opis w error. Pliki wejścia zostają do końca przechowywania.
canceledAnulowany przez DELETE – pliki usunięte, podgląd 3D i linki nie działają.
  • progress – done (wyniki gotowe albo nieudane) i total. Wynik nieudany ma status: "failed" i opis w error; render z choć jednym gotowym wynikiem kończy się jako succeeded.
  • queue (tylko w kolejce): position, workersOnline i estimatedSeconds – szacunek ze średniej ostatnich renderów; null, gdy żaden węzeł nie jest w sieci.
  • GET /renders/{id}?wait=30 – odpowiedź przyjdzie, gdy render się skończy, najpóźniej po 30 s (od 1 do 30). Zamiast odpytywać co sekundę – wywołuj w pętli.
  • GET /renders?limit=20 – lista najnowszych; następna strona: ?after= z pola next (dopóki hasMore), filtr ?status=.
  • DELETE /renders/{id} – anuluje render (także w trakcie liczenia) i usuwa jego pliki: podgląd 3D i adresy plików przestają działać, zostaje sam opis.
  • Pliki renderu (Twoje pliki i wyniki) trzymamy 30 dni (expiresAt), potem usuwamy: purged: true, viewer: null, adresy plików null. Zapisz wyniki u siebie.
  • warnings – uwagi do plików: rozdzielczość poniżej 300 dpi, ukryte linie wykrojnika, dopełniony spad.

Podgląd 3D na Twojej stronie

viewer.url to strona z interaktywnym modelem – ten sam podgląd co w konfiguratorze kreatora. Rysuje go przeglądarka oglądającego, więc działa od razu, także gdy packshoty jeszcze się liczą.

HTML
<!-- podgląd 3D na Twojej stronie: adres z pola viewer.url -->
<iframe src="https://kreator.auralab360.pl/podglad-3d/q3Xn8LpV0aT2bR6sKe1WmY9cHd4fJg7u?tlo=jasne"
  title="Podgląd 3D" width="100%" height="560" style="border:0"
  allow="fullscreen" loading="lazy"></iframe>
Parametr adresuDziałanie
tlo=jasne · tlo=ciemnetło sceny (także bg=light, bg=dark)
obrot=1model obraca się sam, dopóki ktoś go nie dotknie (także autorotate=1)
ui=0bez przycisków i podpowiedzi – sam model
  • Przeciągnięcie obraca produkt (na komputerze także pochyla), dwuklik wraca do frontu; przyciski: przód, tył, przybliżenie, tło jasne/ciemne i pełny ekran (ramka potrzebuje allow="fullscreen").
  • Na telefonie palec obraca w poziomie, dwa palce przybliżają, dwa stuknięcia wracają do frontu; w wąskiej ramce przyciski stoją w rzędzie pod modelem.
  • Stronę można osadzić w ramce na dowolnej domenie; wyszukiwarki jej nie indeksują. Adres jest dostępem do podglądu – działa do końca przechowywania renderu albo do DELETE.

Webhooki

Po zakończeniu renderu wysyłamy POST z pełnym renderem na adres webhooka – domyślny adres klucza albo webhookUrl z danego zlecenia.

ZdarzenieKiedy
render.succeededrender gotowy (pojedyncze wyniki mogą być nieudane)
render.failedrender nieudany po 3 próbach
pingpróbny – POST /webhooks/test wysyła go od razu i zwraca kod odpowiedzi Twojego serwera
  • Podpis: X-Aura-Signature: t=<unix>,v1=<hex>, gdzie hex = HMAC-SHA256 sekretem webhooka (whsec_… – dostajesz go od nas razem z kluczem; ma go każdy klucz) z tekstu <t>.<surowa treść>. Licz go z bajtów, które przyszły (przed parsowaniem JSON), porównuj w stałym czasie i odrzucaj wiadomości starsze niż 5 minut.
  • Odpowiedz kodem 2xx w ciągu 10 s (dłuższą pracę zrób w tle). Inaczej ponawiamy: do 8 prób – kolejne po 30 s, 2 min, 10 min, 30 min, 1 h, 3 h i 6 h. Odpowiedź 410 Gone kończy ponawianie. Przekierowań nie wykonujemy.
  • X-Aura-Delivery i id zdarzenia są te same przy każdym ponowieniu – zapisz je i pomiń duplikat. Kolejność dostaw nie jest gwarantowana – decyduje data.status.
  • Adres webhooka: publiczny https z nazwą domeny (adresów IP i sieci wewnętrznych nie obsługujemy).
zapytanie – nagłówki
POST /aura/webhook HTTP/1.1
Content-Type: application/json; charset=utf-8
User-Agent: AuraLab360-Webhooks/1.0
X-Aura-Event: render.succeeded
X-Aura-Delivery: cmv1x0d2k0004a95n3ytzq7e1
X-Aura-Signature: t=1760001347,v1=5f0c6e0d5a7c3e9b1f2a4d6c8e0b2a4c6e8f0a2b4c6d8e0f1a3b5c7d9e1f3a5b
treść – data to render jak w GET /renders/{id} (fragment)
{
  "id": "evt_cmv1x0c9n0002a95nhq3l5r2b",
  "type": "render.succeeded",
  "createdAt": "2026-10-09T09:15:47.660Z",
  "data": {
    "id": "rnd_7Gk2LmQ9TxWb3Hc5Rv1Z",
    "object": "render",
    "status": "succeeded",
    "finishedAt": "2026-10-09T09:15:47.659Z",
    "packaging": {
      "id": "dropper-50",
      "name": "Butelka z pipetą 50 ml (szkło bursztynowe)",
      "volume": "50 ml",
      "model": "dropper"
    },
    "progress": { "done": 12, "total": 12 },
    "viewer": { "url": "https://kreator.auralab360.pl/podglad-3d/q3Xn8LpV0aT2bR6sKe1WmY9cHd4fJg7u" },
    "outputs": [
      {
        "name": "hero",
        "kind": "shot",
        "label": "Butelka z kartonikiem",
        "status": "ready",
        "contentType": "image/jpeg",
        "width": 2000,
        "height": 2000,
        "bytes": 280732,
        "url": "https://kreator.auralab360.pl/api/v1/renders/rnd_7Gk2LmQ9TxWb3Hc5Rv1Z/outputs/hero?expires=1792142540&signature=Jm7fQ2v9xKpL0aZr8sYbWc3nT5dE1gHu6iOkRqVwXyA",
        "downloadUrl": "https://kreator.auralab360.pl/api/v1/renders/rnd_7Gk2LmQ9TxWb3Hc5Rv1Z/outputs/hero?expires=1792142540&signature=Jm7fQ2v9xKpL0aZr8sYbWc3nT5dE1gHu6iOkRqVwXyA&download=1",
        "error": null
      }
    ],
    "archive": {
      "url": "https://kreator.auralab360.pl/api/v1/renders/rnd_7Gk2LmQ9TxWb3Hc5Rv1Z/archive.zip?expires=1792142540&signature=Jm7fQ2v9xKpL0aZr8sYbWc3nT5dE1gHu6iOkRqVwXyA"
    },
    "error": null,
    "warnings": [],
    "metadata": { "sku": "ZH-50" }
  }
}
// Node.js 18+ i Express: treść musi zostać surowa (express.raw), podpis liczymy z bajtów, które przyszły
import crypto from 'node:crypto';
import express from 'express';

const SECRET = process.env.AURA_WEBHOOK_SECRET; // whsec_… – od AuraLab360, razem z kluczem API
const app = express();

/** Podpis z nagłówka X-Aura-Signature: t=<unix>,v1=<hex> – HMAC-SHA256 z "<t>.<surowa treść>". */
function verify(header, body) {
  const parts = Object.fromEntries(String(header || '').split(',').map((p) => p.trim().split('=', 2)));
  const t = Number(parts.t);
  if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > 300 || !parts.v1) return false;
  const expected = crypto.createHmac('sha256', SECRET).update(t + '.' + body.toString('utf8')).digest('hex');
  return expected.length === parts.v1.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

app.post('/aura/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  if (!verify(req.get('X-Aura-Signature'), req.body)) return res.status(400).send('Zły podpis');
  const event = JSON.parse(req.body.toString('utf8'));
  // X-Aura-Delivery jest ten sam przy ponowieniu – zapisz go i pomiń dostawę, którą już obsłużyłeś
  if (event.type === 'render.succeeded') {
    // event.data.archive.url – ZIP ze wszystkimi wynikami; event.data.metadata – Twoje dane ze zlecenia
  }
  res.sendStatus(200); // odpowiedz w ciągu 10 s – dłuższą pracę zrób w tle
});

app.listen(3000);

Błędy

Każdy błąd ma ten sam kształt: statusCode, code (stały – do obsługi w kodzie), message (po polsku – do pokazania użytkownikowi), details (pola z problemem) i requestId (podaj go, pisząc do nas).

400 – plik nie pasuje do wykrojnika
{
  "statusCode": 400,
  "code": "OWN_ART_SIZE",
  "message": "Plik ma inny format niż wykrojnik etykiety – strona ze spadem powinna mieć 126 × 61 mm. Strona pliku: 126 × 126 mm. Pobierz wykrojnik i zaprojektuj na nim (z tłem do krawędzi strony). Plik może też mieć sam wymiar etykiety, bez spadu: 120 × 55 mm – spad dopełnimy.",
  "details": {
    "page": [126, 61],
    "trim": [120, 55]
  },
  "requestId": "req-2f"
}
422 – niedostępny wynik
{
  "statusCode": 422,
  "code": "UNKNOWN_OUTPUT",
  "message": "Popraw zaznaczone pola.",
  "details": {
    "outputs": "Niedostępne wyniki: composition. Dostępne: color, front, left, back, trio, open, detail, dark, preview. Grafika „Skład” wymaga tabeli składu (composition) albo produktu z recepturą."
  },
  "requestId": "req-30"
}
KodHTTPKiedy
API_KEY_MISSING401Brak nagłówka Authorization: Bearer … (albo X-API-Key) – także przy pobieraniu pliku bez podpisanego adresu.
API_KEY_INVALID401Nieznany, wyłączony albo unieważniony klucz.
RATE_LIMITED429Za dużo zapytań (klucza albo z adresu IP) – nagłówek Retry-After.
QUOTA_EXCEEDED429Wykorzystany miesięczny limit renderów klucza – details: used, quota, resetsAt.
QUEUE_FULL429Klucz ma już 50 renderów w kolejce albo w trakcie liczenia.
UPLOAD_LIMIT429Jednym kluczem wysłano w ostatniej godzinie ponad 2 GB plików – nagłówek Retry-After.
VALIDATION_FAILED422Błędne pole – details: nazwa pola → opis (np. brak packaging i product, zły JSON w composition).
UNKNOWN_PACKAGING422Nie ma takiego opakowania – lista: GET /packagings.
UNKNOWN_PRODUCT422Nie ma takiego produktu (identyfikatora ani SKU).
PRODUCT_NOT_RENDERABLE422Produkt w opakowaniu bez wykrojnika – nie da się go narysować przez API.
LABEL_REQUIRED422Brak pliku etykiety (pole label).
BOX_REQUIRED422Blister: brak pliku kartonika (pole box).
NO_LABEL_SHEET422Opakowanie bez etykiety (blister) albo bez wykrojnika etykiety.
NO_BOX_SHEET422Opakowanie bez kartonika (np. słoik HDPE).
UNKNOWN_CAP422Zakrętki nie ma na liście caps opakowania.
UNKNOWN_CONTENTS422Zawartości nie ma na liście contents.options opakowania.
CONTENTS_NOT_ALLOWED422contents razem z product – produkt ma zawartość z receptury.
NAME_REQUIRED422Grafika „Skład” z własnej tabeli (composition) bez nazwy produktu (name) – to tytuł grafiki.
INVALID_WEBHOOK_URL422webhookUrl nie jest publicznym adresem https z nazwą domeny albo klucz nie ma sekretu webhooków.
UNKNOWN_OUTPUT422Wynik niedostępny dla tego opakowania (np. hero bez kartonika, composition bez tabeli składu).
SIZE_NOT_ALLOWED422Rozmiar ponad limit klucza (klucz próbny – 1200 px).
OWN_ART_SIZE400Strona pliku nie pasuje do wykrojnika – w komunikacie i w details oczekiwane wymiary (page, trim).
OWN_ART_DPI400Obraz ma mniej niż 150 dpi w rozmiarze arkusza.
OWN_ART_EMPTY400Plik jest pusty albo to sam wykrojnik, bez projektu.
OWN_ART_TYPE400Plik nie jest PDF-em, PNG ani JPG-iem (sprawdzamy zawartość, nie rozszerzenie).
OWN_ART_PX400Obraz ma więcej niż 20 000 px na dłuższym boku.
INVALID_IMAGE400Uszkodzony albo niekompletny plik PNG.
PDF_UNREADABLE400Nie udało się odczytać PDF-a – zapisz go ponownie (np. PDF/X).
FILE_TOO_LARGE400Plik większy niż 25 MB.
FILE_DOWNLOAD400Nie udało się pobrać pliku spod podanego adresu (odpowiedź inna niż 200, za duży, za długo, adres wewnętrzny).
TOO_MANY_FILES400Więcej niż dwa pliki w jednym zleceniu.
UNKNOWN_FILE_FIELD400Plik w polu innym niż label i box.
DUPLICATE_FILE400Ten sam arkusz dwa razy (np. plik label i adres labelUrl).
PAYLOAD_TOO_LARGE413Treść JSON ponad 32 MB – duże pliki wysyłaj jako multipart albo adres URL.
PACKAGING_NOT_FOUND404GET /packagings/{id} – nie ma takiego opakowania.
RENDER_NOT_FOUND404Nie ma takiego renderu albo należy do innego klucza.
OUTPUT_NOT_FOUND404Wynik nie jest (jeszcze albo już) dostępny.
LINK_EXPIRED403Podpisany adres wygasł albo jest zmieniony (i nie ma klucza API właściciela renderu) – pobierz render ponownie po nowe linki.
STORAGE_FULL507Chwilowy brak miejsca na serwerze – spróbuj za kilka minut.

W renderze nieudanym error.code to RENDER_FAILED; błędy pojedynczych wyników są w outputs[].error. Na błędy 5xx i zerwane połączenia odpowiadaj ponowieniem z tym samym Idempotency-Key.

Przykłady integracji

Zlecenie z plikiem etykiety i kartonika, czekanie na wynik i zapis ZIP-u – bez dodatkowych bibliotek (PHP: cURL, Python: requests).

// Node.js 18+ (fetch, FormData i Blob wbudowane) – zlecenie, czekanie na wynik, ZIP na dysk
import { readFile, writeFile } from 'node:fs/promises';

const API = 'https://kreator.auralab360.pl/api/v1';
const auth = { Authorization: 'Bearer ' + process.env.AURA_API_KEY };
const file = async (path) => new Blob([await readFile(path)], { type: 'application/pdf' });

const form = new FormData();
form.append('packaging', 'dropper-50');
form.append('name', 'Zielona herbata');
form.append('cap', 'zlota');
form.append('label', await file('etykieta.pdf'), 'etykieta.pdf');
form.append('box', await file('kartonik.pdf'), 'kartonik.pdf');
form.append('metadata', JSON.stringify({ sku: 'ZH-50' }));

let res = await fetch(API + '/renders', { method: 'POST', headers: { ...auth, 'Idempotency-Key': 'zh-50-etykieta-v1' }, body: form });
let render = await res.json();
if (!res.ok) throw new Error(render.code + ': ' + render.message);
console.log('Podgląd 3D:', render.viewer.url);

const deadline = Date.now() + 15 * 60_000;
while ((render.status === 'queued' || render.status === 'processing') && Date.now() < deadline) {
  res = await fetch(API + '/renders/' + render.id + '?wait=30', { headers: auth });
  render = await res.json();
}
if (render.status !== 'succeeded') throw new Error(render.error ? render.error.message : 'Render: ' + render.status);

const zip = await fetch(render.archive.url); // podpisany adres – bez klucza
await writeFile('packshoty-' + render.id + '.zip', Buffer.from(await zip.arrayBuffer()));
for (const o of render.outputs) console.log(o.name, o.status, o.url || o.error);

OpenAPI i wersje

  • Pełny opis API w formacie OpenAPI 3.1: https://kreator.auralab360.pl/api/v1/openapi.json – do importu w Postmanie lub Insomni (Import → adres) albo do wygenerowania klienta (np. openapi-generator).
  • Wersja w adresie: /api/v1. W jej ramach zmiany są tylko dodające – nowe pola, opakowania, ujęcia i kody błędów – więc ignoruj pola, których nie znasz. Zmianę niezgodną wstecz wprowadzimy jako /api/v2 i zapowiemy z wyprzedzeniem.
  • Nowe opakowania pojawiają się w GET /packagings same, gdy dodamy je do katalogu.

Chcesz podłączyć API?

Napisz, do czego potrzebujesz podglądów i packshotów – przygotujemy klucz (najpierw próbny) i pomożemy w integracji.