Nylon PayNylon Pay

Collect Payment

Initiate a payment collection with event-driven status tracking

collectPayment(request)

Initiates a payment collection and returns a PaymentInstance immediately. Use the event listeners to track status changes in real time.

const payment = await nylonpay.collectPayment(request);

Request Fields

FieldTypeRequiredDescription
amountnumberyesPayment amount in smallest currency unit. Minimum 500 UGX
currencyCurrencyyesISO 4217 currency code (e.g., "UGX")
descriptionstringyesPayment description shown to customer
customer.namestringyesCustomer full name
customer.phoneNumberstringyesCustomer phone number. Any common format accepted, auto-normalized to the market's calling code (256… for UGX, 254… for KES). See Phone Number Format
customer.emailstringnoCustomer email address
methodPaymentMethodnoSpecific payment method to use ("mobileMoney" or "bank")
referencestringnoUnique reference (any valid UUID). Auto-generated as UUID v4 if omitted
metadataRecord<string, string>noCustom key-value pairs attached to the transaction
tagsstring[]noUp to 10 business labels for filtering. See Smart Tags
testOutcome"success", "fail", or a Nylon failure codenoForce the sandbox result while testing. Omit it and the sandbox picks success about 70% of the time. Sandbox keys only
prompt"pin"noKeep the sandbox payment pending until you enter the customer PIN. See Testing the customer PIN. Sandbox keys only

Example

import { createNylonPay } from '@nile-squad/nylonpay-ts';

const nylonpay = createNylonPay({
  apiKey: 'npk_test_...',
  apiSecret: 'nps_test_...',
  onError: (error) => {
    if (error.reason === 'SERVICES_DOWN') {
      console.error('Pause payment attempts:', error.message);
    }
  },
});

const payment = await nylonpay.collectPayment({
  amount: 50000,
  currency: 'UGX',
  description: 'Order #12345',
  customer: {
    name: 'John Doe',
    phoneNumber: '+256700000000',
    email: 'customer@example.com',
  },
  reference: '550e8400-e29b-41d4-a716-446655440000', // UUID (any version accepted)
  metadata: {
    orderId: '12345',
    items: '3',
  },
});

payment.on('success', ({ transaction }) => {
  console.log('Payment completed:', transaction.id);
});

Forcing the sandbox result

While testing with a sandbox key, pass testOutcome to force a result. Use "success" to walk the happy path and "fail" or a code such as "insufficient_balance" to walk the failure path, including webhooks and your event handlers. Forced fails are labelled Sandbox simulated:. Omit it and the sandbox succeeds about 70% of the time.

Sending testOutcome with a live key is rejected as a validation error, so remove it before going live.

const payment = await nylonpay.collectPayment({
  amount: 50000,
  currency: 'UGX',
  description: 'Order #12345',
  customer: {
    name: 'John Doe',
    phoneNumber: '+256700000000',
  },
  testOutcome: 'fail',
});

payment.on('failed', ({ error }) => {
  console.log('Payment failed as forced:', error);
});

Testing the customer PIN

Pass prompt: 'pin' with a sandbox key to test the step where the customer enters a PIN. The payment stays pending until you type the customer PIN on the phone in the dashboard Sandbox page. The PIN is 5 digits and appears above the phone. Use the Set PIN button to change it. Every sandbox payment from your merchant accepts the same PIN, whichever sandbox key made the payment.

The customer gets 3 attempts. Three wrong PINs fail the payment. No PIN within 2 minutes fails it too. After the correct PIN, the payment finishes and your webhook is sent as usual. The collectPaymentAndResolve call can wait up to about 2 minutes while the PIN is pending.

The phone's Messages also show the customer's SMS. A collection reads like "YOUR MERCHANT NAME has deducted UGX 7,000 at a fee of UGX 0 from your mobile money account." Each message shows the new balance of the test customer wallet, which starts at UGX 1M. This is test money only.

If you pass both testOutcome and prompt, the forced outcome applies and prompt is ignored. Pass only prompt to test the PIN step.

Sending prompt with a live key is rejected as a validation error, so remove it before going live.

const payment = await nylonpay.collectPayment({
  amount: 7000,
  currency: 'UGX',
  description: 'Order 1042',
  customer: { name: 'Test Customer', phoneNumber: '+256700000000' },
  prompt: 'pin',
});

Payment Flow

  1. Call collectPayment() with the customer details and amount.
  2. The customer receives a payment prompt on their phone.
  3. The SDK reports processing, success, failed, or cancelled events.
  4. Use wait() or webhooks when you need a final transaction state.

Idempotency

The reference field prevents duplicate charges. If a request fails and you retry with the same reference, the SDK returns the existing payment instance instead of creating a new one.

A supplied reference must be a valid UUID of any version. The SDK generates a UUID v4 when you omit reference. Never reuse the same reference for different payments.

Return Value

collectPayment() returns a PaymentInstance with:

MethodDescription
.on(event, handler)Listen for events (processing, success, failed, cancelled, error)
.once(event, handler)Listen once, then auto-remove
.off(event, handler)Remove a handler
.wait()Promise that resolves Transaction on success, null on failure/cancel/error. Never rejects.
.referenceThe transaction reference
.statusCurrent transaction status

On this page