All providers

Notch Pay

payment·🇨🇲🇨🇮🇸🇳🇰🇪🇺🇬🇬🇭·Sandbox available

Notch Pay is a payment gateway enabling businesses to accept and send money via mobile money (MTN MoMo, Orange Money, M-Pesa, Wave, Airtel) across Cameroon, Côte d'Ivoire, Senegal, Kenya, Uganda and Ghana. Each market settles in its local currency (XAF in CM; XOF in CI/SN; KES, UGX, GHS).

Use with AI agents

After installing the plugin or adding the MCP server, prompt your agent:

Add Notch Pay checkout to accept MTN MoMo and Orange Money payments in Cameroon.
Install the plugin →

Capabilities

CapabilityTypeStatusiMethodExample
block_customersynchronousAvailablePOST
cancel_paymentsynchronousAvailableDELETE
create_beneficiarysynchronousAvailablePOST
create_customersynchronousAvailablePOST
create_paymentsynchronousAvailablePOST
create_webhooksynchronousAvailablePOST
delete_beneficiarysynchronousAvailableDELETE
delete_customersynchronousAvailableDELETE
delete_webhooksynchronousAvailableDELETE
get_balancesynchronousAvailableGET
get_beneficiarysynchronousAvailableGET
get_customersynchronousAvailableGET
get_webhooksynchronousAvailableGET
list_beneficiariessynchronousAvailableGET
list_channelssynchronousAvailableGET
list_countriessynchronousAvailableGET
list_currenciessynchronousAvailableGET
list_customer_payment_methodssynchronousAvailableGET
list_customer_paymentssynchronousAvailableGET
list_customerssynchronousAvailableGET
list_paymentssynchronousAvailableGET
list_transferssynchronousAvailableGET
list_webhookssynchronousAvailableGET
process_paymentsynchronousAvailablePOST
send_transfersynchronousAvailablePOST
unblock_customersynchronousAvailablePOST
update_customersynchronousAvailablePOST
update_webhooksynchronousAvailablePUT
verify_paymentsynchronousAvailableGET
verify_transfersynchronousAvailableGET
webhook_payment_completedwebhookAvailablePOST

Gotchas

block_customer

  • Blocking a customer is reversible — use unblock_customer to restore access. However, blocking does not cancel any payments already in progress at the time of the block.
  • The request body must be empty or omitted entirely. Sending a non-empty JSON body may cause unexpected behavior.
  • Calling block_customer on an already-blocked customer may return 200 without error. Do not rely on the response to determine whether the customer was previously unblocked.

cancel_payment

  • Only payments with status 'pending' can be canceled. Payments that are 'processing', 'complete', or 'failed' cannot be canceled and return a 422 error.
  • Cancellation is irreversible. Once canceled, the reference cannot be reused to restart the payment — create a new payment instead.
  • The Authorization header uses your public key with no 'Bearer ' prefix.

create_beneficiary

  • The Authorization header value is your public key with no prefix — do not add 'Bearer ' or 'Basic ' before it.
  • The channel slug must exactly match a Notch Pay supported channel (e.g. "cm.mtn", "cm.orange"). An invalid channel returns a 422 error without listing valid values.
  • account_number must be a valid phone number for mobile money channels — include the country code (e.g. +237XXXXXXXXX). Passing just a local number may fail silently or create an unusable beneficiary.
  • Store the returned beneficiary.id immediately — it is required to initiate transfers to this recipient and to delete the beneficiary later.
  • This endpoint requires your Notch Pay **private key** in the Authorization header, not the public key used for create_payment. Using a public key returns 406 Not Acceptable.
  • The channel slug determines the settlement currency: cm.* → XAF, ci.*/sn.* → XOF, ke.* → KES, ug.* → UGX, gh.* → GHS. The currency does not need to be specified at beneficiary creation but is fixed by the channel.

create_customer

  • At least one of email or phone is required. Submitting only name returns a 422 validation error — the Notch Pay docs make 'name' look mandatory but the API really enforces 'one of email/phone'.
  • The Authorization header must contain the public key directly as the token value — not prefixed with 'Bearer'. The format is exactly the key string.
  • Customer IDs returned by Notch Pay are opaque strings. Do not apply encodeURIComponent to these IDs when constructing path-based URLs — pass them as-is.
  • The address object uses 'address_line1' / 'address_line2' (and optional 'state'), not 'street'. Sending 'street' silently drops the field.

create_payment

  • Always verify payment status server-side by calling verify_payment (GET /payments/{reference}) before fulfilling an order. The callback redirect can be forged by the user.
  • The transaction object has no 'id' field — use 'reference' (format: trx.xxx) as the unique identifier. The 'sandbox' field is an integer (1 = sandbox, 0 = live), not a boolean.
  • Use a unique, idempotent reference per payment. Reusing a reference across different transactions will cause reconciliation errors.
  • The Authorization header value is your public key with no prefix — do not add 'Bearer ' before it.
  • For sandbox testing, use a public key containing 'test_' in its value. The same API endpoint is used for both test and live keys.
  • At least one of email, phone, or customer is required. Omitting all three returns a 422 error.
  • The currency must match the channel's country: XAF for cm.* channels (Cameroon), XOF for ci.*/sn.* (Côte d'Ivoire/Senegal), KES for ke.* (Kenya), UGX for ug.* (Uganda), GHS for gh.* (Ghana). A mismatch between currency and channel returns 422.

create_webhook

  • The webhook URL must be HTTPS. HTTP URLs are rejected with a 422 error.
  • Store the endpoint.id from the response — it is required to call update_webhook or delete_webhook later.
  • The events array must not be empty. Subscribing to no events is rejected. Only subscribe to event types your server actually handles.
  • The Authorization header uses your public key with no 'Bearer ' prefix.
  • This API registers the webhook configuration on the Notch Pay side. To validate incoming payloads, you must verify the X-Notch-Signature header on your receiving endpoint.
  • This endpoint requires your Notch Pay **private key** in the Authorization header, not the public key used for create_payment. Using a public key returns 406 Not Acceptable.

delete_beneficiary

  • The Authorization header value is your public key with no prefix — do not add 'Bearer ' before it.
  • Deletion is permanent and irreversible. There is no archive or soft-delete — once deleted, the beneficiary ID cannot be recovered.
  • A 404 response means either the beneficiary does not exist or it belongs to a different API key. Beneficiaries are scoped to the account that created them.
  • Do not URL-encode the beneficiary ID when inserting it into the path — pass it as-is.
  • This endpoint requires your Notch Pay **private key** in the Authorization header, not the public key used for create_payment. Using a public key returns 406 Not Acceptable.

delete_customer

  • Deletion is permanent and irreversible. There is no soft-delete or recycle bin — once deleted, the customer and all associated data cannot be recovered via the API.
  • A 404 is returned if the customer ID does not exist or no longer belongs to your account. Check for 404 separately from other error codes.
  • Deleting a customer does not automatically cancel or refund any associated payments. Resolve outstanding transactions before deleting the customer record.

delete_webhook

  • Deletion is immediate and irreversible. Notch Pay will stop delivering events to the endpoint right away.
  • The endpoint path parameter is the webhook endpoint ID, not its URL.
  • A 404 is returned if the endpoint ID does not exist or belongs to a different account.
  • The Authorization header uses your public key with no 'Bearer ' prefix.
  • This endpoint requires your Notch Pay **private key** in the Authorization header, not the public key used for create_payment. Using a public key returns 406 Not Acceptable.

get_balance

  • Use balance.available (not balance.total) to determine whether you have enough funds to initiate a transfer. total includes reserved and pending amounts that are not yet usable.
  • The response includes an environment field — verify it matches your expected mode ("live" vs "sandbox") to avoid acting on test data in production.
  • The Authorization header uses your public key with no 'Bearer ' prefix.
  • This endpoint requires your Notch Pay **private key** in the Authorization header, not the public key used for create_payment. Using a public key returns 406 Not Acceptable.

get_beneficiary

  • The Authorization header value is your public key with no prefix — do not add 'Bearer ' before it.
  • The id path parameter must be the Notch Pay beneficiary ID (from create_beneficiary response), not the account_number or phone number.
  • A 404 response means the beneficiary does not exist under the authenticated account — beneficiaries are scoped to the API key used to create them.
  • Do not URL-encode the beneficiary ID when inserting it into the path — pass it as-is.
  • This endpoint requires your Notch Pay **private key** in the Authorization header, not the public key used for create_payment. Using a public key returns 406 Not Acceptable.

get_customer

  • A 404 is returned when the customer ID does not exist or does not belong to your account. Always handle 404 explicitly rather than treating it as a generic error.
  • Customer IDs are opaque strings — pass them as-is into the URL path. Do not apply any encoding transformation to the ID.
  • The customer object does not include a 'blocked' or 'address' field — these are not returned by the API. Use block_customer / unblock_customer endpoints to manage block status.

get_webhook

  • The endpoint path parameter is the webhook endpoint ID, not its URL. Use the id field from create_webhook or list_webhooks.
  • A 404 is returned if the endpoint ID does not exist or belongs to a different account.
  • The Authorization header uses your public key with no 'Bearer ' prefix.
  • This endpoint requires your Notch Pay **private key** in the Authorization header, not the public key used for create_payment. Using a public key returns 406 Not Acceptable.

list_beneficiaries

  • The Authorization header value is your public key with no prefix — do not add 'Bearer ' before it.
  • Query parameters (limit, page, search) must be appended to the URL as a query string — they are not sent in the request body.
  • When current_page equals last_page, you have reached the end of the list. Requesting beyond last_page returns an empty items array rather than an error.
  • Pagination uses 'totals' (not 'total') and 'selected' (not 'per_page'). Reading the wrong field name silently returns undefined.
  • The totals field reflects the count at the time of the request; concurrent creates or deletes can cause inconsistencies when paginating large lists.
  • This endpoint requires your Notch Pay **private key** in the Authorization header, not the public key used for create_payment. Using a public key returns 406 Not Acceptable.

list_channels

  • Always filter by country and currency before displaying channels to users — not all channels are available in every country, and showing irrelevant options degrades UX.
  • Use min_amount and max_amount to validate the user's payment amount before initiating a transaction; submitting an out-of-range amount will result in a rejected payment.
  • Store the channel slug (not the id or name) when initiating a payment — it is the required identifier in subsequent API calls.
  • Cache the response — channel data changes rarely, but min/max amounts can be updated by Notch Pay without notice. A daily refresh is sufficient.
  • The Authorization header uses your public key with no 'Bearer ' prefix.

list_countries

  • This endpoint returns ALL 249 ISO 3166-1 countries — it is a reference/validation list, NOT a list of countries where Notch Pay operates. To find where Notch Pay actually has active channels, call GET /channels filtered by country instead.
  • Use the country code (not the country name) when filtering channels or initiating payments; the name is for display purposes only.
  • The Authorization header uses your public key with no 'Bearer ' prefix.

list_currencies

  • This endpoint returns ALL world currencies (ISO 4217 global list), NOT only currencies accepted by Notch Pay — it is a reference/validation endpoint. The actual currency used across all Notch Pay channels is XAF regardless of the customer's country.
  • Use the 'faction' field to format amounts correctly — XAF has faction: 0, so amounts must be integers. Sending 1000.50 for XAF will cause a validation error.
  • Use the currency code (not the name) when specifying currency in payment or channel API calls; the name field is for display purposes only.
  • The Authorization header uses your public key with no 'Bearer ' prefix.

list_customer_payment_methods

  • A 404 is returned if the customer ID does not exist. The customer ID must come from create_customer or list_customers — do not use a payment reference or beneficiary ID.
  • The items array may be empty if the customer has no saved payment methods — this is not an error. A customer only accumulates payment methods after completing at least one process_payment call.
  • The response schema for this endpoint was not live-tested (May 2026) — field names and structure are based on the OpenAPI spec and may differ from actual responses. Treat as draft.
  • The Authorization header uses your public key with no 'Bearer ' prefix.

list_customer_payments

  • A 404 is returned if the customer ID does not exist. Verify the customer exists via get_customer before listing their payments.
  • Pagination query parameters (limit, page) are passed as URL query string parameters. The customer ID is in the URL path, not the query string.
  • The payments array may be empty if the customer has no payments yet — this is not an error condition. Always check payments.length before iterating.
  • The top-level array is named 'payments' (not 'items') and pagination uses 'totals' (not 'total') and 'selected' (not 'per_page'). Reading the wrong field name silently returns undefined.

list_customers

  • Query parameters (limit, page, search) are passed as URL query string parameters, not in the request body. A GET request body is ignored.
  • Pagination is 1-based: the first page is page=1. Passing page=0 may return an empty result set or an error.
  • The 'totals' field (not 'total') returns the count of all matching customers. The 'selected' field (not 'per_page') indicates how many items were returned in this page. Using 'total' or 'per_page' will return undefined.
  • Pagination uses 'totals' (not 'total') and 'selected' (not 'per_page').

list_payments

  • All query parameters are optional — omitting all of them returns the full paginated list with the API default page size.
  • date_start and date_end must be ISO 8601 strings. Passing plain dates without a time component (e.g. "2024-01-01") may be rejected or interpreted differently by the API.
  • The Authorization header uses your public key with no 'Bearer ' prefix.
  • Iterate through pages using the page param and stop when current_page equals last_page to avoid requesting beyond the last page.
  • Pagination uses 'totals' (not 'total') and 'selected' (not 'per_page') — using the wrong field name will silently return undefined.

list_transfers

  • The Authorization header value is your public key with no prefix — do not add 'Bearer ' before it.
  • All transfer endpoints require an additional `X-Grant` header for enhanced security. Pass the grant token generated in your Notch Pay dashboard as `X-Grant: {token}`. Requests without this header return 401.
  • Pagination starts at page 1, not page 0. Passing page=0 may return an unexpected result or an error.
  • date_start and date_end must be ISO 8601 formatted strings. Passing plain date strings (e.g. '2024-01-01') without time and timezone may be rejected or silently ignored.
  • A transfer with status 'pending' is still in progress — do not treat it as completed. Only 'complete' status confirms a successful payout.
  • Pagination uses 'totals' (not 'total') and 'selected' (not 'per_page'). Reading the wrong field name silently returns undefined.
  • The totals field reflects the count across all pages, not just the current page. Use last_page to know when you have fetched all records.
  • This endpoint requires your Notch Pay **private key** in the Authorization header, not the public key used for create_payment. Using a public key returns 406 Not Acceptable.

list_webhooks

  • The Authorization header uses your public key with no 'Bearer ' prefix.
  • All query parameters are optional. Omitting them returns the full paginated list with the API default page size.
  • The top-level array is named 'endpoints' (not 'items'). Pagination uses 'totals' (not 'total') and 'selected' (not 'per_page'). Reading the wrong field name silently returns undefined.
  • Iterate through pages by incrementing the page param and stop when current_page equals last_page.
  • This endpoint requires your Notch Pay **private key** in the Authorization header, not the public key used for create_payment. Using a public key returns 406 Not Acceptable.

process_payment

  • process_payment must be called after create_payment — it requires the reference from the created transaction and will return 404 if the reference does not exist.
  • A 200 response with status "Accepted" means the payment was submitted to the mobile operator, not that it has been confirmed. Always use verify_payment afterwards to check the final status before fulfilling an order.
  • The phone number in data.phone must be in E.164 format (e.g. "+237670000000"). Passing a local format without the country code will cause the mobile operator to reject the request.
  • The channel slug is country-and-operator specific (e.g. "cm.mtn", "cm.orange"). Using a slug that does not match the customer's operator will result in a failed payment.
  • Calling process_payment on a transaction that is already 'complete', 'canceled', or 'failed' returns 422 with message 'Payment cannot be processed'.
  • The Authorization header uses your public key with no 'Bearer ' prefix.
  • The API also accepts PUT /payments/{reference} with the same body and response — this is a legacy alias. Prefer POST.

send_transfer

  • Transfers are not immediately settled — the initial status is "pending". Always call verify_transfer (GET /transfers/{reference}) to confirm completion before recording the disbursement as successful.
  • Either beneficiary (saved beneficiary ID) or the recipient+channel pair is required. Providing neither returns a 422 error.
  • All transfer endpoints require an additional `X-Grant` header for enhanced security. Generate this grant token in your Notch Pay dashboard and pass it as `X-Grant: {token}`. Requests without this header return 401.
  • Your server's IP address must be whitelisted in the Notch Pay dashboard before API transfers will be accepted. Requests from non-whitelisted IPs are rejected regardless of valid API credentials.
  • The Authorization header uses your public key with no 'Bearer ' prefix.
  • This endpoint requires your Notch Pay **private key** in the Authorization header, not the public key used for create_payment. Using a public key returns 406 Not Acceptable.
  • The currency must match the channel's country: XAF for cm.* channels (Cameroon), XOF for ci.*/sn.* (Côte d'Ivoire/Senegal), KES for ke.* (Kenya), UGX for ug.* (Uganda), GHS for gh.* (Ghana). A mismatch returns 422.

unblock_customer

  • Calling unblock_customer on a customer that is not currently blocked may return 200 without error. Use get_customer to check the blocked field before unblocking if idempotency matters.
  • The request body must be empty or omitted entirely. Sending a non-empty JSON body may cause unexpected behavior.
  • After unblocking, the customer can immediately initiate new payments. Ensure any fraud review or compliance checks are completed before calling unblock_customer.

update_customer

  • Notch Pay uses POST (not PATCH or PUT) for partial updates. Only the fields included in the body are updated; omitted fields retain their current values.
  • Sending an empty body or only the id field will return a 422 validation error — include at least one field to update in the request body.
  • Customer IDs are opaque strings — pass them as-is into the URL path without any encoding.
  • The address object uses 'address_line1' / 'address_line2' (and optional 'state'), not 'street'. Sending 'street' silently drops the field.

update_webhook

  • Updating the events field replaces the entire list — it is not a merge. To add a single event type, fetch the current list via get_webhook first, append the new event, then send the full updated array.
  • The endpoint path parameter is the webhook endpoint ID, not its URL.
  • At least one body field (url, events, or description) must be provided; sending an empty body may return a 422.
  • The new URL must be HTTPS. HTTP URLs are rejected.
  • The Authorization header uses your public key with no 'Bearer ' prefix.
  • This endpoint requires your Notch Pay **private key** in the Authorization header, not the public key used for create_payment. Using a public key returns 406 Not Acceptable.

verify_payment

  • Only fulfill an order when transaction.status is "complete" — "pending" means the user has not paid yet.
  • The reference must come from the transaction object returned by create_payment. Do not use values from the callback URL parameters, which can be tampered with.
  • Use your public key in the Authorization header with no 'Bearer ' prefix — same key as create_payment.

verify_transfer

  • Only record a disbursement as successful when transfer.status is "complete". "pending" means the mobile money network has not yet confirmed delivery.
  • All transfer endpoints require an additional `X-Grant` header for enhanced security. Pass the grant token generated in your Notch Pay dashboard as `X-Grant: {token}`. Requests without this header return 401.
  • The Authorization header uses your public key with no 'Bearer ' prefix.
  • This endpoint requires your Notch Pay **private key** in the Authorization header, not the public key used for create_payment. Using a public key returns 406 Not Acceptable.

webhook_payment_completed

  • Never fulfill an order based solely on receiving a webhook — always call verify_payment (GET /payments/{reference}) server-side to confirm the transaction status before acting.
  • Verify the signature using `crypto.timingSafeEqual` against the raw request body BEFORE parsing JSON. A simple string comparison (`===`) is vulnerable to timing attacks.
  • Webhook handlers must be idempotent — Notch Pay retries on non-2xx responses with increasing delays, which can cause duplicate event delivery. Store processed event IDs in your database and skip already-processed events.
  • The `payment.processing` status means the payment is in progress on the mobile money network — do not fulfill the order yet. Only act on `payment.complete`.
  • Register your webhook URL in the Notch Pay dashboard and select the events to subscribe to (e.g. payment.complete). The endpoint URL must be HTTPS.

Details

Category
payment
Sandbox
Yes