McTaba Labs logo
Software EngineeringThe WhiteboardProjectsEventsMasterclassesWebinarsLearn
Book Call

500+ developers already in the community

Get answers, find accountability partners, and stay ahead

Join Discord →
McTaba Labs logo

Educating 1 million students in tech by 2030.

Programs

  • HighSchool Graduates Launchpad
  • AI & Business Automation
  • Corporate Training
  • McTaba Story & Mission
  • Full-Stack Curriculum
  • Course Pricing & Plans
  • Frequently Asked Questions

Resources

  • Join Discord Community
  • Tech Events in Nairobi
  • Masterclasses
  • Free Resources
  • Learn
  • Campus
  • Africa Tech Talent Report
  • Partner With Us
  • Start a Project
  • Our Work

Contact Us

  • 124 Manyani East Road, Lavington, Nairobi
  • +254727795603
  • Book a Discovery Call

Office Hours:

Mon-Fri: 9am - 2pm EAT

Sat: 10am - 12pm EAT

© 2027 McTaba Labs - A product of Edtech Industries. All rights reserved.

Privacy PolicyTerms of ServiceRefund Policy
  1. Learn
  2. Paystack for African Developers
  3. Handle Paystack Webhooks in Android with Kotlin
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 22, 2026

Handle Paystack Webhooks in Android with Kotlin

Android apps cannot receive Paystack webhooks directly. Build a webhook endpoint on your backend, verify the x-paystack-signature, and update your database. Use Firebase Cloud Messaging (FCM) to push payment events to the Android app. In the Android app, handle FCM messages in a FirebaseMessagingService subclass and update the UI.

In this article

  1. 1. Architecture
  2. 2. Backend Webhook Handler with FCM
  3. 3. Android: Firebase Messaging Service
  4. 4. Learn More

Architecture

Paystack fires webhooks to your server. Your server then notifies the Android app:

Paystack → Your Backend Server (webhook received + verified)
                     ↓
               Update Database
                     ↓
            FCM Push to Android App
                     ↓
        FirebaseMessagingService handles message
                     ↓
           Update ViewModel / UI

Backend Webhook Handler with FCM

// Node.js backend with Firebase Admin SDK
var crypto = require('crypto');
var admin = require('firebase-admin');

app.post('/api/webhooks/paystack',
  express.raw({ type: 'application/json' }),
  async (req, res) => {
    var sig = req.headers['x-paystack-signature'];
    var hash = crypto
      .createHmac('sha512', process.env.PAYSTACK_SECRET_KEY)
      .update(req.body)
      .digest('hex');

    if (hash !== sig) return res.status(400).send('Invalid signature');
    res.sendStatus(200);

    var event = JSON.parse(req.body.toString());

    if (event.event === 'charge.success') {
      var email = event.data.customer.email;
      var reference = event.data.reference;
      var amount = event.data.amount / 100;

      // Update order in DB
      await db.orders.markAsPaid(reference);

      // Get user's FCM token
      var user = await db.users.findByEmail(email);
      if (user?.androidFcmToken) {
        await admin.messaging().send({
          token: user.androidFcmToken,
          notification: {
            title: 'Payment Received',
            body: 'NGN ' + amount + ' confirmed. Ref: ' + reference
          },
          data: {
            event: 'charge.success',
            reference: reference,
            amount: String(amount)
          }
        });
      }
    }
  }
);

Get weekly developer tips

Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.

No spam. Unsubscribe anytime.

Android: Firebase Messaging Service

Add Firebase to your Android project, then create a messaging service:

// PaystackMessagingService.kt
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage

class PaystackMessagingService : FirebaseMessagingService() {

    override fun onNewToken(token: String) {
        super.onNewToken(token)
        // Send the new token to your backend
        sendTokenToBackend(token)
    }

    override fun onMessageReceived(message: RemoteMessage) {
        super.onMessageReceived(message)

        val event = message.data["event"]
        val reference = message.data["reference"]
        val amount = message.data["amount"]

        when (event) {
            "charge.success" -> {
                // Send a broadcast that the payment Activity/ViewModel can receive
                val intent = android.content.Intent("com.yourapp.PAYMENT_SUCCESS")
                intent.putExtra("reference", reference)
                intent.putExtra("amount", amount)
                sendBroadcast(intent)

                // Also show a notification
                showNotification("Payment Confirmed", "NGN $amount received")
            }
        }
    }

    private fun showNotification(title: String, body: String) {
        val notificationManager = getSystemService(NOTIFICATION_SERVICE)
            as android.app.NotificationManager
        val channelId = "payment_events"

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            val channel = android.app.NotificationChannel(
                channelId, "Payment Events",
                android.app.NotificationManager.IMPORTANCE_HIGH
            )
            notificationManager.createNotificationChannel(channel)
        }

        val notification = androidx.core.app.NotificationCompat.Builder(this, channelId)
            .setContentTitle(title)
            .setContentText(body)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setAutoCancel(true)
            .build()

        notificationManager.notify(System.currentTimeMillis().toInt(), notification)
    }

    private fun sendTokenToBackend(token: String) {
        // Use Retrofit to POST the token to your backend
        // Store it so your backend can target this device
    }
}

Register in AndroidManifest.xml:

<service
    android:name=".PaystackMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

Learn More

This guide is part of the Paystack integration guides by language and framework series.

Sign up for the McTaba newsletter

Key Takeaways

  • ✓Paystack webhooks are HTTP POST requests to your server. Android apps cannot receive them directly.
  • ✓Build the webhook handler on your backend (Node.js, Django, Spring Boot, etc.).
  • ✓Use Firebase Cloud Messaging (FCM) to push payment confirmation events to the Android app.
  • ✓Implement a FirebaseMessagingService in Android to receive and handle FCM messages.
  • ✓Send the FCM token from Android to your backend so it can target specific devices with payment events.
  • ✓For simpler setups, poll a backend status endpoint after checkout instead of using push notifications.

Frequently Asked Questions

Do I need Firebase for Paystack webhooks in Android?
No. Firebase is one option for delivering payment events to Android. You can also poll a backend status endpoint after checkout. Polling is simpler but less efficient. FCM is better for background notifications when the user is not actively using the app.
How do I send the FCM token to my backend from Android?
Override onNewToken in your FirebaseMessagingService. Call FirebaseMessaging.getInstance().getToken() in your main Activity on startup. Store the token in SharedPreferences and send it to your backend API when the user logs in or on first launch.
What if the user does not allow notifications on Android 13+?
Request the POST_NOTIFICATIONS permission at runtime on Android 13+ using ActivityCompat.requestPermissions. If denied, fall back to polling the backend status endpoint after checkout. Always provide an in-app payment status screen the user can check manually.
Can I receive Paystack webhooks directly in Android?
No. Android apps do not have a public HTTPS domain that Paystack can reach. You must have a server-side endpoint. If you want a serverless solution, use Supabase Edge Functions or Firebase Cloud Functions as your webhook receiver.

Learn Paystack Integration

KES 2,999

The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.

Start Paystack Course

Not ready? Create Free Account

Keep reading

Paystack Integration Guides by Language and Framework

A complete directory of Paystack integration guides organized by programming language and framework. Each guide covers accepting payments, verifying transactions, handling webhooks, and building subscriptions in your specific stack.

Read more

Accept Payments with Paystack in Android with Kotlin

Accept Paystack payments in a native Android app built with Kotlin. This guide covers initializing transactions from your backend, displaying the Paystack checkout in a WebView Activity, detecting the callback redirect, and verifying payment.

Read more

Verify Paystack Payments in Android with Kotlin

After Paystack checkout in Android, send the transaction reference to your backend for verification. This guide shows how to call your backend verify endpoint with Retrofit and Kotlin coroutines, handle success and failure, and update your UI.

Read more

Build Paystack Subscriptions in Android with Kotlin

Add Paystack subscription billing to a native Android app. This guide covers initializing subscription transactions from your backend, the WebView checkout flow in Kotlin, checking subscription status, and building a plan management screen.

Read more

Idempotent Paystack Webhook Handlers: The Complete Pattern

A complete guide to building idempotent Paystack webhook handlers. Covers why Paystack sends duplicate events, using transaction references as idempotency keys, database-level deduplication with a processed_events table, and the full production-ready pattern in Node.js.

Read more

Why You Must Return 200 Immediately from a Paystack Webhook

The number one Paystack webhook reliability rule: return 200 before doing anything else. This guide explains why Paystack has a timeout, what happens when you break the rule, and how to implement the respond-first-then-queue pattern in Node.js.

Read more

Explore related topics

M-Pesa & African Stack

M-Pesa Daraja API tutorials, USSD development, and WhatsApp Business API guides. The African Stack that global bootcamps do not teach.

Learn to Code in Kenya

Everything a Kenyan needs to know before writing their first line of code. Career paths, real costs, hardware requirements, and honest answers about what it takes.

Learning to Code

Roadmaps, language guides, and practical advice for learning to code and launching a programming career.

Breaking Into Tech

Practical, no-nonsense guides for anyone looking to start or change their career in tech. From choosing your first language to acing interviews.

The African Stack: Skills for This Market

The skills that make Kenyan developers hard to replace: M-Pesa, USSD, WhatsApp, fintech, and building for the African market.

Bonaventure Ogeto

Bonaventure Ogeto

Founder, McTaba Labs

Bonaventure is the founder of McTaba Labs, a coding bootcamp in Nairobi, Kenya. He has spent years building products for the African market and mentoring the next generation of developers across the continent.