<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: AIzombie Lab</title>
    <description>The latest articles on DEV Community by AIzombie Lab (@aizombie_lab).</description>
    <link>https://dev.to/aizombie_lab</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4218242%2F4e101579-9cdd-4c1d-9500-b998b081cd19.png</url>
      <title>DEV Community: AIzombie Lab</title>
      <link>https://dev.to/aizombie_lab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aizombie_lab"/>
    <language>en</language>
    <item>
      <title>Building aizombie.app: Locked Effects, Stripe Credits, and Seedance via TryAllAPI</title>
      <dc:creator>AIzombie Lab</dc:creator>
      <pubDate>Sat, 31 Oct 2026 04:17:17 +0000</pubDate>
      <link>https://dev.to/aizombie_lab/building-aizombieapp-locked-effects-stripe-credits-and-seedance-via-tryallapi-4lk7</link>
      <guid>https://dev.to/aizombie_lab/building-aizombieapp-locked-effects-stripe-credits-and-seedance-via-tryallapi-4lk7</guid>
      <description>&lt;p&gt;&lt;em&gt;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.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;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 &lt;em&gt;that&lt;/em&gt; clip from their own photos — not a blank prompt box and a CapCut timeline.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://aizombie.app/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=builder" rel="noopener noreferrer"&gt;aizombie.app&lt;/a&gt; (product name &lt;strong&gt;ZombieHug&lt;/strong&gt;) 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 &lt;a href="https://tryallapi.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=builder" rel="noopener noreferrer"&gt;TryAllAPI&lt;/a&gt; into Seedance. Prices and model ids change; treat live site / console as source of truth.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff1ummk6s5ku1rhvwbuvw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff1ummk6s5ku1rhvwbuvw.jpg" alt="aizombie.app homepage — sample demo beside the locked Zombie Love Story create panel" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why lock the effect (instead of “write your own prompt”)
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;So the homepage locks one effect:&lt;/p&gt;

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

&lt;p&gt;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 &lt;a href="https://aizombie.app/effects?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=builder" rel="noopener noreferrer"&gt;More effects&lt;/a&gt; page — same family of zombie stories, each with its own create path — without turning the homepage into a prompt IDE.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fggfwpf1c3xh77xij7lya.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fggfwpf1c3xh77xij7lya.jpg" alt="Create panel: Photo 1 / Photo 2 uploads, 18+ consent, aspect ratio and resolution" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live pricing on the create button (verified on the site while writing this): &lt;strong&gt;480p from about $5.24&lt;/strong&gt;, &lt;strong&gt;720p Single at $6.99&lt;/strong&gt; (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.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack overview
&lt;/h2&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Front / SSR&lt;/td&gt;
&lt;td&gt;TanStack Start (Vite)&lt;/td&gt;
&lt;td&gt;Landing, upload panel, generation status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime&lt;/td&gt;
&lt;td&gt;Cloudflare Workers&lt;/td&gt;
&lt;td&gt;Edge deploy, secrets, API routes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DB&lt;/td&gt;
&lt;td&gt;Cloudflare D1&lt;/td&gt;
&lt;td&gt;Credits, orders, task rows (table prefixes if DBs are shared)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payments&lt;/td&gt;
&lt;td&gt;Stripe Checkout&lt;/td&gt;
&lt;td&gt;One-time packs + optional subscriptions; guest checkout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Video upstream&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://tryallapi.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=builder" rel="noopener noreferrer"&gt;TryAllAPI&lt;/a&gt; → Seedance&lt;/td&gt;
&lt;td&gt;Async create + poll&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Analytics&lt;/td&gt;
&lt;td&gt;GA&lt;/td&gt;
&lt;td&gt;Funnel sanity check&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The product pipeline in one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4504yweu5jcxmv80yccf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4504yweu5jcxmv80yccf.jpg" alt="High-level pipeline: template, one-time buy, API compute" width="799" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Demo clips on the homepage are &lt;strong&gt;self-generated&lt;/strong&gt; samples hosted with the site (for example under &lt;code&gt;/samples/&lt;/code&gt;), 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a video API aggregator
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;one API key in Workers Secrets
&lt;/li&gt;
&lt;li&gt;USD balance billed by usage
&lt;/li&gt;
&lt;li&gt;a path to Seedance (and fallbacks) without rewriting the client each time the console UI changes
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Operational checklist I actually use after register / top-up:&lt;/p&gt;

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

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /api/v3/contents/generations/tasks
Authorization: Bearer &amp;lt;TRYALLAPI_API_KEY&amp;gt;
Content-Type: application/json
Accept-Encoding: identity

GET /api/v3/contents/generations/tasks/{id}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiqy23nsbx7ht7kar07l4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiqy23nsbx7ht7kar07l4.jpg" alt="TryAllAPI console — Seedance model detail used as the upstream for ZombieHug" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Seedance parameters that matter in production
&lt;/h2&gt;

&lt;p&gt;A few details that bit me (and are worth copying into any similar site):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Two reference images, fixed roles.&lt;/strong&gt; The story needs Photo 1 and Photo 2 mapped correctly. Same-person clones look wrong; the UI says so on purpose.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pass &lt;code&gt;duration&lt;/code&gt; as an explicit integer.&lt;/strong&gt; Some models default to “smart length.” Omitting duration can silently lengthen the clip and the bill.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;resolution&lt;/code&gt; and &lt;code&gt;ratio&lt;/code&gt;.&lt;/strong&gt; 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.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;generate_audio&lt;/code&gt;.&lt;/strong&gt; On by default for this product so the download feels finished; creators who want a trending sound can mute/replace later.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status machine.&lt;/strong&gt; Expect something like &lt;code&gt;queued&lt;/code&gt; → &lt;code&gt;running&lt;/code&gt; → &lt;code&gt;succeeded&lt;/code&gt; / &lt;code&gt;failed&lt;/code&gt;. Success URLs are often &lt;strong&gt;short-lived signed links&lt;/strong&gt; — download/rehost on your side before handing the file to the user.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decent failure.&lt;/strong&gt; On &lt;code&gt;supply_unavailable&lt;/code&gt; or hard failures: refund credits, show a short human message, log the detailed upstream error server-side, optionally fall back to another Seedance tier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rough mental model for upstream cost (illustrative only — use your own &lt;code&gt;usage&lt;/code&gt; fields and invoices):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tokens ≈ duration_sec × width × height × fps / 1024
cost   ≈ tokens × price_per_million_tokens
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  Credits, Stripe, and the “can charge money” line
&lt;/h2&gt;

&lt;p&gt;Demo UIs are easy. The line between toy and product is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User hits Create → check credit balance.
&lt;/li&gt;
&lt;li&gt;If short → Stripe Checkout Session (guest allowed).
&lt;/li&gt;
&lt;li&gt;Webhook (plus a return-URL sync check) grants credits.
&lt;/li&gt;
&lt;li&gt;Pre-debit / lock credits, create upstream task, persist &lt;code&gt;task_id&lt;/code&gt; in D1.
&lt;/li&gt;
&lt;li&gt;Poll until done; succeed → show MP4; fail → &lt;strong&gt;refund credits&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

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

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

&lt;p&gt;Secrets stay in Workers: &lt;code&gt;TRYALLAPI_API_KEY&lt;/code&gt;, &lt;code&gt;STRIPE_SECRET_KEY&lt;/code&gt;, webhook secret, auth secrets. The browser only ever sees publishable Stripe keys if needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy notes (Workers + D1)
&lt;/h2&gt;

&lt;p&gt;Typical loop on this template family:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="c"&gt;# wire D1 database_id, production env, custom domain in wrangler&lt;/span&gt;
pnpm cf:deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before calling a deploy “done”:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Product rules that are not optional
&lt;/h2&gt;

&lt;p&gt;Face-based generation is not “just another SaaS CRUD app”:&lt;/p&gt;

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

&lt;p&gt;Those constraints belong in the product, not in a footnote you add after the first dispute email.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would reuse on the next trend site
&lt;/h2&gt;

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

&lt;p&gt;If you want the consumer path: open &lt;a href="https://aizombie.app/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=builder" rel="noopener noreferrer"&gt;aizombie.app&lt;/a&gt;, watch the sample, upload two photos you have rights to (Photo 1 gun/survivor, Photo 2 zombie), pick 480p or 720p, pay once.&lt;/p&gt;

&lt;p&gt;If you want the builder path: register at &lt;a href="https://tryallapi.com/register?aff=5A6A&amp;amp;utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=builder" rel="noopener noreferrer"&gt;TryAllAPI&lt;/a&gt;, 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.&lt;/p&gt;

&lt;p&gt;That is the whole product thesis in one sentence: &lt;strong&gt;template the story, sell the credits, outsource the GPU drama.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>api</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
