RORK LABJP
MAX — Rork Max generates native Swift for iPhone, iPad, Apple Watch, Apple TV, and Vision Pro, with 2-click App Store publishing and no Xcode requiredSTACK — Standard Rork builds cross-platform mobile apps with React Native (Expo); choosing between the two by use case is the key decisionFOCUS — Unlike web-first tools such as Bolt or Lovable, Rork specializes in native iOS and Android app generationBUGS — A hands-on review reports Rork resolved about 70% of bugs without manual help, with the remaining 30% needing edits in the exported codebaseFUNDING — Rork raised $2.8M from a16z (Andreessen Horowitz)PRICING — It is free to start, with paid plans from $25/month, so you can try before committingMAX — Rork Max generates native Swift for iPhone, iPad, Apple Watch, Apple TV, and Vision Pro, with 2-click App Store publishing and no Xcode requiredSTACK — Standard Rork builds cross-platform mobile apps with React Native (Expo); choosing between the two by use case is the key decisionFOCUS — Unlike web-first tools such as Bolt or Lovable, Rork specializes in native iOS and Android app generationBUGS — A hands-on review reports Rork resolved about 70% of bugs without manual help, with the remaining 30% needing edits in the exported codebaseFUNDING — Rork raised $2.8M from a16z (Andreessen Horowitz)PRICING — It is free to start, with paid plans from $25/month, so you can try before committing
Articles/AI Models
AI Models/2026-06-17Advanced

Making Credits Add Up in a Rork AI Image App — Field Notes on Atomic Ledgers and Moderation

Credit billing in a Rork AI image and video app breaks in production because of the order between generation and deduction. Here are the field notes — atomic ledger consumption, idempotency, refunds on failure, and moderation — with Supabase code you can ship.

Rork417AI image generationfal.aiSupabase28credit billingidempotency2content moderationadvanced6

Premium Article

The first AI image app I shipped got a support message on launch day: "Five images were generated but only one credit was deducted." It looked like a happy report, but it was proof the billing was broken. Tapping the generate button quickly five times sent five requests to the server almost simultaneously, and every one of them read the balance before any deduction landed.

The hard part of a credit-based app is not generating the image. Throw the request at fal.ai and a result comes back in a second or two. The hard part is keeping an external operation (generation) and an internal state (the balance) in agreement, every time, without drift. Get this wrong and you either give images away for free or, worse, charge for failures and collect one-star reviews. Running paid apps as a solo developer, the second one costs you more than the lost revenue — it costs trust.

These are field notes for a React Native app generated with Rork, backed by Supabase Edge Functions. I will show where the naive implementation falls apart, then move to atomic consumption, idempotency, refunds on failure, and moderation.

Three ways naive "check → generate → deduct" breaks in production

Most tutorials are written in this order: read the balance, generate if it is enough, subtract one on success. It works in development. The problem is that production has concurrency and network jitter.

Failure pathWhat happensResult
Concurrency (TOCTOU)Multiple requests read the same pre-deduction balanceSeveral images generated on a balance of 1; charges leak
Crash/timeout before deductGeneration succeeded but the deduct UPDATE never landsFree generations keep flowing
Deduct after failureThe API returned 5xx but you already subtractedCharging for failures; bad reviews

The first one is the nastiest. There is a time gap between SELECT credits and UPDATE credits = credits - 1, and another request slips into that gap. Disabling the button on the client does not save you: retries, double taps, and duplicate sends on slow networks still get through. The boundary you must defend lives inside the database, not in the client.

Hold credits as a ledger, not a balance column

Change the data model first. Stop treating a single users.credits column as the source of truth, and make a ledger — one row per change — the source of truth. The balance becomes the sum, or a derived value kept for convenience. A ledger lets you trace exactly when, on what, and how many credits were spent or returned, which makes refunds and audits simple.

-- The ledger is the source of truth for credit changes
create table credit_ledger (
  id          uuid primary key default gen_random_uuid(),
  user_id     uuid not null references auth.users(id),
  delta       integer not null,        -- purchase +, consumption -, refund +
  reason      text not null,           -- 'purchase' | 'image' | 'video' | 'refund'
  ref_id      text,                    -- generation job id or checkout session id
  idem_key    text,                    -- idempotency key (below)
  created_at  timestamptz not null default now()
);
 
-- Physically forbid double-recording under the same idempotency key
create unique index credit_ledger_idem_uniq
  on credit_ledger (user_id, idem_key)
  where idem_key is not null;
 
create index credit_ledger_user_idx on credit_ledger (user_id);

The current balance is select coalesce(sum(delta), 0) from credit_ledger where user_id = $1. If the growing ledger worries you, you can fold it into monthly snapshot rows, but at a solo-developer scale (tens of thousands of rows) the sum query is plenty fast.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
The exact paths where check-then-generate-then-deduct breaks, and how to consume atomically in a Postgres function
Idempotency keys that stop double charges, plus a refund ledger that reliably returns credits on failure or cancel
Two-stage moderation on prompt input and image output, and the operational limits that keep you through App Store review
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

AI Models2026-05-06
7 Real Challenges When Building a Tarot App with Rork (And How to Solve Them)
A practical guide to building a daily tarot and oracle card app with Rork. Covers card data architecture, AI interpretation generation, daily reset logic, monetization design, and App Store review pitfalls specific to fortune-telling apps.
AI Models2026-05-05
Build an AI-Powered Certification Exam App with Rork: Adaptive Learning That Targets Your Weak Spots
Build a certification exam prep app with Rork and Gemini API. Learn to implement adaptive quiz logic, AI-driven weakness analysis, and Supabase-backed progress tracking — from first prompt to App Store.
AI Models2026-04-30
Building an AI-Powered Photo Organizer App with Rork — A Complete Implementation Guide Using Vision, CLIP, and pgvector
A complete implementation guide for building an AI-powered photo organizer app with Rork. Extract faces, objects, and text with the Vision framework, generate semantic embeddings with CLIP, and run similarity search at scale using Supabase pgvector — designed as a production pipeline from day one.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →