Skip to content

About

Official Kotlin & Java SDK for Nylon Pay (Uganda Mobile Money API)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

7 Commits

Folders and files

Repository files navigation

Nylon Pay Kotlin & Java SDK

JitPack License: MIT

Official Kotlin & Java SDK for the Nylon Pay mobile money payment API (Uganda mobile money: MTN MoMo & Airtel Money).

Features

  • Collect Payments — Mobile money collections (MTN / Airtel) and bank collections
  • Blocking Resolve — collectPaymentAndResolve & makePayoutAndResolve with adaptive polling until terminal state
  • Payouts & Withdrawals — Mobile money and bank disbursement / transfers to customer accounts
  • Hosted Invoices — Create payment links for card and mobile money checkout flows
  • Transaction Queries & Tag Filtering — Query payments by reference or database ID, list transactions by tags and date range
  • Phone Verification — Validate mobile money registered phone numbers and registered customer names
  • Webhook Verification — Constant-time HMAC-SHA256 signature check, delivery ID tracking, and timestamp replay protection
  • Deterministic Request Signing (RFC 8785 / JCS) — Canonical Unicode code-point key ordering + HMAC-SHA256 headers (x-nylon-key, x-nylon-nonce, x-nylon-timestamp, x-nylon-signature)
  • Response Nonce Binding & Integrity — Rejects replayed responses and validates server _responseSignature fail-closed
  • Smart Retries — Automatic exponential backoff + jitter for transient network/server glitches
  • Zero External Dependencies — Uses only Java 11+ standard library (java.net.http, javax.crypto, java.time)

Installation

Option 1: JitPack (Recommended)

Gradle (Kotlin DSL)

repositories {
    mavenCentral()
    maven { url = uri("https://jitpack.io") }
}

dependencies {
    implementation("com.github.nile-squad:nylonpay-kt:1.0.0")
}

Gradle (Groovy)

repositories {
    mavenCentral()
    maven { url 'https://jitpack.io' }
}

dependencies {
    implementation 'com.github.nile-squad:nylonpay-kt:1.0.0'
}

Maven (pom.xml)

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

<dependency>
    <groupId>com.github.nile-squad</groupId>
    <artifactId>nylonpay-kt</artifactId>
    <version>1.0.0</version>
</dependency>

Quick Start (Kotlin)

import com.carthigan.nylonpay.NylonPayClient

val client = NylonPayClient(
    apiKey = "npk_your_api_key",
    apiSecret = "nps_your_api_secret",
)

// 1. Collect Mobile Money Payment (Fire-and-forget for webhook flows)
val payment = client.collectPayment(
    amount = 5000,
    phoneNumber = "0700000000", // Automatically normalized to 256700000000
    customerName = "John Doe",
    description = "Order #1234",
    tags = listOf("checkout", "mobile"),
)
println("Status: ${payment.status}")       // "pending"
println("Reference: ${payment.reference}") // UUID reference to track payment

// 2. Or Collect & Block Until Terminal State (Success, Failed, Cancelled)
val resolvedTx = client.collectPaymentAndResolve(
    amount = 5000,
    phoneNumber = "0700000000",
    customerName = "John Doe",
    description = "Quick checkout",
)
println("Final status: ${resolvedTx.status}") // "successful" / "failed"

// 3. Make a Payout / Disbursement (Min: 5,000 UGX)
val payout = client.makePayout(
    amount = 50000,
    phoneNumber = "0770000000",
    accountHolderName = "Jane Doe",
    description = "Reward Payout",
)
println("Payout Reference: ${payout.reference}")

// 4. Create a Hosted Payment Invoice (Card & Mobile Money)
val invoice = client.createInvoice(
    amount = 25000,
    customerEmail = "customer@example.com",
    customerName = "Alice",
    description = "Monthly Subscription",
)
println("Send payment link to customer: ${invoice.paymentLink}")

Quick Start (Java)

import com.carthigan.nylonpay.NylonPayClient;
import com.carthigan.nylonpay.PaymentResponse;
import com.carthigan.nylonpay.TransactionStatus;

public class Main {
    public static void main(String[] args) {
        NylonPayClient client = new NylonPayClient(
            "npk_your_api_key",
            "nps_your_api_secret"
        );

        PaymentResponse response = client.collectPayment(
            5000,
            "0700000000",
            null, // auto-generates UUID
            "John Doe",
            null, // customerEmail
            "Order #1234",
            "UGX",
            "mobileMoney",
            null, // bank details
            null, // metadata
            null  // tags
        );

        System.out.println("Status: " + response.getStatus());
        System.out.println("Reference: " + response.getReference());
    }
}

Webhook Verification

Verify webhook callbacks from Nylon Pay safely with constant-time HMAC-SHA256 signature verification and timestamp freshness validation:

import com.carthigan.nylonpay.NylonPayWebhookVerifier

val verifier = NylonPayWebhookVerifier(
    webhookSecret = "nps_your_webhook_secret", // from Nylon Pay dashboard
    maxTimestampAgeSeconds = 300L,              // 5 minutes replay tolerance (pass -1L to disable)
)

// In your HTTP webhook handler:
val signature = request.headers["x-nylon-signature"]
val rawBodyBytes = request.receiveChannel().toByteArray()

val result = verifier.verify(rawBodyBytes, signature)

if (result.valid) {
    val deliveryId = result.deliveryId // Use for idempotency / deduplication
    // Process the successful payment in your database
} else {
    // Reject request: 400 Bad Request or 401 Unauthorized
    println("Webhook validation failed: ${result.error}")
}

Note on replay tolerance: maxTimestampAgeSeconds = 0L enforces zero tolerance (maximum strictness). To explicitly disable the freshness check, pass NylonPayWebhookVerifier.DISABLE_FRESHNESS_CHECK (-1L).


Configuration Options

val client = NylonPayClient(
    apiKey = "npk_...",
    apiSecret = "nps_...",
    baseUrl = "https://api.nylonpay.nilesquad.com/api/services", // Optional custom endpoint
    timeout = Duration.ofSeconds(90),                           // Optional timeout (covers inline resolve)
    maxRetries = 3,                                             // Auto-retry transient errors
    maxPollInterval = Duration.ofSeconds(2),                    // Base polling interval
    maxPollDuration = null,                                     // Optional total polling cap
)
Parameter Type Default Description
apiKey String Required API Key starting with npk_
apiSecret String Required API Secret starting with nps_
baseUrl String https://api.nylonpay.nilesquad.com/api/services Base URL for API calls
timeout Duration 90s HTTP connection & read timeout
maxRetries Int 3 Number of automatic retries on network/server errors (408, 429, 5xx)
maxPollInterval Duration 2s Initial polling interval for resolve operations
maxPollDuration Duration? null Optional timeout cap on resolve polling (null = wait until terminal)

API Methods

Method Description
collectPayment(...) Initiate a mobile money or bank collection (returns immediate PaymentResponse)
collectPaymentAndResolve(...) Initiate collection and block until terminal state (successful, failed, cancelled)
makePayout(...) Disburse money to customer mobile money or bank account
makePayoutAndResolve(...) Initiate payout and block until terminal state
getStatus(reference) Fetch current lightweight transaction status
getTransaction(reference?, id?) Fetch full transaction details by reference UUID or transaction ID
createInvoice(...) Create a hosted payment invoice link (supports card & mobile money)
listTransactions(...) Query transactions by tags, status, type, and date range with pagination
getTransactionsByTag(tag, ...) Query transactions associated with a specific tag
verifyPhone(phoneNumber) Verify mobile money account validity and registered customer name
verifyWebhook(rawBody, signature, tolerance?) Verify incoming webhook payload authenticity and freshness

Error Handling

The SDK throws NylonPayException with detailed error categorization:

try {
    val res = client.collectPayment(500, "0700000000")
} catch (e: NylonPayException) {
    println("Error: ${e.message}")
    println("Category: ${e.category}")   // "validation", "auth", "limit", "rate_limit", "network", "timeout", "internal"
    println("Retryable: ${e.retryable}") // true if safe to retry
}

License

MIT License. Copyright (c) 2026 Nile Squad.

About

Official Kotlin & Java SDK for Nylon Pay (Uganda Mobile Money API)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages