Node.js · Sieraden try-on API

Sieraden try-on API in Node.js

In één zin

Stel PHOTTA_API_KEY in env in, schrijf een kleine fetch-helper voor https://api.photta.app/api/v1 met een Bearer-sleutel, POST naar /api/v1/tryon/jewelry en poll vervolgens elke 3 seconden /api/v1/tryon/jewelry/{id} totdat de status completed is.

  • Typische duur: 1.5–4 min
  • Credits: 5 credits bij 2K · 6 credits bij 4K
  • Verwerking: async, polling
  • Limieten: 600 requests/min
  • Authenticatie: Bearer key

Elk getal op deze pagina is afkomstig uit de Photta-API-documentatie · gecontroleerd

POST/api/v1/tryon/jewelry
const res = await fetch("https://api.photta.app/api/v1/tryon/jewelry", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "jewelry_image": "https://cdn.yourstore.com/products/gold-necklace.jpg",
    "jewelry_type": "necklace",
    "mannequin_id": "mnk_j9k1l2",
    "background": "soft window light on dark velvet",
    "resolution": "2K",
    "aspect_ratio": "3:4",
    "user_instruction": "Make the pendant 10% smaller."
  }),
});
const { data } = await res.json(); // data.id, data.status

async function waitFor(id) {
  for (let attempt = 0; attempt < 120; attempt++) {
    const res = await fetch(`https://api.photta.app/api/v1/tryon/jewelry/${id}`, { headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}` } });
    const { data } = await res.json();
    if (data.status === "completed") return data.output_url;
    if (data.status === "failed") throw new Error(data.error_message ?? "generation failed");
    await new Promise((r) => setTimeout(r, 3000));
  }
  throw new Error("timed out after 6 minutes");
}

In één oogopslag

In één oogopslag

Endpoint
POST /api/v1/tryon/jewelry
Authenticatie
Bearer API key
Verwerking
Asynchroon — poll het status-endpoint
Typische duur
1.5–4 min
Credits
5 credits bij 2K · 6 credits bij 4K
Beeldverhoudingen
3:4 · 1:1 · 4:3 · 9:16 · 16:9
Invoerlimieten
Tot 10 MB per afbeelding; JPEG, PNG, WebP
Idempotent
Nee

Hoe het werkt

Vijf stappen, ongeveer vijf minuten van registratie tot eerste afbeelding.

  1. Stap 1

    Meld je aan en genereer een sleutel

    Maak een account aan op ai.photta.app. Open het Developers-gedeelte van het dashboard, klik op Generate API key en kopieer de live-sleutel. Deze begint met `photta_live_` gevolgd door 32 hex-tekens.

  2. Stap 2

    Sla de sleutel op in env, niet in broncode

    Voeg `PHOTTA_API_KEY=...` toe aan `.env` (of de secret store van je platform) en laad deze via `process.env`. Commit de sleutel nooit; importeer hem nooit in een bestand gemarkeerd met `'use client'` — de bundler trekt hem anders naar de browser.

    node --version   # 18 or later ships fetch
    echo "PHOTTA_API_KEY=photta_live_xxxxx" >> .env
  3. Stap 3

    Schrijf een kleine fetch-helper

    Eén wrapper van 20 regels rond `fetch()` regelt de basis-URL, Authorization-header, JSON-body en foutnormalisatie. Dit is de enige abstractie die je nodig hebt totdat er een officiële SDK verschijnt.

    // photta.js — one helper for every endpoint
    const BASE = "https://api.photta.app/api/v1";
    export async function photta(path, init = {}) {
      const res = await fetch(BASE + path, { ...init, headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json", ...(init.headers ?? {}) } });
      const body = await res.json();
      if (!res.ok) throw Object.assign(new Error(body.error?.message ?? res.statusText), { status: res.status, retryAfter: res.headers.get("Retry-After"), body });
      return body;
    }
  4. Stap 4

    Verstuur een try-on en voer polling uit

    Voer een POST uit naar `/api/v1/tryon/jewelry` met de gedocumenteerde voorbeeld-body — de onderstaande code bevat elk veld. De API retourneert direct een generatie-ID. Voer elke 3 seconden polling uit op `/api/v1/tryon/jewelry/{id}` totdat `status === 'completed'`.

    const res = await fetch("https://api.photta.app/api/v1/tryon/jewelry", {
      method: "POST",
      headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
      body: JSON.stringify({
        "jewelry_image": "https://cdn.yourstore.com/products/gold-necklace.jpg",
        "jewelry_type": "necklace",
        "mannequin_id": "mnk_j9k1l2",
        "background": "soft window light on dark velvet",
        "resolution": "2K",
        "aspect_ratio": "3:4",
        "user_instruction": "Make the pendant 10% smaller."
      }),
    });
    const { data } = await res.json(); // data.id, data.status
    
    async function waitFor(id) {
      for (let attempt = 0; attempt < 120; attempt++) {
        const res = await fetch(`https://api.photta.app/api/v1/tryon/jewelry/${id}`, { headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}` } });
        const { data } = await res.json();
        if (data.status === "completed") return data.output_url;
        if (data.status === "failed") throw new Error(data.error_message ?? "generation failed");
        await new Promise((r) => setTimeout(r, 3000));
      }
      throw new Error("timed out after 6 minutes");
    }
  5. Stap 5

    Sla het resultaat op

    De voltooide payload bevat `output_url` en `thumbnail_url`. Haal de bytes één keer op en sla ze op in je eigen objectopslag — de URL's zijn stabiel, maar je product mag voor de weergave niet afhankelijk zijn van het CDN van Photta.

Errors

400invalid_request_error
The request is malformed or contains invalid parameters.
401authentication_error
The API key is missing, invalid, or expired.
402insufficient_credits_error
Your account does not have enough credits.
404not_found_error
The requested resource does not exist.
409conflict_error
The request conflicts with current state — e.g. your concurrent-batch cap is reached.
429rate_limit_error
Too many requests. Slow down and retry.Retry-After: 30
500api_error
An internal server error occurred. Retry later.
try {
  await photta("/tryon/jewelry", { method: "POST", body: JSON.stringify({
    "jewelry_image": "https://cdn.yourstore.com/products/gold-necklace.jpg",
    "jewelry_type": "necklace",
    "mannequin_id": "mnk_j9k1l2",
    "background": "soft window light on dark velvet",
    "resolution": "2K",
    "aspect_ratio": "3:4",
    "user_instruction": "Make the pendant 10% smaller."
  }) });
} catch (err) {
  if (err.status === 402) console.error("insufficient_credits_error: top up before retrying");
  else if (err.status === 429) await new Promise((r) => setTimeout(r, Number(err.retryAfter ?? 30) * 1000));
  else throw err;
}

Limieten

  • 600 verzoeken per minuut per API key (Vast venster; de limiet is identiek op elk abonnement)
  • Een 429 bevat Retry-After: 30 seconden
  • Tot 10 MB per afbeelding
  • Formaten: JPEG, PNG, WebP
  • Gelijktijdige batches per abonnement: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
  • Uitsluitend polling — de API stuurt geen webhooks.

Waarom een helper beter is dan een clientbibliotheek — voorlopig

  • Node 18+ levert standaard fetch mee — geen runtime-afhankelijkheden
  • Dezelfde helper werkt binnen Next.js route handlers, server actions en elke worker
  • Houd de API-sleutel in env; importeer de helper nooit vanuit een 'use client'-module, anders lekt de bundler deze
  • Werkt met elke wachtrij of cron: BullMQ, Inngest, Trigger.dev, Vercel Cron, Cloudflare Queues

Wat het niet doet

  • Nog geen officieel @photta/node-package — REST is momenteel het enige pad
  • Polling is het enige signaal voor voltooiing; de API verstuurt geen webhooks
  • Alleen een Bearer-sleutel; er is geen OAuth client-credentials-flow

Veelgestelde vragen van developers

Is er een officiële Photta Node.js-SDK?

Nog niet. Het gedocumenteerde pad is rechtstreekse REST via de native fetch van Node — de helper op deze pagina is het volledige integratie-oppervlak, en hij werkt hetzelfde voor elke functionaliteit.

Welke Node.js-versies worden ondersteund?

Alles wat native `fetch` ondersteunt — wat neerkomt op Node 18 en nieuwer. Op Node 16 gebruik je een polyfill met `node-fetch` of voer je een upgrade uit. De rest van de code is standaard ECMAScript 2020 (async/await, template literals, dynamische imports), dus er zijn geen verdere runtime-vereisten.

Hoe authenticeer ik vanuit Node?

Stuur `Authorization: Bearer photta_live_xxx` mee bij elk verzoek. Plaats de sleutel in een omgevingsvariabele en laad deze via `process.env`; importeer deze nooit vanuit een bestand dat in de browser draait.

Hoe ga ik om met de generatietijd?

Het generatie-endpoint is volledig asynchroon. Een POST retourneert direct een generatie-ID met `status: 'processing'`. Voer elke 3–5 seconden polling uit met `GET /api/v1/tryon/jewelry/{id}` totdat `status` verandert in `completed` of `failed`, en begrens het aantal pogingen zodat een vastgelopen taak een verzoek niet laat hangen.

Kan ik de API aanroepen binnen Next.js?

Ja — vanuit een route handler (`app/**/route.ts`), een server action (`'use server'`) of middleware. Houd de API-sleutel op de server; importeer de helper nooit vanuit een `'use client'`-bestand. Voor langdurige taken die de functietime-out van Vercel overschrijden, delegeer je de polling naar een wachtrij (Inngest, Trigger.dev, BullMQ) en stuur je de generatie-ID terug naar de browser, zodat deze je eigen status-endpoint kan pollen.

Hoe signaleert de API fouten?

Niet-2xx-antwoorden bevatten een JSON-body met een `error`-object: `type`, `code`, `message` en een request-ID voor ondersteuning. Veelvoorkomende situaties: 400 invalid_request_error waarbij `param` naar het ongeldige veld verwijst; 402 insufficient_credits met aantallen voor `required` en `available`; 429 rate_limit_exceeded met `retry_after` in seconden en een bijbehorende Retry-After-header. 5xx-fouten kunnen veilig opnieuw worden geprobeerd met exponentiële back-off.

Probeer de API in vijf minuten

Genereer een Photta API-sleutel, plak het bovenstaande cURL-fragment en je hebt je eerste afbeelding op een model voordat de koffie klaar is.

  • 1.5–4 min
  • 5 credits bij 2K · 6 credits bij 4K
  • async, polling
  • 600 requests/min
  • Bearer key