All apps
2.El Bilet app icon

2.El Bilet

A second-hand ticket marketplace with fixed prices and auctions, connecting people who can't go with people who couldn't get a ticket.

  • iOS
  • Android
  • 2025
  • My own product
App Store · on hold Google Play · on hold

Screenshots

Click an image to enlarge it.

About the app

Event tickets have a two-sided problem: on one side, people who have a ticket but can no longer go; on the other, people who couldn't get one. These two groups look for each other in social media comments and forums, scattered all over the place. 2.El Bilet started from the idea of moving that exchange into a single place — concerts, theatre, matches, stage shows, family events, all split into categories.

When posting a listing there were two options: fixed price or auction. The two sit side by side in the interface, but underneath they are not the same thing. An auction has a bid order, a closing time and auto-accept rules; a fixed price has none of that. Instead of writing them as two separate products, I built a shared "listing" model: a listing has a sale format, and the closing condition and the rule for picking a winner change with that format.

The genuinely hard part was trust. In a second-hand marketplace nobody wants to move first: the buyer doesn't want to send money before seeing the ticket, and the seller doesn't want to hand over the ticket before getting paid. So instead of a single "buy" button, I turned the exchange into a staged transaction — payment completed, ticket sent, and payment released to the seller are separate states. On the home screen the user saw their own "pending transactions" and knew whose turn the next step was. That was also my strongest card against the risk of fake tickets: the money was not released until the ticket reached the other side.

This marketplace also had a quirk of its own: the thing being sold has an expiry date. The moment the event starts, the ticket is worthless. So listings close on their own based on time, and on the search side, time-based filters like "very urgent", "last 48 hours" and "price dropped" were front and centre. For sellers I added visibility tools too — featuring on the showcase, ranking higher in search, sending offers to users who favourited a listing — and the product's revenue model was built on that.

Buyer and seller rarely settled things in a single message, so I didn't keep the chat side light: real-time messaging where they could negotiate, plus voice and video calls. On top of that there was map-based discovery of people selling and people looking for tickets; finding someone in the same city, or even heading to the same event, made the exchange easier.

The app isn't in the stores right now — I put the project on hold for a while, I didn't shut it down. I paused the release because I prioritised other products; the listing flow, verification and the escrow structure are all still in place, and I plan to keep developing it.

Key features

  • Two sale formats: selling a ticket as a fixed-price listing or by auction
  • Staged transaction flow: complete payment → send the ticket → receive payment, each step its own state
  • Pending transactions screen: a tracking list showing whose turn the next step is
  • Categories: concerts, stage, sports, family and education — with their sub-categories
  • Time-based filters: "very urgent", "last 48 hours" and "price dropped"
  • Sorting: lowest price, highest price, most recently added or random
  • Visibility tools: featuring on the showcase, ranking higher in search and filters, adding a highlight frame
  • Automatic bid acceptance and sending offers to users who favourited a listing
  • Negotiation chat: real-time messaging, voice and video calls
  • Map-based discovery: finding nearby users selling and looking for tickets
  • Automatic closing of expired listings — based on the event date

Technologies used

115 technologies · 12 categories

Languages and Platform

  • Swift (iOS)
  • Java (Android)
  • Kotlin (Android)
  • iOS SDK
  • Android SDK
  • Native on both platforms

UI and Application Layer

  • UIKit / SwiftUI (iOS)
  • Android View / Compose
  • UICollectionView / RecyclerView
  • Pagination
  • Countdown timers
  • Photo picker (PHPicker)
  • Android media picker
  • Image caching

Backend and Data

  • Firebase Firestore
  • Firebase Authentication
  • Firebase Storage
  • Cloud Functions
  • Scheduled Cloud Functions
  • Firestore queries and indexes
  • Firestore security rules
  • Server timestamps
  • Firestore offline cache
  • Batch writes
  • Cursor-based pagination
  • Denormalisation
  • Counter fields
  • Cloud Functions triggers
  • Scheduled jobs
  • Data migration

Real-Time and Media

  • Firestore real-time listeners
  • JitsiMeet SDK
  • DigitalOcean server hosting
  • WebRTC media streaming
  • AVFoundation (iOS)
  • Camera/microphone permissions
  • Firebase Cloud Messaging
  • APNs (iOS notifications)
  • STUN / TURN configuration
  • Audio routing (speaker / earpiece)
  • Keeping calls alive in the background
  • Reconnecting after network drops
  • Call state synchronisation
  • Server resource and scale monitoring

Location and Maps

  • MapKit (iOS)
  • Google Maps SDK (Android)
  • Core Location (iOS)
  • FusedLocationProvider (Android)
  • Location permissions
  • Geographic proximity queries
  • Map pin management

Payments and Revenue

  • Virtual POS integration
  • Escrow flow
  • Server-side payment verification
  • Payout transfer to the seller
  • Commission calculation
  • Transaction history records

Architecture and Patterns

  • MVVM / MVC
  • Transaction state machine
  • Firestore data modelling
  • Atomic transactions
  • Concurrent bid handling
  • Server-side business rules
  • Firestore triggers

Networking and Data Transfer

  • URLSession (iOS)
  • HTTP client (Android)
  • JSON parsing (Codable)
  • Retries and timeouts
  • Offline state handling
  • Download and upload queue
  • Multipart file upload
  • Bandwidth-adaptive quality

Security and Privacy

  • Keychain (iOS)
  • EncryptedSharedPreferences (Android)
  • HTTPS and ATS
  • Auth token management
  • Session refresh
  • Permission rationale copy
  • Account deletion flow
  • Server-side authorisation checks
  • Sensitive data masking

UI States and Accessibility

  • Dark theme support
  • Dynamic Type
  • Safe area handling
  • Empty / loading / error states
  • Skeleton loading
  • Pull to refresh
  • Keyboard and focus management
  • Deep linking (Universal Links)
  • VoiceOver / TalkBack labels

Testing, Debugging and Measurement

  • Xcode Instruments
  • Android Profiler
  • LLDB
  • Logcat
  • Memory leak tracking
  • Network traffic inspection
  • Reading crash reports
  • Testing on real devices
  • Testing across screen sizes

Tools and Release Process

  • Xcode
  • Android Studio
  • App Store Connect
  • Google Play Console
  • CocoaPods
  • Gradle
  • Git
  • Open-source libraries (GitHub)
  • TestFlight
  • Play Console internal testing
  • Version and build numbering
  • Signing and provisioning profiles
  • App Store review process
  • App Privacy / Data Safety forms
  • Store assets and ASO copy
  • App size optimisation
Solo work

Idea, design, interface, code, store release and post-release maintenance — I ran the entire process end to end on my own. No team, no agency, no outsourcing.

Development notes

  • Languages and approachThe iOS side was written in Swift, the Android side in Java and Kotlin. No cross-platform framework was used; both apps were built with their own platform's native tooling. I have been doing mobile development since 2020.
  • No AI assistanceAll of the code was written by hand. This project was built before AI coding tools like Claude Code and Codex became widespread — no such tool existed at the time.
  • DependenciesA large number of open-source GitHub libraries and CocoaPods packages were used. Dependency management ran through CocoaPods on iOS and Gradle on Android.
  • Video call infrastructureJitsiMeet was self-hosted on my own server rather than used as a ready-made service (DigitalOcean). Server setup, media streaming and scaling were all on me.
  • Escrow flowPayment and ticket transfer were designed not as one step but as separate states waiting on each other; neither party had to take the risk of moving first on their own.
  • Testing and debuggingTested on real devices, across different screen sizes and under poor network conditions. After release I read crash reports and shipped fixes release by release.
  • Release processI handled the review process for both stores myself: App Store Connect and Google Play Console setup, the privacy declarations (App Privacy / Data Safety), release notes, store assets, and fixes based on rejection reasons.
  • Product ownershipIdea, design, development, backend, store release and post-release maintenance — I ran the whole process on my own.

Let's talk about 2.El Bilet

I'd be happy to walk you through the technical details, the problems I ran into and how I solved them.