Nylon PayNylon Pay

REST API

Call the Nylon Pay REST API directly from your server

The REST API runs the same operations as the SDK: collect a payment, send a payout, check a transaction, list transactions, and verify a phone number. Every call goes from your server to ours with an access token.

Read Limitations before you choose REST.


1. How a call is shaped

Every operation is one POST to https://api.nylonpay.com/api/services. The body names the operation with service and action, and carries the input in payload. For the REST API, service is always "rest".

curl -s https://api.nylonpay.com/api/services \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "intent": "execute",
    "service": "rest",
    "action": "get-status",
    "payload": {
      "reference": "11db1c21-7f43-490c-b76e-485baa326edf"
    }
  }'

A successful call answers 200 with the result in data. A refused call answers 400 and status is false.

Operationaction
Exchange keys for an access tokenauth
Collect a paymentcollect-payment
Send a payoutmake-payout
Get payment statusget-status
Get a transactionget-transaction
List transactionslist-transactions
Verify a phone numberverify-phone

2. Get an access token

Create a key in Dashboard > API Keys, choose REST API under Use with, then Sandbox or Live. Add allowed IP addresses to a key to accept its calls from those addresses only. A sandbox key made for the SDK also works on the REST API.

Exchange the key and secret for a token with auth:

curl -s https://api.nylonpay.com/api/services \
  -H "Content-Type: application/json" \
  -d '{
    "intent": "execute",
    "service": "rest",
    "action": "auth",
    "payload": {
      "apiKey": "npk_live_...",
      "apiSecret": "nps_live_..."
    }
  }'

Send the token on every other call as Authorization: Bearer <accessToken>.

  • Calls are server to server. We refuse them from a browser.
  • A token is valid for up to one hour. expiresIn is in seconds.
  • Use one key per server calling the API.
  • When a call is refused for authentication, get a new token with auth and retry the same request once, with the same reference. If it is refused again, surface the error.

3. Operations

Collect a payment

collect-payment starts a payment from the customer's mobile money or bank account.

FieldTypeRequiredDescription
amountnumberyesAmount in the smallest currency unit. Minimum 500 UGX
currencystringyesISO 4217 currency code (e.g. "UGX")
descriptionstringyesShown to the customer
customer.namestringyesCustomer full name
customer.phoneNumberstringyesAny common format accepted, auto-normalized to the market's calling code (256… for UGX). See Phone Number Format
customer.emailstringnoCustomer email address
methodstringno"mobileMoney" or "bank"
referencestringyesUUID of any version. Same reference, same payment
metadataobjectnoCustom string key-value pairs attached to the transaction
tagsstring[]noUp to 10 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 Sandbox. Sandbox keys only
curl -s https://api.nylonpay.com/api/services \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "intent": "execute",
    "service": "rest",
    "action": "collect-payment",
    "payload": {
      "amount": 50000,
      "currency": "UGX",
      "description": "Order #12345",
      "customer": {
        "name": "John Doe",
        "phoneNumber": "+256700000000",
        "email": "customer@example.com"
      },
      "reference": "11db1c21-7f43-490c-b76e-485baa326edf",
      "metadata": { "orderId": "12345" }
    }
  }'

A second call with the same reference answers the same payment, marked duplicate: true. It carries the response recorded when the payment was created, so check Get payment status for the current state.

Send a payout

make-payout sends money to a customer's mobile money account or bank account.

FieldTypeRequiredDescription
amountnumberyesAmount in the smallest currency unit. Minimum 5,000 UGX for mobile money, 50,000 UGX for bank transfers
currencystringyesISO 4217 currency code (e.g. "UGX")
descriptionstringyesPayout description
customer.namestringyesRecipient full name
customer.phoneNumberstringyesRecipient phone number. Any common format accepted, auto-normalized
customer.emailstringnoRecipient email address
destination.accountHolderNamestringyesName on the receiving account
destination.accountNumberstringyesMobile money number or bank account number
destination.bankNamestringnoBank name, required for bank account payouts
destination.phonestringyesRecipient phone number, auto-normalized
referencestringyesUUID of any version. Same reference, same payout
metadataobjectnoCustom string key-value pairs attached to the transaction
tagsstring[]noUp to 10 labels for filtering
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 payout pending until you enter the customer PIN. See Sandbox. Sandbox keys only
curl -s https://api.nylonpay.com/api/services \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "intent": "execute",
    "service": "rest",
    "action": "make-payout",
    "payload": {
      "amount": 5000,
      "currency": "UGX",
      "description": "Withdrawal 1042",
      "customer": {
        "name": "Jane Doe",
        "phoneNumber": "+256700000000"
      },
      "destination": {
        "accountHolderName": "Jane Doe",
        "accountNumber": "+256700000000",
        "phone": "+256700000000"
      },
      "reference": "07808afc-9ba0-4dc9-9689-f577a979e1e2"
    }
  }'

A new reference starts a new payout. Reuse the same reference when retrying.

Get payment status

get-status checks one transaction by reference. Use it to confirm a payment after a timeout or when a webhook has not arrived.

FieldTypeRequiredDescription
referencestringyesThe reference used at creation
curl -s https://api.nylonpay.com/api/services \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "intent": "execute",
    "service": "rest",
    "action": "get-status",
    "payload": {
      "reference": "11db1c21-7f43-490c-b76e-485baa326edf"
    }
  }'
FieldDescription
idNylon transaction ID
operatorTidID on the customer's operator or bank receipt. null until it is reported
failureReasonHuman sentence when the payment failed or was cancelled, otherwise null
failureCategoryBroad class: provider, customer, internal, validation
failureCodeNylon code such as insufficient_balance
statusTextExtra human sentence. For on_hold, the review sentence for example "This payout is being reviewed and will complete shortly."
delayedtrue when the payment has been waiting longer than a few minutes

Get a transaction

get-transaction returns the full transaction record. Pass id or reference, one of the two.

curl -s https://api.nylonpay.com/api/services \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "intent": "execute",
    "service": "rest",
    "action": "get-transaction",
    "payload": {
      "id": "cc0e59d2-0a28-4bb6-8344-32aea6f8ce8c"
    }
  }'

List transactions

list-transactions returns your transactions, newest first.

FieldTypeRequiredDescription
tagsstring[]noReturn transactions carrying all of these tags
statusstringnopending, processing, on_hold, successful, failed, or cancelled
typestringnoTransaction type filter
limitnumbernoPage size from 1 to 100. Default 20
offsetnumbernoRows to skip. Default 0
createdAfterstringnoISO 8601 datetime
createdBeforestringnoISO 8601 datetime
curl -s https://api.nylonpay.com/api/services \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "intent": "execute",
    "service": "rest",
    "action": "list-transactions",
    "payload": {
      "limit": 20,
      "offset": 0
    }
  }'

Verify a phone number

verify-phone asks the operator for the name registered on a phone number. Use it to confirm a customer's identity before a collection or a payout.

FieldTypeRequiredDescription
phoneNumberstringyesPhone number in any common format, auto-normalized
purposestringno"collection" or "payout"
curl -s https://api.nylonpay.com/api/services \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "intent": "execute",
    "service": "rest",
    "action": "verify-phone",
    "payload": {
      "phoneNumber": "+256700000000"
    }
  }'

4. Statuses and polling

StatusMeaning
pendingCreated. The customer has not acted yet, or the payout is queued
processingIn flight with the operator or bank
on_holdWaiting on a review. statusText carries the sentence to show
successfulMoney moved
failedIt did not complete. failureReason and failureCode say why
cancelledStopped before completion

A payment in pending or processing for longer than a few minutes comes back with delayed: true on status checks.

Webhooks push status changes to your server. Use get-status or get-transaction to confirm after a timeout, after a delayed result, or when a webhook has not arrived. Space status checks as our polling guidance describes.


5. Errors

Refusals raised by the operation end with an error-type value. Branch on that value, not on message text. A request with missing or malformed fields is refused before the operation runs, with a Validation failed: message naming the field.

error-typeMeaningRetry
authKey, token, or permission refusedNo. Get a new token and retry once, then fix the key
validationInput rejectedNo. Correct the input first
limitAccount or KYC transaction limit exceededNo. The amount exceeds the account limit
rate_limitToo many requestsYes, after the wait given in the message
accountMerchant account missing or not activeNo
providerThe payment provider rejected the operationYes, after a delay
duplicateThe reference belongs to another transactionNo. Retry with a new reference
not_foundThe reference or id does not exist yetNo
internalUnexpected server-side failureYes, after a delay. Contact support if it repeats

6. Sandbox

With a sandbox key, pass testOutcome to force the result. Use "success" to walk the happy path and "fail" or a code such as "insufficient_balance" to walk the failure path, including webhooks. Forced fails are labelled Sandbox simulated:.

curl -s https://api.nylonpay.com/api/services \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "intent": "execute",
    "service": "rest",
    "action": "collect-payment",
    "payload": {
      "amount": 50000,
      "currency": "UGX",
      "description": "Order #12345",
      "customer": { "name": "John Doe", "phoneNumber": "+256700000000" },
      "reference": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
      "testOutcome": "fail"
    }
  }'

Pass prompt: "pin" to hold a sandbox payment until you enter the customer PIN on the dashboard Sandbox page. Pass both and the forced outcome applies and prompt is ignored. The PIN flow works the same as it does with the SDK; see Testing the customer PIN.

Sending testOutcome or prompt with a live key is refused as a validation error, so remove them before going live.


7. Webhooks

We send a webhook to your server when a payment changes status. The same events, payloads, and signature verification apply whether the payment came through the SDK or the REST API. See Webhooks.


8. Limitations

The REST API covers the core payment flow. The SDKs cover more, and do more of the work for you.

SDKREST API
Request protectionEvery request is signed, and a captured request cannot be sent againAnyone holding the access token can call with it until it expires
Response protectionEvery response is verified as coming from us, unchangedYour code trusts what arrives over HTTPS
Signing inAutomaticYou exchange keys for a token and get a new one every hour
Waiting for the resultwait() and payment events report the final statusYou poll get-status or handle webhooks yourself
RetriesBuilt in, with the same referenceYou retry, and must reuse the same reference
ErrorsTyped errors with a reason to branch onYou read error-type from the message text
KeysAny serverOne key per server
OperationsEverything on this page, plus invoices, collect-and-wait, payout-and-wait, airtime and billsThe seven operations on this page

Use the REST API when your stack has no SDK. Otherwise use an SDK: TypeScript, Python or PHP.


See Also

On this page