Bygg · Shopify

Bygg en try-on-app for Shopify

I én setning

En Shopify try-on-app leser produktbildet fra Admin API, sender det via POST til Photta, poller jobben i en bakgrunnsworker, og overleverer deretter den ferdige URL-en til Shopify via productCreateMedia.

  • Credits: 5 credits ved 2K · 6 credits ved 4K
  • Typisk tidsbruk: 1.5–4 min
  • Prosessering: asynkron, polling

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

Les produktbildet fra Admin API, render try-on med Photta, og skyv resultatet tilbake som produktmedie. Fire kall, ingen egen bildehåndtering.

RESPONSE=$(curl -s -X POST https://api.photta.app/api/v1/tryon/apparel \
  -H "Authorization: Bearer $PHOTTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "product_type": "top",
  "product_images": [
    "https://cdn.yourstore.com/products/shirt-front.jpg"
  ],
  "product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
  "product_category": "t_shirt",
  "mannequin_id": "mnk_f3a9b1",
  "pose_id": "pose_c2d4e5",
  "background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
  "lock_background": true,
  "resolution": "2K",
  "aspect_ratio": "3:4",
  "body_size": "M",
  "expression": "neutral",
  "user_instruction": "Keep the collar pattern crisp and centered."
}')
ID=$(echo "$RESPONSE" | jq -r '.data.id')

Slik fungerer det

Fra en produktside til et try-on-bilde

Definer app-scopes, les bildet, send inn, poll utenfor request-stien, legg ved mediet.

  1. Trinn 1

    Definer scopes for appen

    En try-on-app må lese produkter og skrive medier. Be kun om produkt-scopes appen din faktisk bruker og ingenting annet — forhandlere leser samtykkeskjermen.

  2. Trinn 2

    Hent en Photta API-nøkkel

    Én nøkkel per miljø, lagret i appens serverkonfigurasjon. Den sendes aldri til nettbutikken eller til forhandlerens nettleser.

  3. Trinn 3

    Les produktbildet

    Gjør en spørring mot produktet for å hente dets første bilde. Den URL-en er offentlig, og det er nøyaktig hva Photta-endepunktet forventer — ingen re-opplasting, ingen signert URL å administrere.

  4. Trinn 4

    Send inn try-on

    POST bildet sammen med en mannequin og en positur. Responsen er umiddelbar og inneholder genererings-ID-en; ingenting er rendret ennå.

  5. Trinn 5

    Poll i en bakgrunnsjobb

    Shopify forventer at en webhook-handler svarer i løpet av sekunder, og en generering tar lenger tid enn det. Bekreft mottak, legg i kø, og poll hvert 3. sekund fra workeren.

  6. Trinn 6

    Legg ved mediet

    Gi Shopify den ferdige URL-en, så laster den ned filen selv. Lagre bildet på din side også, slik at galleriet overlever uavhengig.

De fire kallene, ende til ende

Photta-forespørselen og polling er gjengitt fra API-dokumentasjonen; Shopify-kallene tilhører Admin API selv.

// Shopify Admin GraphQL — the product's first image is your source photo
const query = `query($id: ID!) {
  product(id: $id) { title images(first: 1) { nodes { url } } }
}`;

const res = await admin.graphql(query, { variables: { id: productGid } });
const { data } = await res.json();
const productImage = data.product.images.nodes[0].url;
const res = await fetch("https://api.photta.app/api/v1/tryon/apparel", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "product_type": "top",
    "product_images": [
      "https://cdn.yourstore.com/products/shirt-front.jpg"
    ],
    "product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
    "product_category": "t_shirt",
    "mannequin_id": "mnk_f3a9b1",
    "pose_id": "pose_c2d4e5",
    "background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
    "lock_background": true,
    "resolution": "2K",
    "aspect_ratio": "3:4",
    "body_size": "M",
    "expression": "neutral",
    "user_instruction": "Keep the collar pattern crisp and centered."
  }),
});
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/apparel/${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");
}
// Shopify downloads the URL itself, so hand it the Photta output_url
const mutation = `mutation($id: ID!, $media: [CreateMediaInput!]!) {
  productCreateMedia(productId: $id, media: $media) {
    mediaUserErrors { field message }
  }
}`;

await admin.graphql(mutation, {
  variables: {
    id: productGid,
    media: [{ originalSource: outputUrl, mediaContentType: "IMAGE", alt: "Virtual try-on" }],
  },
});

Spørsmål utviklere stiller

Spørsmål Shopify-utviklere stiller

Hvor skal Photta-nøkkelen ligge i en Shopify-app?

I app-serverens miljø, aldri i temaet, en app-blokk eller en app-proxy-respons. Alt nettbutikken kan lese, kan en kunde lese.

Hvilke Shopify-scopes kreves for dette?

Lesing av produktbilde og skriving av produktmedier. Photta trenger ingen Shopify-tilgang i det hele tatt — appen din er det eneste som kommuniserer med begge parter.

Hvordan holder jeg webhooken rask?

Svar umiddelbart med en bekreftelse, legg arbeidet i kø, og poll fra workeren. En generering tar lengre tid enn en webhook-handler bør bruke, så ingenting som venter på den hører hjemme i handleren.

Kan jeg fakturere forhandlere per bilde?

Det er din prisbeslutning. Photta belaster kontoen din i credits per kall, så kostnaden per bilde er kjent før du rendrer; hva du fakturerer i tillegg er opp til deg.

Hva om et produkt mangler bilde?

Hopp over det fremfor å sende en plassholder. Endepunktet krever et ekte klesfotografi, og en plassholder bruker credits på et bilde ingen kommer til å publisere.

Lever appen, ikke infrastrukturen

Photta-kallene på denne siden er hentet direkte fra API-dokumentasjonen. Hent en nøkkel, så er den første rendringen bare minutter unna.