Kash creator checkout
A creator-checkout demo with server-priced amounts, duplicate-submission handling, and a sales dashboard. Mock payments only.
- Software
My work on this demo connects creator setup, a checkout interface, and a sales dashboard. The engineering focus was keeping amounts on the server, representing money in integer cents, validating requests, and handling repeat submissions without creating another payment record.
- When
- April 2026
- Where
- Playto engineering challenge
- Role
- Designer and developer
- Flow
- Creator setup, checkout page, sales dashboard
- Money
- Prices loaded on the server, stored as integer cents
- Payments
- Mock payments and simulated receipts
- Tools
- Next.js, React, TypeScript, Prisma, SQLite, Zod, Vitest
Paying twice with one key
The checkout page makes one idempotency key when it loads and sends it with every submission. The server looks up the price itself, then inserts the payment. The payments table allows each key once, so a repeat fails the insert, and the server returns the payment that already has that key, marked as a replay, without another receipt. Try a retry, a double submit, and a fresh page.
Local simulation. No payment details are collected and no request leaves your browser.
Checkout page 1
Example creator
Sticker pack
$12.00
Shown for display. The server stores 1200 cents and charges from its own price table.
- Idempotency key for this page
- 7f3a9c2e…
- Each request sends
- Product sticker-pack and this key. No amount.
Nothing sent yet. This checkout page's key, 7f3a9c2e…, goes with every request it sends.
The buttons need JavaScript. The description above covers each case.
Server and database
| Payment | Key | Amount, cents | Requests with this key |
|---|---|---|---|
| No rows yet. | |||
Simulated receipts logged: 0
Request log
Newest first.
- No requests yet.
How it works
A creator picks a handle, a product, and a price. A buyer pays on the creator’s checkout page, and the creator sees each sale, newest first, on a dashboard.
Decisions
- The client never sends a price. The payment request has no amount field. The server looks up the creator and copies the price from the database, so editing the page cannot change what is charged.
- Money is an integer number of cents. Prices are stored as cents. Dollar input is parsed with at most two decimal places and an upper bound, which avoids floating-point rounding.
- Handles are normalized. Handles are trimmed and lowercased on write and on lookup, and limited to letters, digits, underscores, and hyphens.
- Every request is validated. Request bodies pass through Zod schemas before any database work.
- Only the last four card digits are kept. The mock card form never stores a full number.
Duplicate submissions
When the checkout page loads, the browser creates one random idempotency key and sends it with every submission from that page, including retries after an error. The payment table has a unique constraint on the key.
The first request inserts the payment and logs a simulated receipt. If the same key arrives again, the insert fails on the unique constraint, and the server loads the payment that already has that key and returns it, marked as a replay, without sending another receipt. Two requests that race each other resolve the same way: one inserts and the other replays. No locks are needed because the database’s unique index decides which one wins.
Tests
Unit tests cover money parsing and request validation, including rejected keys and malformed email addresses.