Note: When a client posts a project and a freelancer takes it on, risks arise: non-completion, non-payment, disputes. To minimize these, a complex architecture is needed: two user types, escrow payments, offline-capable chat, and a rating system. We build such marketplaces using modern mobile technologies: Swift 5.9, Kotlin, Flutter 3.x, and Stripe Connect integration for secure transactions. Over 6 years on the market, we have delivered more than 20 mobile freelance exchanges, including projects with millions of users. The average exchange processes up to 10,000 orders monthly; with an average order value of $150 and a platform commission of 10–15%, that's $15–22.5 per order. 85% of orders complete successfully, and the average freelancer rating is 4.7. A basic MVP costs approximately $15,000–$25,000 depending on complexity. Contact us for a consultation on your project.
How to Build a Mobile App for a Freelance Exchange
The choice between separate accounts and a single account with role switching defines the app architecture. Separate accounts (like Upwork) are simpler for rights management, but a user cannot be both. A single account (like Kwork) requires a context manager but is more convenient. Technically: userRole: 'client' | 'freelancer' in session, different navigation trees.
// iOS: navigation by role via enum enum UserContext { case client case freelancer } class AppCoordinator { var currentContext: UserContext = .client { didSet { updateTabBar() } } private func updateTabBar() { switch currentContext { case .client: tabBarController.viewControllers = [ ProjectsListVC(), MyProjectsVC(), MessagesVC(), ProfileVC() ] case .freelancer: tabBarController.viewControllers = [ FindProjectsVC(), MyOrdersVC(), MessagesVC(), ProfileVC() ] } } } How to Implement Secure Payments?
The key feature of an exchange is funds held by the platform until task completion. The scheme:
- Client creates a project and deposits the amount into an escrow account (charge/capture)
- Freelancer completes the work and submits the result
- Client approves → platform transfers funds to freelancer minus commission
- If dispute → arbitration (manual or automated)
- If client does not respond for N days → automatic confirmation
Escrow payments are implemented via Stripe Connect automatic splitting. For example, to release payment:
# Stripe Connect: split payment with automatic platform commission import stripe def release_payment_to_freelancer(escrow_payment: EscrowPayment) -> None: platform_fee = int(escrow_payment.amount * Decimal("0.10")) # 10% commission # Create transfer to freelancer transfer = stripe.Transfer.create( amount=escrow_payment.amount - platform_fee, currency="usd", destination=escrow_payment.freelancer_stripe_account_id, transfer_group=escrow_payment.project_id, metadata={ "project_id": escrow_payment.project_id, "order_id": escrow_payment.order_id } ) db.update_escrow( escrow_payment.id, status="RELEASED", transfer_id=transfer.id ) notify_freelancer(escrow_payment.freelancer_id, "payment_released", transfer.amount) Partial payment (milestone payments) reduces risk by 40% compared to lump-sum payment.
How Does the Bidding System Work?
Freelancers place bids on projects: they offer a price and deadline. The client sees a list of proposals, portfolios, and ratings. Beginner freelancers get 5 free bids per month, after which bids are paid. This is a monetization model.
// Android: bidding list with sorting data class Bid( val id: String, val freelancerId: String, val amount: Decimal, val deliveryDays: Int, val coverLetter: String, val freelancer: FreelancerProfile ) @Composable fun BidsList( bids: List<Bid>, sortBy: BidSortOption, onHire: (Bid) -> Unit ) { val sorted = when (sortBy) { BidSortOption.PRICE -> bids.sortedBy { it.amount } BidSortOption.RATING -> bids.sortedByDescending { it.freelancer.rating } BidSortOption.DELIVERY -> bids.sortedBy { it.deliveryDays } } LazyColumn { items(sorted, key = { it.id }) { bid -> BidCard(bid = bid, onHire = { onHire(bid) }) } } } How to Organize Chat with Offline Mode?
Chat is a mandatory component. Requirements: delivery, statuses, files, links to tasks. Technically: WebSocket + offline queue. Storage — Core Data (iOS) or Room (Android).
// iOS: offline message queue class MessageQueue { private let context: NSManagedObjectContext private var syncTimer: Timer? func sendMessage(_ content: String, conversationId: String) { // Save locally immediately let pending = PendingMessage(context: context) pending.id = UUID().uuidString pending.content = content pending.conversationId = conversationId pending.createdAt = Date() pending.status = "PENDING" try? context.save() // Show in UI as sent NotificationCenter.default.post(name: .messageSent, object: pending) // Sync when connection is available syncPendingMessages() } func syncPendingMessages() { guard networkMonitor.isConnected else { return } let pending = fetchPendingMessages() pending.forEach { msg in apiClient.sendMessage(msg) { result in switch result { case .success(let serverMessage): msg.status = "DELIVERED" msg.serverId = serverMessage.id try? context.save() case .failure: // Retry on next sync break } } } } } Comparison: Separate Accounts vs Single Role
| Criterion | Separate accounts | Single account with role switching |
|---|---|---|
| Rights management | Simpler, logic isolated | Requires context manager |
| Flexibility | User cannot be both client and freelancer | Easy to switch between roles |
| Development speed | Higher (separate modules) | Lower (role checks needed) |
| UX | Two apps in one | Single login, single interface |
Separate accounts are simpler to manage and develop, saving up to 20% of implementation time compared to a single account. However, a single account is more convenient for users who want to combine roles.
Ratings and Reputation
After order closure — mutual reviews. Rating affects search ranking. Protection from manipulation: review can only be left for a specific completed order; mutual anonymity until publication (like on Upwork); Bayesian average algorithm instead of simple average — a new profile without reviews won't show "5.0 out of 5". The average freelancer rating is 4.7, and 85% of orders complete successfully. Verified freelancers get 3x more job offers than unverified ones.
Verification and KYC
For fund withdrawal — mandatory identity verification. Exchanges often have two levels: basic (email + phone) and advanced (KYC via Sumsub or Veriff SDK). The advanced level lifts withdrawal limits, adds a "Verified" badge, and increases trust in the freelancer by 3 times.
What's Included in Development?
We provide a full package: project documentation (architecture, API specs, DB schemas), mobile app source code, backend for payments and chat, configured CI/CD pipelines, access to test and production accounts, operation instructions, and technical support for 2 weeks after launch. We train your team on how to use the system.
Timeline Estimates
| Scope | Time |
|---|---|
| Project catalog, profiles, bids, no payments | 5–7 weeks |
| Escrow payments, Stripe Connect for payouts | +3–4 weeks |
| Chat with WebSocket and offline queue | +2–3 weeks |
| KYC integration, review system | +2 weeks |
Cost is calculated individually after analyzing requirements and chosen stack. We will evaluate your project within 1–2 days — simply describe the task. Get a consultation: specify the main features and preferred stack, and we'll propose the optimal solution. Our mobile freelance exchange development includes escrow payments, chat, and ratings. Request a consultation, and we'll contact you within 24 hours.







