DEV Community

Cover image for Building aizombie.app: Locked Effects, Stripe Credits, and Seedance via TryAllAPI
AIzombie Lab
AIzombie Lab

Posted on Originally published at aizombie.app

Building aizombie.app: Locked Effects, Stripe Credits, and Seedance via TryAllAPI

How I shipped a two-photo → vertical AI zombie video product on Cloudflare Workers, with guest checkout and a video API aggregator instead of wiring every model vendor myself.

In late September 2026 a short “zombie love story” format started showing up everywhere on TikTok and Reels: one person lowers a gun, opens their arms, the other leaps in as a zombie, then the cut lands on a warm memory. People wanted that clip from their own photos — not a blank prompt box and a CapCut timeline.

I built aizombie.app (product name ZombieHug) for that job. Upload two adult photos, pay once, get a ~15s 9:16 MP4 with several shots and sound. No account required for a single pack. This post is the builder walkthrough: product shape, stack, credit/payment loop, and how video generation goes through TryAllAPI into Seedance. Prices and model ids change; treat live site / console as source of truth.

aizombie.app homepage — sample demo beside the locked Zombie Love Story create panel

Why lock the effect (instead of “write your own prompt”)

Free-form video models are flexible and messy. For a viral-format product, mess kills conversion. Users bounce when they have to invent a storyboard, guess camera language, and still get the wrong roles.

So the homepage locks one effect:

  1. Photo 1 = the person who holds the gun / survivor side
  2. Photo 2 = the person who becomes the zombie
  3. Fixed multi-shot story (gun down → leap → memory cut)
  4. Optional one-line place note; aspect ratio and resolution are the only knobs most people need

That trade-off is intentional. Repeatable results beat infinite creative control when the job is “ship the recognizable format tonight.” Extra variants live on a separate More effects page — same family of zombie stories, each with its own create path — without turning the homepage into a prompt IDE.

Create panel: Photo 1 / Photo 2 uploads, 18+ consent, aspect ratio and resolution

Live pricing on the create button (verified on the site while writing this): 480p from about $5.24, 720p Single at $6.99 (500 credits ≈ one 720p), with a 3-pack and larger packs / optional subscriptions. Guest Stripe checkout is the default path for “I only want one video.”

Stack overview

I did not start from a blank framework. The site sits on a TanStack Start template I maintain (shipany-tanstack), deployed to Cloudflare Workers, with D1 for users / orders / credit ledger / generation tasks, and Stripe Checkout for packs.

Layer Choice Role
Front / SSR TanStack Start (Vite) Landing, upload panel, generation status
Runtime Cloudflare Workers Edge deploy, secrets, API routes
DB Cloudflare D1 Credits, orders, task rows (table prefixes if DBs are shared)
Payments Stripe Checkout One-time packs + optional subscriptions; guest checkout
Video upstream TryAllAPI → Seedance Async create + poll
Analytics GA Funnel sanity check

The product pipeline in one line:

two photos → fixed story template prompt
→ check credits (else Stripe)
→ Worker creates Seedance task via TryAllAPI
→ poll until MP4 URL → store / show
→ on failure: refund credits
Enter fullscreen mode Exit fullscreen mode

High-level pipeline: template, one-time buy, API compute

Demo clips on the homepage are self-generated samples hosted with the site (for example under /samples/), so visitors can judge the format before paying. Do not scrape other products’ CDN videos for demos — it is both unnecessary and a compliance mess.

Why a video API aggregator

Direct vendor onboarding for every video model means accounts, KYC, docs drift, and different async status machines. For a small indie product I wanted:

  • one API key in Workers Secrets
  • USD balance billed by usage
  • a path to Seedance (and fallbacks) without rewriting the client each time the console UI changes

That is what TryAllAPI is for on this project: aggregate models behind one base URL, keep the site focused on UX + credits + Stripe.

Operational checklist I actually use after register / top-up:

  1. Confirm available USD balance in the console (not only the checkout success page).
  2. Create a token in pay-as-you-go style billing.
  3. Enable the video / Seedance-related channel group on that token. Wrong group → “no available channel” even when the model id is correct.
  4. Prefer separate keys per product (aizombie-prod vs sandbox).
  5. Put the key only in Workers Secrets (for example TRYALLAPI_API_KEY). Never in the frontend bundle or a blog post.

Conceptually the call shape looks like this (field names follow the aggregator’s v3 contents API; always re-check current docs):

POST /api/v3/contents/generations/tasks
Authorization: Bearer <TRYALLAPI_API_KEY>
Content-Type: application/json
Accept-Encoding: identity

GET /api/v3/contents/generations/tasks/{id}
Enter fullscreen mode Exit fullscreen mode

I send Accept-Encoding: identity from the Worker because some gateways behave badly with transparent decompression. Model ids I have used in production look like doubao-seedance-2-5-… for the default path, with 2.0 / fast variants as capacity fallbacks when the primary returns supply errors.

TryAllAPI console — Seedance model detail used as the upstream for ZombieHug

Seedance parameters that matter in production

A few details that bit me (and are worth copying into any similar site):

  • Two reference images, fixed roles. The story needs Photo 1 and Photo 2 mapped correctly. Same-person clones look wrong; the UI says so on purpose.
  • Pass duration as an explicit integer. Some models default to “smart length.” Omitting duration can silently lengthen the clip and the bill.
  • resolution and ratio. The product pushes 480p / 720p and 9:16 for Shorts/Reels/TikTok, with 16:9 and 21:9 available. Cost tracks resolution tier and duration more than portrait vs landscape.
  • generate_audio. On by default for this product so the download feels finished; creators who want a trending sound can mute/replace later.
  • Status machine. Expect something like queued → running → succeeded / failed. Success URLs are often short-lived signed links — download/rehost on your side before handing the file to the user.
  • Decent failure. On supply_unavailable or hard failures: refund credits, show a short human message, log the detailed upstream error server-side, optionally fall back to another Seedance tier.

Rough mental model for upstream cost (illustrative only — use your own usage fields and invoices):

tokens ≈ duration_sec × width × height × fps / 1024
cost   ≈ tokens × price_per_million_tokens
Enter fullscreen mode Exit fullscreen mode

Price the site after you measure a few real 720p runs with retry margin, Stripe fees, and failed-job refunds — not from a spreadsheet fantasy of 0% failure.

Credits, Stripe, and the “can charge money” line

Demo UIs are easy. The line between toy and product is:

  1. User hits Create → check credit balance.
  2. If short → Stripe Checkout Session (guest allowed).
  3. Webhook (plus a return-URL sync check) grants credits.
  4. Pre-debit / lock credits, create upstream task, persist task_id in D1.
  5. Poll until done; succeed → show MP4; fail → refund credits.

Two books of account stay separate: USD balance at TryAllAPI (your cost) vs site credits (what you sold). Mixing them in one mental ledger is how you underprice or invent “mysterious” losses.

When several products share one Stripe account, isolate webhooks by endpoint or by metadata (site / product). Callbacks pointed at the wrong apex domain are a classic multi-site footgun.

Secrets stay in Workers: TRYALLAPI_API_KEY, STRIPE_SECRET_KEY, webhook secret, auth secrets. The browser only ever sees publishable Stripe keys if needed.

Deploy notes (Workers + D1)

Typical loop on this template family:

pnpm install
# wire D1 database_id, production env, custom domain in wrangler
pnpm cf:deploy
Enter fullscreen mode Exit fullscreen mode

Before calling a deploy “done”:

  • D1 binding is correct; shared DBs use table prefixes, not a new database per micro-idea (free-tier DB counts are limited).
  • AUTH_TRUSTED_ORIGINS and Stripe return / webhook URLs match https://aizombie.app.
  • GA id is set for a coarse funnel (land → upload → pay → wait → download).
  • One real end-to-end path on production or a staging Worker: upload → pay → render → download.

Product rules that are not optional

Face-based generation is not “just another SaaS CRUD app”:

  • Require an explicit 18+ / rights-to-use confirmation on upload.
  • Block minors and refuse celebrity / stranger misuse in copy and policy.
  • Expect upstream safety refusals; refund and explain.
  • Keep privacy policy honest about retention; do not train on user media by default.
  • Market as an independent fan-style tool for a trend format — not as an official tie-in to any film or creator unless you actually have that deal.
  • Use your own sample renders in marketing.

Those constraints belong in the product, not in a footnote you add after the first dispute email.

What I would reuse on the next trend site

  1. Locked effect + guest one-time pack beats “sign up, subscribe, then maybe generate.”
  2. Credits with automatic refund on failed generation is table stakes for trust.
  3. Aggregator for video models keeps the Worker thin: create, poll, store, refund.
  4. Self-hosted samples sell the format faster than paragraphs of SEO copy.
  5. Measure the funnel before polishing prompt poetry — upload and payment drops usually matter more than another adjective in the storyboard.

If you want the consumer path: open aizombie.app, watch the sample, upload two photos you have rights to (Photo 1 gun/survivor, Photo 2 zombie), pick 480p or 720p, pay once.

If you want the builder path: register at TryAllAPI, top up a small USD balance, create a token with the right video group, prove create+poll in a Worker, then wire credits and Stripe. Keep keys out of git. Make failure boring and refundable.

That is the whole product thesis in one sentence: template the story, sell the credits, outsource the GPU drama.

Top comments (0)