Node.js · Ghost mannequin-API

Ghost mannequin-API i Node.js

I én setning

Sett PHOTTA_API_KEY i env, skriv en liten fetch-hjelper for https://api.photta.app/api/v1 med en Bearer-nøkkel, POST til /api/v1/ghost-mannequin, og poll deretter /api/v1/ghost-mannequin/{id} hvert 3. sekund til status er completed.

  • Typisk tidsbruk: 1.5–4 min
  • Credits: 4 credits ved 2K · 5 credits ved 4K
  • Prosessering: asynkron, polling
  • Grenser: 600 forespørsler/min
  • Autentisering: Bearer-nøkkel

Hvert tall på denne siden er hentet fra dokumentasjonen for Photta-API-et · verifisert

POST/api/v1/ghost-mannequin
const res = await fetch("https://api.photta.app/api/v1/ghost-mannequin", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
    "back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
    "image_side": "front",
    "angle": "side",
    "style": "3d",
    "background_color": "white",
    "resolution": "2K",
    "aspect_ratio": "3:4",
    "user_instruction": "closed front, cream interior lining",
    "brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
  }),
});
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/ghost-mannequin/${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");
}

Kort oppsummert

Kort oppsummert

Endepunkt
POST /api/v1/ghost-mannequin
Autentisering
Bearer API-nøkkel
Prosessering
Asynkron – poll status-endepunktet
Typisk tidsbruk
1.5–4 min
Credits
4 credits ved 2K · 5 credits ved 4K
Bildeformater
3:4 · 1:1 · 4:3 · 9:16 · 16:9
Inndatagrenser
Opptil 10 MB per bilde; JPEG, PNG, WebP
Idempotent
Nei

Slik fungerer det

Fem steg, omtrent fem minutter fra registrering til første bilde.

  1. Trinn 1

    Registrer deg og generer en nøkkel

    Opprett en konto på ai.photta.app. Åpne Developers-seksjonen i dashbordet, klikk Generate API key, og hent live-nøkkelen. Den starter med `photta_live_` etterfulgt av 32 hex-tegn.

  2. Trinn 2

    Lagre nøkkelen i env, ikke i kildekoden

    Legg til `PHOTTA_API_KEY=...` i `.env` (eller plattformens hemmelighetslager) og last den inn via `process.env`. Du må aldri committe nøkkelen, og aldri importere den i en fil merket med `'use client'` — bundleren vil dra den inn i nettleseren.

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

    Skriv en liten fetch-hjelper

    En 20-linjers wrapper rundt `fetch()` håndterer base-URL, Authorization-header, JSON-body og feilnormalisering. Dette er den eneste abstraksjonen du trenger inntil en offisiell SDK lanseres.

    // 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. Trinn 4

    Send inn en try-on og poll

    POST til `/api/v1/ghost-mannequin` med den dokumenterte eksempel-bodyen — koden nedenfor inneholder alle felter. API-et returnerer en genererings-ID umiddelbart. Poll `/api/v1/ghost-mannequin/{id}` hvert 3. sekund til `status === 'completed'`.

    const res = await fetch("https://api.photta.app/api/v1/ghost-mannequin", {
      method: "POST",
      headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
      body: JSON.stringify({
        "product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
        "back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
        "image_side": "front",
        "angle": "side",
        "style": "3d",
        "background_color": "white",
        "resolution": "2K",
        "aspect_ratio": "3:4",
        "user_instruction": "closed front, cream interior lining",
        "brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
      }),
    });
    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/ghost-mannequin/${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. Trinn 5

    Persister resultatet

    Den fullførte payloaden inkluderer `output_url` og `thumbnail_url`. Hent bytene én gang og lagre dem i din egen objektlagring — URL-ene er stabile, men produktet ditt bør ikke være avhengig av Phottas CDN for rendering.

Feil

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("/ghost-mannequin", { method: "POST", body: JSON.stringify({
    "product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
    "back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
    "image_side": "front",
    "angle": "side",
    "style": "3d",
    "background_color": "white",
    "resolution": "2K",
    "aspect_ratio": "3:4",
    "user_instruction": "closed front, cream interior lining",
    "brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
  }) });
} 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;
}

Grenser

  • 600 forespørsler per minutt per API-nøkkel (Fast tidsvindu; grensen er lik for alle abonnementer)
  • En 429 inneholder Retry-After: 30 sekunder
  • Opptil 10 MB per bilde
  • Formater: JPEG, PNG, WebP
  • Samtidige batcher per abonnement: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
  • Kun polling – API-et sender ikke webhooks.

Hvorfor en hjelper slår et klientbibliotek — foreløpig

  • Node 18+ leveres med native fetch — ingen kjøretidsavhengigheter
  • Den samme hjelperen fungerer i Next.js route handlers, server actions og alle typer workers
  • Hold API-nøkkelen i env; importer aldri hjelperen fra en 'use client'-modul, ellers vil bundleren lekke den
  • Fungerer med alle køer og cron-tjenester: BullMQ, Inngest, Trigger.dev, Vercel Cron, Cloudflare Queues

Hva den ikke gjør

  • Ingen offisiell @photta/node-pakke ennå — REST er den eneste veien i dag
  • Polling er det eneste fullføringssignalet; API-et sender ingen webhooks
  • Kun Bearer-nøkkel; det finnes ingen OAuth client-credentials-flyt

Spørsmål utviklere stiller

Finnes det en offisiell Photta Node.js-SDK?

Ikke ennå. Den dokumenterte veien er ren REST via Nodes native fetch — hjelperen på denne siden utgjør hele integrasjonsflaten, og den fungerer likt for alle capabilities.

Hvilke Node.js-versjoner støttes?

Alt som støtter native `fetch` — som betyr Node 18 og nyere. På Node 16 må du enten polyfille med `node-fetch` eller oppgradere. Resten av koden er ren ECMAScript 2020 (async/await, template literals, dynamiske imports), så det er ingen andre kjøretidskrav.

Hvordan autentiserer jeg fra Node?

Send `Authorization: Bearer photta_live_xxx` på hver forespørsel. Legg nøkkelen i en miljøvariabel og les den via `process.env`; importer den aldri fra en fil som kjører i nettleseren.

Hvordan håndterer jeg genereringsvinduet?

Genererings-endpointet er fullstendig asynkront. POST returnerer en genererings-ID umiddelbart med `status: 'processing'`. Poll `GET /api/v1/ghost-mannequin/{id}` hvert 3.–5. sekund til `status` endres til `completed` eller `failed`, og sett en grense for antall forsøk slik at en jobb som henger seg opp ikke låser en forespørsel.

Kan jeg kalle API-et inne i Next.js?

Ja — fra en route handler (`app/**/route.ts`), en server action (`'use server'`) eller middleware. Hold API-nøkkelen på serveren; importer aldri hjelperen fra en `'use client'`-fil. For langvarige jobber som overskrider Vercels funksjonstimeout, utsett pollingen til en kø (Inngest, Trigger.dev, BullMQ) og returner genererings-ID-en til nettleseren slik at den kan polle ditt eget status-endpoint.

Hvordan signaliserer API-et feil?

Ikke-2xx-responser inneholder en JSON-body med et `error`-objekt: `type`, `code`, `message` og en request-ID for support. Vanlige tilfeller: 400 invalid_request_error med `param` pekende på det ugyldige feltet; 402 insufficient_credits med `required`- og `available`-antall; 429 rate_limit_exceeded med `retry_after` i sekunder og en tilhørende Retry-After-header. 5xx-feil er trygge å prøve på nytt med eksponensiell backoff.

Prøv API-et på fem minutter

Generer en Photta API-nøkkel, lim inn cURL-kodesnutten ovenfor, og du har ditt første bilde på modell før kaffen er ferdig traktet.

  • 1.5–4 min
  • 4 credits ved 2K · 5 credits ved 4K
  • asynkron, polling
  • 600 forespørsler/min
  • Bearer-nøkkel