setup-guides

Gelato setup — story-as-merch posters (Phase 0)

Story-as-merch (spec) prints posters of a story's cover art via Gelato (print-on-demand, no inventory). Phase 0 is author-at-cost self-orders of a single 13×19″ poster from the season page.

Until GELATO_API_KEY is set the feature is safe but inert: an order still takes payment via Stripe and parks the row at awaiting_fulfillment (no print is placed). Set the env to activate fulfillment.

Environment variables

VarRequiredWhat it is
GELATO_API_KEYto fulfillGelato API key (dashboard → API Keys). Without it, paid orders park at awaiting_fulfillment.
GELATO_POSTER_13X19_UIDrecommendedGelato product UID for the 13×19″ poster SKU. The code default is a placeholder — confirm the real UID from Gelato's product catalog.
GELATO_POSTER_13X19_BASE_CENTSoptionalPOD base cost snapshot in cents (default 1200). Phase 1 replaces this with live quoting.
GELATO_POSTER_SHIPPING_CENTSoptionalFlat shipping snapshot in cents (default 800). Phase 1 quotes live shipping per address.
MERCH_MARGIN_PERCENToptionalFan-storefront markup over POD base cost, percent (default 40).
MERCH_MARGIN_MIN_CENTSoptionalAbsolute floor on the markup so cheap items still clear (default 500 = $5).
MERCH_DEFAULT_CREATOR_PCToptionalCreator's share of the markup, percent (default 50). Per-creator override: creator_revenue_splits.merch_creator_pct.
GELATO_{TEE,HOODIE,MUG,HAT}_UIDrecommendedGelato product UIDs for the apparel/drinkware SKUs. Code defaults are placeholders — confirm each from Gelato's catalog.
GELATO_{TEE,HOODIE,MUG,HAT}_BASE_CENTSoptionalPOD base cost per SKU (defaults: tee 1500, hoodie 3000, mug 900, cap 1800).
GELATO_{TEE,HOODIE,MUG,HAT}_SHIPPING_CENTSoptionalFlat shipping per SKU (defaults: tee 500, hoodie 700, mug 600, cap 600).

Reuses already-configured infra: REPLICATE_API_TOKEN (the 4× cover upscale — print-asset.ts) and STRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRET (checkout + the merch_order webhook dispatch).

Activation steps

  1. Apply migration 426 (merch_orders + creator_revenue_splits.merch_creator_pct) to prod.
  2. Create a Gelato account; generate an API key → set GELATO_API_KEY on the backend (Railway).
  3. Find the 13×19″ poster product UID in Gelato's catalog → set GELATO_POSTER_13X19_UID. Set the cost/shipping env vars to match what Gelato charges.
  4. As a story owner, open your season page → Make it real → Order a poster → complete Stripe Checkout. Verify the merch_orders row reaches a Gelato status and the upscaled print asset looks clean at poster size (the print-resolution quality gate — spec §2).

How it flows

Author at-cost (POST /api/merch/:seasonId/self-checkout, owner only) and fan storefront (POST /api/merch/:seasonId/checkout, anyone incl. guests, public seasons only) both → Stripe Checkout (collects shipping address) → checkout.session.completed webhook → fulfillMerchOrder() upscales the cover to print resolution, then places the Gelato order (or parks it if GELATO_API_KEY is unset). Fan orders also book the creator's margin share to creator_earnings and pass a pre-sale cover-moderation gate (gpt-4o-mini vision).

GELATO MERCH — Docs | HiveJournal