# Integrate NuePay API v1

Build against https://api.nuepay.net/v1. Read the linked contract and relevant guides before writing code. If behavior is unspecified, flag the gap instead of inventing an endpoint or parameter.

## Implementation rules

- Call NuePay from your server with `Authorization: Bearer <secret>`. Keep integration credentials in environment variables; never embed them in browser code, prompts, logs or source control.
- The official sandbox playground at `https://platform.nuepay.net/developers#sandbox` is the browser exception: it accepts `np_test_` secrets in tab memory and calls the canonical API. Canonical API browser CORS permits only `https://platform.nuepay.net`; merchant websites and live secrets do not belong in this flow.
- A named key identifies its application and merchant. Do not send an application nickname or account number for authentication. Up to ten applications share the merchant wallet; there are no separate application wallets or spending scopes.
- Start with `np_test_` credentials and simulated funds. The same API base accepts test and live keys. Verify `/application` and the expected `mode` before testing. Only switch to real payments when explicitly authorized by the merchant.
- Send UGX amounts as decimal strings, never binary floating-point calculations. Collections credit the requested principal; the quoted total includes NuePay's fee and is rounded up to whole UGX. Telecom charges may apply; display this notice with the collection total. Disbursements require whole UGX amounts and debit principal plus fee. Get `/quotes` before displaying charges; quotes do not move or reserve funds.
- Bind the displayed total: send `expected_payer_charge` for collections or `expected_wallet_debit` for disbursements. A `409 quote_changed` rejects creation before any payment starts; refresh the quote and obtain approval again. Accepted retries retain their saved pricing and exact payload. Limits and fee ranges can change; never hardcode them.
- Persist a UUID and the exact payment payload before calling `/collections` or `/disbursements`. Send that UUID in `Idempotency-Key`. After a timeout or retry, reuse both; never issue a fresh UUID to retry an uncertain payment. A changed payload with the same UUID returns `409`.
- `202` means accepted. Only `success` confirms payment. `process` is unresolved; an HTTP or browser timeout is not proof of failure. Collections unconfirmed at NuePay's 120-second deadline return `failed/payment_timeout`; poll every 15 seconds. A confirmed failure permits a fresh customer attempt with a new UUID. A delayed notification of an earlier success must still be reconciled and fulfilled once; never discard a confirmed receipt or release an interrupted invoice-posting reservation because a browser timer expired. An actual NuePay `failed/payment_timeout` result remains a failed checkout; contradictory late funds need separate reconciliation.
- A payout with `process/authorization_required` is awaiting an additional approval. Retain its original reference, idempotency UUID and payload; its original wallet debit remains reserved. Do not create another payout. Follow status reads and verified webhooks or contact NuePay Support. The reason change increments the payment version and records a `disbursement.process` event.
- For bounded collection initiation, send optional `request_expires_at` in exact UTC `YYYY-MM-DDTHH:MM:SSZ` form and preserve it on retries. New requests at or after that acceptance deadline return `410 request_expired` without creation; existing identical requests still return the original payment. It does not extend approval time. Recover a lost response with `GET /collections/{requestId}` using the saved idempotency UUID, application and environment. This never sends a phone prompt. A 404 after the saved acceptance deadline confirms that request can no longer create a collection. Use `/transactions/{reference}` once the reference is known.
- Handle non-2xx responses using `code`, `message` and `errors`. Log the HTTP `X-Request-Id` for investigation; `data.request_id` identifies the original payment UUID, not the current HTTP attempt. Honor rate limits and use bounded backoff.
- Configure each application's HTTPS notification URL in Keys & Webhooks. Use View Signing Secret beside the same key to copy its whsec_ code. The API key requests payments; the signing secret verifies updates. Verify `X-NuePay-Signature` using HMAC-SHA256 over `timestamp + "." + raw_body`, compare in constant time, and reject timestamps more than five minutes from your synchronized clock.
- After signature verification, match body `id` to `X-NuePay-Event-Id`, check `livemode`, durably deduplicate event IDs, and apply only newer payment `version` values. Save events before returning 2xx. Deliveries may repeat or arrive out of order; fulfil a real order only on a live success.

## Acceptance checks

- Test collection and disbursement success, failure and timeout with the sandbox simulation endpoint. Sandbox never moves real funds; sandbox webhook delivery is opt-in.
- Test identical retries, changed-payload conflicts and a network timeout after dispatch. Verify that neither charges nor fulfilment repeat.
- Test invalid signatures, stale timestamps, duplicate/out-of-order webhooks, test/live isolation and insufficient wallet funds.
- Store payment reference, application ID, merchant reference, idempotency UUID, status and version. Reconcile any unresolved payment before showing a final outcome.

## Read next

- [Quickstart](https://docs.nuepay.net/quickstart/index.md)
- [All endpoints](https://docs.nuepay.net/api/index.md)
- [Retries and statuses](https://docs.nuepay.net/reliability/index.md)
- [Webhook verification](https://docs.nuepay.net/webhooks/index.md)
- [Going live](https://docs.nuepay.net/going-live/index.md)

## Source

API v1. Behavior reviewed against platform commit `a486150c60056ea6eb7742ce26fc9cac5a13929f` on 2026-11-04.
Docs index: https://docs.nuepay.net/llms.txt. Contract: https://docs.nuepay.net/openapi.json.

---

# WooCommerce gateway

Install NuePay for MTN and Airtel Uganda payments on a UGX WooCommerce store.

Canonical page: https://docs.nuepay.net/woocommerce/

Accept MTN and Airtel Uganda mobile money on your WooCommerce store. Customers review the fee, enter their number and approve payment on their phone.

## Before you install

- An approved NuePay account with API access and a dedicated application for your store.
- WordPress 6.4+, WooCommerce 8.3+, PHP 8.1+ with OpenSSL, and MySQL/MariaDB.
- A store priced in UGX, HTTPS, normal WordPress permalinks and working WordPress cron.

The gateway supports classic checkout, Checkout Blocks and High-Performance Order Storage (HPOS). No Node service or Composer installation is needed on the store.

## Install and activate

1. Back up your store and obtain the NuePay WooCommerce release ZIP. NuePay administrators publish approved packages in [Integrations → Plugins](https://platform.nuepay.net/integration/plugins); contact support if the package is not listed.
2. In WordPress, open **Plugins → Add New → Upload Plugin**, select the ZIP and choose **Install Now**.
3. Activate the plugin, keep WooCommerce active and open **WooCommerce → Settings → Payments → NuePay**.

Upload the installable ZIP, not the source repository. The package includes README.md, INSTALLATION.md and GUIDE.md.

## Connect your store

Create a dedicated application in NuePay **Keys & Webhooks**. Copy its test API secret and use **View Signing Secret**, with your transactional PIN, to obtain its separate webhook signing secret.

| Setting | Value |
| --- | --- |
| Test mode | Enabled during setup |
| Test API secret | The application's `np_test_` secret |
| Test webhook signing secret | Its separate `whsec_` secret |
| Live API and signing secrets | The corresponding live application credentials, when going live |

Save changes, then choose **Check saved connection**. No account number is required and no payment is requested. Saved secrets are encrypted and never shown back in the form; blank fields keep existing values.

## Set the notification URL

Copy the exact **Webhook URL** shown in the payment settings and save it on the matching NuePay application. Include any WordPress subdirectory.

```
https://YOUR-STORE-HOST/wp-json/nuepay/v1/webhook
```



Use a public HTTPS hostname on port 443. If WordPress generates a `?rest_route=` URL, enable normal permalinks and copy the new URL. Allow POST requests through security/cache services without requiring a WordPress login.

Enable **Send payment updates**. Sandbox callbacks also require sandbox delivery to be enabled. Localhost cannot receive public callbacks; checkout polling can still confirm sandbox outcomes.

## Test checkout

1. Keep Test mode on, enable NuePay and place an order.
2. Choose NuePay, review the order amount, NuePay fee and total, enter a supported number and confirm the total.
3. Choose **Start test payment**, then use **Success**, **Failed** or **Timeout**.
4. Refresh during an attempt and confirm the original payment recovers without another request.

> **Test success leaves the order unpaid**
> 
> Sandbox moves no real money, does not release downloads and does not trigger paid-order fulfilment. Timeout stays pending and can later be simulated as Success or Failed.

Test the checkout your store actually uses, including guest and signed-in customer access. Before real use, configure the live secrets, switch off Test mode, check the saved connection and verify an owner-approved controlled payment.

## Payment totals and confirmation

Opening checkout and loading a quote never sends a phone prompt. The customer confirms the quoted total before requesting payment. NuePay adds its quoted fee to the order principal; telecom charges may apply separately.

Checkout checks every 15 seconds. Verified notifications and background recovery can finish the same attempt after the browser closes. Only a matching live success marks the order paid. New requests stay blocked while an earlier outcome is uncertain.

Changed or cancelled orders, mismatched amounts and conflicting payments require store review. Compare the original reference in NuePay before marking an order paid or arranging a refund.

## Recovery and maintenance

Keep WordPress cron and WooCommerce Scheduled Actions working. The `nuepay_reconcile` action checks unresolved attempts every minute. Exclude checkout, order-pay, payment AJAX requests and the webhook from full-page caching.

Review order notes and **WooCommerce → Status → Logs → nuepay**. If a payment remains pending, check its original reference and delivery history; do not delete records to force another charge.

### Secrets, upgrades and supported scope

Keep WordPress security salts in private migration backups: saved secrets and pending payloads depend on them. For signing-secret rotation, pause updates in NuePay, rotate, save the replacement, then resume updates and review delivery history. API-secret rotation is separate.

Back up before upgrades and replace the plugin as one package. Deactivation stops scheduled recovery and preserves records. This release supports individual UGX collections; automatic subscriptions, currency conversion, bulk payments, saved payment methods and API refunds are outside its scope.
