Skip to content
16px
How Food Delivery Apps Show "PAID" Instantly on the Delivery Partner's Screen
BackendPaymentsWebSocketsSystem DesignKafkaRedisReal-Time

How Food Delivery Apps Show "PAID" Instantly on the Delivery Partner's Screen

Ever noticed how Zomato or Swiggy instantly flips to "Payment Received" on the delivery partner's screen the second you tap Pay? Here's the backend engineering behind that magic.

February 21, 20264 min read

Ever ordered food on Zomato or Swiggy with UPI-on-delivery and noticed something magical? The second you tap "Pay," your delivery partner's screen instantly flips to "Payment Received." No refresh. No awkward waiting. Just instant confirmation.

Let's break down how this actually works behind the scenes.

The Problem

Think about what's happening here. Two completely different devices — your phone and the delivery partner's phone — need to stay in sync in real time. The payment has to be verified, recorded, and communicated across multiple systems, all within a couple of seconds.

Without good design, you'd end up with scenarios like:

  • You paid but the delivery partner still sees "Pending"
  • The delivery partner marks it as paid but you never actually paid
  • A network glitch causes a double charge

None of this is acceptable at the scale these apps operate — millions of orders a day.

The Flow: What Happens When You Tap "Pay"

Let's walk through each step in sequence.

Step 1: You Place an Order

Your app sends a request through the API Gateway (typically Nginx or AWS ALB). This routes the request to the Order Service, which creates an order with status PENDING in a PostgreSQL database. The order also gets cached in Redis for fast reads.

Step 2: Payment Initiation

The Order Service talks to the Payment Service Core, which is where things get interesting. It doesn't just blindly hit one payment gateway. A Smart Router picks the best gateway (Razorpay, Cashfree, Juspay, etc.) based on real-time success rates. If Razorpay's success rate drops, traffic automatically shifts to Cashfree.

The Payment Service also checks an Idempotency Store (Redis) to make sure duplicate requests don't create duplicate charges.

Step 3: You Pay via UPI/Card

The app loads the Payment SDK (like Razorpay.js or Juspay SDK) and you complete the payment on your end. The money moves from your account to the gateway.

Step 4: The Gateway Confirms via Webhooks

Here's where the real backend engineering kicks in. The payment gateway doesn't call your server and wait for a response. Instead, it fires a webhook — an HTTP POST to your server saying "hey, this payment succeeded."

But webhooks are unreliable. Networks fail. Servers go down. So instead of processing the webhook immediately, the Webhook Receiver dumps it into a message queue (Kafka or SQS).

Step 5: Queue Processing

A Webhook Processor picks up messages from the queue and processes them. It does a few critical things:

  • Dedup check — the same webhook might arrive twice, so it checks the Idempotency Store to avoid double processing
  • Signature verification — confirms the webhook actually came from the gateway, not some attacker
  • Transaction update — marks the transaction as SUCCESS in the Transactions DB (PostgreSQL)

Step 6: Order Status Update

The processor publishes an event that updates the order status from PENDING to PAID. This is the moment of truth.

Step 7: Real-Time Push to Delivery Partner

The order status change triggers the Real-Time Notification layer. This uses Redis Pub/Sub as an event bus to fan out updates. A WebSocket server (Socket.io) pushes the update directly to the delivery partner's app. For backup, a push notification (FCM/APNs) is also sent.

This is why it feels instant — WebSocket connections are persistent. There's no polling. The server pushes the update the moment it happens.

What Makes It Reliable

Several engineering decisions work together to make this system trustworthy at scale.

Smart Gateway Routing

The system doesn't depend on a single payment gateway. The Smart Router continuously monitors success rates and latency of each gateway and routes payments to the one most likely to succeed. If one goes down, the Fallback Logic automatically retries through another.

Idempotency

Duplicate webhooks are a real problem. Gateways often send the same webhook multiple times (it's by design — at-least-once delivery). The Idempotency Store ensures that even if the same webhook arrives 5 times, the payment is only processed once.

Reconciliation Engine

What if a webhook never arrives? A Reconciliation Worker runs as a cron job every 5 minutes, polling for PENDING transactions and verifying their actual status directly with the payment gateway. It also runs a Settlement Tracker that matches expected settlements with actual bank settlements.

This is the safety net that catches everything the real-time flow might miss.

Observability

At this scale, you need eyes on everything. Prometheus + Grafana monitors metrics like webhook processing latency, gateway success rates, and queue depth. If success rates drop below a threshold, alerts fire. Distributed tracing (Jaeger) lets engineers trace a single payment across all these services.

Why This Design Matters

This isn't about fancy tech. It's about solving real problems:

  • For users: You pay after receiving your order and get instant confirmation. No anxiety about whether the payment went through.
  • For delivery partners: They don't need to carry change. No more "bhaiya ₹5 extra nahi hai" moments. Their screen shows PAID the moment you pay.
  • For the business: Every transaction is accounted for. The reconciliation engine ensures nothing slips through the cracks.

The Takeaway

What feels like magic on the surface is really just solid backend design — message queues for reliability, WebSockets for real-time updates, smart routing for resilience, and reconciliation for correctness.

No rocket science. Just thoughtful engineering.


I built a basic prototype of this system in Rust to understand the flow end to end. Check it out: GitHub - Payment Processing

Bhupesh Kumar

Bhupesh Kumar

Backend engineer building scalable APIs and distributed systems with Node.js, TypeScript, and Go.