Flypost is a two-sided marketplace I designed, built, and shipped end-to-end. It pairs event promoters with verified human artists for original show posters — and attaches a provenance receipt to every commission, so the work is provably hand-made. Launching out of Edmonton's underground.
Generated poster art is everywhere, and a promoter has no easy way to tell who actually drew the thing.
Show posters are how a scene shows its face — and the supply is now drowning in low-effort, AI-generated images. Promoters want original art from a real person on a real deadline; artists want commissions that aren't competing with a prompt. Neither side has a trustworthy place to meet.
Make authenticity the product. Every artist is a vetted human — verified identity, hand-made work — and every commission ships with a provenance receipt.
The guarantee isn't a marketing line — it's enforced by the workflow, from onboarding to delivery.
A browsable roster of vetted artists, each with starting price and turnaround. Promoters pick the hand they want.
Identity verification at onboarding and a provenance receipt on every commission — proof the work is hand-made.
A structured path from brief to delivered poster, with expectations on price and timeline set up front.
A public feed of shows and the posters made for them — the scene's portfolio, in one place.
A self-serve 'I'm an artist' path that brings new creators in through the same verification gate.
A clear, public stance on what the platform guarantees — no slop, no anonymous fronts, no AI passing as human.
A promoter finds a verified artist whose style, price, and turnaround fit the show.
They send a brief and commission directly. The artist makes an original, by hand.
The finished poster is delivered with a provenance receipt — provably human, ready to flypost.
A two-sided marketplace that holds money in true per-order escrow and signs every delivery so it's provably hand-made — designed, built, tested, and shipped solo. The product story is above; this is the engineering, for whoever's deciding whether I can build the hard thing.
Flypost takes a buyer's payment, holds it while a human artist makes a poster, and on approval pays the artist and keeps a fee — then hands over a receipt proving a person made it. Every word in that sentence is a place to get money or trust wrong. Here's how each one is built so it can't be.
// Stripe Connect, separate charges & transfers
The marketplace holds the buyer's funds until approval, then pays the artist their cut. The naive build routes everything through the platform balance and pays artists out of commingled money — which means the platform is floating cash it doesn't own and reconciliation is a guess.
I built it on separate charges and transfers, and funded each artist payout from its own charge via source_transaction. Every order's money is escrowed against the exact charge that created it: no commingling, no platform float, each order independently reconcilable down to the cent.
balance_insufficient — transfers draw from available balance, and the buyer's charge was still pending. source_transaction draws from the specific charge instead. The naive version would have quietly needed a float to mask it.Money operations need idempotency keys so a retry can't double-pay. The obvious key — release-{orderId} — is wrong, and subtly so: Stripe replays a key's result, including its failures. A release that failed once (artist not yet verified) became permanently unretryable — the static key replayed the original failure forever.
I replaced it with a per-order Postgres advisory lock (pg_advisory_xact_lock) that serializes releases, plus an adopt-or-create pattern keyed on the charge's transfer_group: any prior money movement is detected and adopted, never duplicated. A failed release now parks the order in a clean approved state, retryable from the operator console.
Accept, decline, expire and cancel all touch the same money. An artist accepting a commission at the exact instant a timeout sweeper tries to refund it is a real race — with real dollars on both sides.
Every state transition is a conditional UPDATE with the guard in the WHERE clause, so a transition physically can't fire twice. The refund path re-reads order state under the advisory lock before it creates a Stripe refund. The sweeper can never refund an order the artist just accepted; the accept can never land on one just refunded. Correctness by construction, not by hoping the timing works out.
Every delivered poster ships with a provenance receipt: a canonical-JSON record (sorted keys, deterministic bytes) signed ed25519 with the platform key. The record embeds its own SPKI public key, so a receipt verifies standalone — no server, no env, no trust in me required. The order page verifies the signature live and demonstrates tamper-detection.
Orders that carry a receipt are undeletable at the database layer (foreign-key RESTRICT) — provenance can't be quietly rewritten. "Made by a human" stops being a marketing line and becomes a signature anyone can check.
A single artist onboarding feeds three things that usually sprawl into three integrations:
transfers capability and never touches card data.v1:iv:ct:tag format built for key rotation, with only the last four digits ever client-visible.One verified identity, three obligations, captured once and kept consistent.
capabilities.transfers === "active" against Stripe at release time — the flag that actually governs a transfer — rather than trusting a cached DB flag that lags verification.revisions_used < revisions_included in the WHERE), not in app code where a double-submit could slip the gate.A 48-check smoke suite runs against the live Stripe test API — not mocks. It asserts the money invariants (commission + payout always equals the poster price, to the cent), signs / verifies / tampers provenance receipts, round-trips storage, then drives two complete order lifecycles through the real webhook handler: payment intent → capture → assign → draft → bounded revision → approve → a real Transfer verified for amount and destination → receipt verification → completion. Plus decline-and-refund checked against the Stripe API, and the negative cases. If the payments logic is wrong, the suite fails before anything ships.
Full-stack SaaS, document-processing pipelines, AI-augmented tools, internal platforms. Free 20-minute discovery call, projects from $2,500 CAD.
steven.sutankayo@novaconvert.ca