Inspiration
Sports card trading is a multi-billion dollar hobby run over DMs, comment threads and payment apps with no buyer protection. The card is real, the photos are real, and the person on the other end is a username created yesterday. Every collector has the same two stories: the card that never arrived, and the card that arrived "mint" with a corner you could shave cheese with.
Existing marketplaces answered this with fees and filters. CardAuthentico answers it with identity and evidence: you always know who is on the other side of the trade, the money does not move until the card lands, and a dispute is decided on video, not on vibes.
What it does
CardAuthentico is a sports-card marketplace shipping as a React Native app (iOS + Android) on top of a web marketplace.
Main features are:
- Identity-verified sellers. Nobody lists before passing Stripe Identity. Every profile carries a Trust Passport -
Basic(confirmed account in good standing),Enhanced(verified government ID + connected payouts + clean delivery record),Premium(earned over a sustained history of high feedback, fast fulfilment and no upheld disputes). The level is rendered next to every listing, not buried in a profile tab. - Payment held until delivery. Checkout runs on Stripe PaymentSheet (Apple Pay / Google Pay / 3DS). The charge completes, but the funds stay in CardAuthentico's balance until the buyer confirms the card arrived as described. Buyer can cancel within 48h of paying while the order is still unpacked; if the seller never acts at all, the order auto-cancels and refunds after 5 days.
- Evidence-based disputes. The unboxing video is the case - the dispute endpoint rejects a claim without one (
unboxVideoMissing). Recording happens in-app, the seller's payout freezes while the case is reviewed. - Hand-to-hand tracking. Sellers print a scannable QR shipping label from the phone; the counterparty scans it with the in-app camera scanner. Tracked carriers are mandatory above a value threshold.
- Describe-it search.
"Basketball rookie under $10,000"typed in plain English, resolved by an LLM search service (/search/v1/card/ai) instead of a six-dropdown filter maze. The same search works inside your own collection. - Photo-to-listing. Shoot the card, the images service reads the slab and prefills sport, set, player, grader and grade (PSA, SGC, Beckett, CGC, CSG).
- Top 5 Cards of the Week. A ranking published every Monday from real marketplace telemetry, with a matched set of live listings for the cards leading the week.
Monetization: two payment rails, on purpose
This is the design decision we are most confident about, and it is the one RevenueCat made cheap to get right.
| Card trading (physical goods) | Pro plan (digital subscription) | |
|---|---|---|
| Store IAP required? | No - Apple App Store and Google Play store both exempt physical goods | Yes |
| Processor | Stripe + Stripe Connect payouts | StoreKit / Google Play Billing |
| SDK | @stripe/stripe-react-native |
react-native-purchases (RevenueCat) |
Routing card sales through IAP would have been wrong twice over: it hands 15–30% of every card sale to the stores, and RevenueCat does not process physical goods at all. So RevenueCat fronts only the pro entitlement, and Stripe does the marketplace.
Pro cuts the buyer fee from 3% to 1.1% and unlocks the full weekly Top 5. The plan pays for itself on a single mid-size pickup - with a monthly price $p$ and a purchase of $P$ dollars, Pro wins when
$$(0.030 - 0.011)\,P \;>\; p \quad\Longrightarrow\quad P \;>\; \frac{p}{0.019}$$
At $p = 9.99$ that is $P \approx \$526$ - roughly one graded rookie. The paywall does not have to argue; the arithmetic does.
The weekly ranking that Pro unlocks is computed server-side each Monday at 00:05 UTC over the week that just closed:
How we built it
CardAuthentico is one React Native app for iOS and Android, a Next.js website, and a cloud backend behind them. A shared design system - the same palette, type scale and components on mobile and web - keeps the marketplace feeling like one product wherever you open it.
- The app is React Native with TypeScript, built from a small library of reusable pieces so a new screen is assembled rather than written from scratch. The camera does double duty: scanning shipping labels and capturing the unboxing video that settles disputes.
- Subscriptions run entirely through RevenueCat. It handles the App Store and Play Store plumbing, and tells our backend - not the phone - when someone becomes a member. Membership is granted server-side from RevenueCat's notification, so the benefits people pay for are never something a modified app can claim for itself.
- The paywall is a Paywalls v2 layout published from the RevenueCat dashboard, with our own screen as a backstop. Copy, pricing and design change without shipping an app update, which is what makes testing them realistic for a small team.
- Payments for cards go through Stripe, kept strictly separate from the subscription. Sellers are paid out through Stripe and identity-verified through it as well.
- Notifications are OneSignal, tied to the person rather than the device, so a message about an order lands on whatever phone they are actually holding and opens the right screen.
- The web side is a Next.js website containing landing page and marketplace.
- The backend is a set of small cloud services over a PostgreSQL database - accounts, listings, search, verification, messaging, payments and shipping - each one doing a single job.
Challenges we ran into
- Age gating an adults-only marketplace without locking out adults. The date-of-birth gate is self-declared, so we layered the platform signal on top (Apple Declared Age Range / Play Age Signals) with thresholds bracketing 18. The verdict is computed on device and never transmitted or stored, and it fails open - an unreadable signal falls back to the DOB gate, because an adult on an old OS must not be locked out.
- Session survival. A refresh failure used to log people out mid-checkout. We moved to a single-flight refresh shared across the whole app, and a strict distinction between a dead client and an unavailable one.
- Presigned image URLs. Card images are S3 objects behind presigned URLs; getting expiry and cache staleness wrong makes a marketplace look broken in the most visible possible way. Freshness checks now gate every image fetch.
- Two payment SDKs, one checkout mental model. Keeping Stripe and RevenueCat strictly separated - and making sure no reviewer could read the physical-goods flow as circumventing IAP - drove the fee, copy and navigation decisions above.
Accomplishments that we're proud of
- Two payment rails in one app, neither policy bent. Stripe PaymentSheet for physical cards, RevenueCat/StoreKit/Play Billing for the
prosubscription, sitting side by side in the same product without a reviewer having grounds to read either as circumventing the other. - A dispute process that actually decides something. Making the unboxing video a hard precondition (
unboxVideoMissing) turned "he said, she said" into a reviewable record, and froze the seller payout while it is reviewed. - Search that replaced the filter panel instead of decorating it. Plain-English queries resolve against the catalogue and against your own collection, with the same bar.
What we learned
- Two payment streams, kept deliberately apart. The biggest architectural decision of the build was not technical - it was choosing to run selling and membership as two completely separate flows. Buying a physical card is a Stripe transaction between two people, with us in the middle holding the money until the card arrives. Membership is a digital subscription, so it belongs in the App Store and Play Store, and RevenueCat runs it end to end. Once we stopped trying to unify them and let each rail do the job it is good at, a whole class of problems disappeared: the fee model got simpler, the checkout copy got clearer, and there was never any doubt about which store rule applied to which screen. It also saved the 15-30% platform cut on every card sold, because physical goods are not supposed to go through in-app purchase in the first place.
- RevenueCat let a two-person team behave like a growth team. Pricing, paywall design and subscription wording used to mean an app release and a week of review before you learned anything. Publishing the paywall from the dashboard changed the unit of iteration from a release to an afternoon - and having one place that answers "is this person a member, on either platform, right now" removed the part of subscriptions everyone underestimates.
- People will wait for a card; they will not wait in silence. Marketplaces live and die on the gap between paying and receiving. Notifications through OneSignal turned out to carry more of the experience than we expected: the offer you received, the card that shipped, the message waiting for a reply, the Monday morning Top 5. Tying them to the person rather than the device, and making every one of them open the exact screen it is about, is what makes the app feel like it is looking after your order instead of merely hosting it.
- Store policy shaped the product, not just the submission. Preparing for review changed real things. Subscribing had to happen inside the app while managing a subscription had to hand off to the store - opposite directions, and an automatic rejection if you get it wrong. A marketplace with messaging needs reporting, blocking and a way to reach a human. And because trading collectibles involves money between strangers, we built the app for adults only: a date-of-birth gate at sign-up, backed by the platform's own age signal, with an 18+ store rating to match. The age check runs on the phone and is never stored or sent anywhere - the point is to keep minors out of a payments product, not to collect more data about the people we let in.
What's next for CardAuthentico
- Annual plan and a trial. One monthly SKU is the right v1, but the fee saving compounds for high-volume collectors - an annual package plus an intro trial, is the obvious next RevenueCat experiment.
- Paywall experiments. A/B the hosted paywall on the two entry points that already carry intent: the locked ranks 2–5 of the Monday drop, and the fee line in the checkout breakdown, where the 3% → 1.1% delta is a live number against the cart the user is looking at.
- Targeted OneSignal journeys. Move from broadcast + transactional to segmented: saved-search hits, price drops on favourited cards, and a win-back for lapsed Pro accounts driven off cancellation and expiration events.
- Grading partnerships and submission tracking. Let collectors send a raw card to a grader from inside the app and follow it back into their collection.
- International. Shipping, payouts and identity verification are currently available only to US users; expanding that list is a market-by-market piece of work, not a flag.
- Web-to-app funnel. A Stripe-checkout web funnel feeding app installs is the natural follow-on now that both rails are live.
Built With
- amazon-web-services
- aws-lambda
- cloudfront
- google-play-billing
- next.js
- node.js
- onesignal
- paseto
- postgresql
- react
- react-native
- react-navigation
- reanimated
- revenuecat
- storekit
- stripe
- stripe-connect
- stripe-identity
- styled-components
- tailwindcss
- typescript
- vision-camera
- webiny
- xcode
- zustand
Log in or sign up for Devpost to join the conversation.