Search all sections, code examples and FAQ answers. Enter at least 2 characters.
Start with the full payment flow
Complete the common setup, create a payment, configure IPN, test the full flow, then choose how incoming payments should work for your business.
For developers
Use API snippets and IPN validation examples to connect your backend.
For product teams
Choose the right payment logic: fixed-price payments, balance top-ups, or payouts.
For launch
Use dashboard settings and the go-live checklist before production.
1. Set up your account
Configure the account settings required before creating and processing payments.
Generate API key
Your API key is generated automatically and is required for API integration.
Set base currency
Base currency is the currency in which the price is displayed.
Generate IPN secret key
Generate and save the IPN Secret key in Payment Settings tab at the Dashboard.
Whitelist NOWPayments IP addresses
Make sure firewall software on your server allows NOWPayments requests. It may be required to whitelist NOWPayments IP addresses on your side. For assistance contact support@nowpayments.io.
Whitelist settings
Whitelist your IP and all wallet addresses, or request to disable these safety measures from your Dashboard. If you have both IPv-4 and IPv-6 addresses, whitelist both.
2. Create your first payment
Use the Create Payment request and include your IPN callback URL.
Create Payment API request
Insert your URL address where you want to get callbacks in the create_payment request. The parameter name is ipn_callback_url.
import requests
import json
url = "https://api.nowpayments.io/v1/payment"
payload = json.dumps({
"price_amount": 3999.5,
"price_currency": "usd",
"pay_currency": "btc",
"ipn_callback_url": "https://example.com",
"order_id": "RGDBP-21314",
"order_description": "Apple Macbook Pro 2019 x 1"
})
headers = {
'x-api-key': '{{api-key}}',
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
Payment address
In response, you get pay_address. This is the deposit address where the user should send the money.
3. Set up IPN
IPN sends payment updates to the callback URL specified in your Create Payment request.
x-nowpayments-sig with your IPN secret.IPN flow
| Requirement | Details |
|---|---|
| Endpoint | Set up an endpoint which can receive POST requests from NOWPayments server. |
| Header | The POST request contains the x-nowpayments-sig parameter in the header. |
| Body | The body is similar to a get payment status response body. |
| Before production | Make a test request to this endpoint to ensure it works properly. |
Server configuration
| Check | Requirement |
|---|---|
| Firewall | A firewall should not prevent NOWPayments POST requests from passing through to the address specified as the IPN callback URL. There can be more than one firewall in the system. |
| Notification server IPs | Whitelist 51.89.194.21, 51.75.77.69, 138.201.172.58, 65.21.158.36. IP whitelisting is an additional safeguard; it never replaces signature validation. |
| Endpoint access | Endpoint must not be closed by authorisation, or other such requirements. |
| Response time | The endpoint shall respond within 3000 ms. |
| Hosting / Cloudflare | NOWPayments does not recommend shared-based hosting services. Be extremely careful when setting up Cloudflare if it is an external firewall. |
Rate limits
| Endpoint | Limit | If exceeded |
|---|---|---|
| GET estimate | 7 requests per second from one outgoing IP address | 429 error code |
| POST payment | 3 requests per second from one outgoing IP address | 429 error code |
| GET /payment/:id | 10 requests per second | 429 error code |
Signature validation steps
Reject missing or empty signatures
If x-nowpayments-sig is missing or empty, reject the request and stop processing. Never run validation only when the header is present: omitting it would bypass that check.
Sort the POST request by keys
Convert it to string using JSON.stringify(params, Object.keys(params).sort()) or the same function.
Sign the string
Sign a string with an IPN-secret key with HMAC and sha-512 key.
Compare signatures
Compare the expected signature with the x-nowpayments-sig request header using constant-time comparison: crypto.timingSafeEqual (Node.js), hash_equals (PHP), or hmac.compare_digest (Python). Do not use ==. Reject a mismatch and stop processing.
IPN validation examples
Run these checks on your backend. If validation returns false, reject the callback (for example, with HTTP 401) and return immediately. Do not update an order or balance. Only process a verified callback after checking its payment status, amount and currency.
Webhook example: Payments
{
"payment_id":123456789,
"parent_payment_id":987654321,
"invoice_id":null,
"payment_status":"finished",
"pay_address":"address",
"payin_extra_id":null,
"price_amount":1,
"price_currency":"usd",
"pay_amount":15,
"actually_paid":15,
"actually_paid_at_fiat":0,
"pay_currency":"trx",
"order_id":null,
"order_description":null,
"purchase_id":"123456789",
"outcome_amount":14.8106,
"outcome_currency":"trx",
"payment_extra_ids":null,
"fee": {
"currency":"btc",
"depositFee":0.09853637216235617,
"withdrawalFee":0,
"serviceFee":0
}
}| Parameter | Use |
|---|---|
| payment_status | Use payment status when processing payment updates. |
| outcome_amount | Check the actual amount received. |
| outcome_currency | Check the currency actually received. |
| x-nowpayments-sig | Validate the callback signature. |
| fee | Review fee details when present in the webhook body. |
const crypto = require('node:crypto');
function sortObject(obj) {
return Object.keys(obj).sort().reduce(
(result, key) => {
result[key] = (obj[key] && typeof obj[key] === 'object') ? sortObject(obj[key]) : obj[key]
return result
},
{}
)
}
function verifyIpnSignature(params, receivedSignature, notificationsKey) {
// A missing, empty or malformed header must fail validation.
if (typeof receivedSignature !== 'string' ||
!/^[a-f0-9]{128}$/i.test(receivedSignature)) return false;
const expected = crypto.createHmac('sha512', notificationsKey)
.update(JSON.stringify(sortObject(params))).digest();
const received = Buffer.from(receivedSignature, 'hex');
return received.length === expected.length &&
crypto.timingSafeEqual(expected, received);
}
// Pass the parsed JSON body, x-nowpayments-sig header and IPN secret.
// If verifyIpnSignature(...) is false, reject and stop processing.
function tksort(&$array)
{
ksort($array);
foreach (array_keys($array) as $k) {
if (is_array($array[$k])) {
tksort($array[$k]);
}
}
}
function check_ipn_request_is_valid($ipn_secret)
{
$received_hmac = $_SERVER['HTTP_X_NOWPAYMENTS_SIG'] ?? '';
if (!is_string($received_hmac) ||
!preg_match('/\A[a-f0-9]{128}\z/i', $received_hmac)) {
return false;
}
$request_json = file_get_contents('php://input');
if ($request_json === false || $request_json === '') return false;
$request_data = json_decode($request_json, true);
if (json_last_error() !== JSON_ERROR_NONE || !is_array($request_data)) {
return false;
}
tksort($request_data);
$sorted_request_json = json_encode($request_data, JSON_UNESCAPED_SLASHES);
if ($sorted_request_json === false) return false;
$hmac = hash_hmac('sha512', $sorted_request_json, trim($ipn_secret));
return hash_equals($hmac, strtolower($received_hmac));
}
// If check_ipn_request_is_valid($ipn_secret) is false,
// reject the callback and return before updating an order or balance.
import json
import hmac
import hashlib
import re
def np_signature_check(np_secret_key, np_x_signature, message):
# A missing, empty or malformed header must fail validation.
if not isinstance(np_x_signature, str) or not re.fullmatch(
r'[a-fA-F0-9]{128}', np_x_signature
):
return False
sorted_msg = json.dumps(message, separators=(',', ':'), sort_keys=True)
signature = hmac.new(
str(np_secret_key).encode(),
sorted_msg.encode(),
hashlib.sha512
).hexdigest()
return hmac.compare_digest(signature, np_x_signature.lower())
# If np_signature_check(...) is False, reject and stop processing.
4. Test the full payment flow
Create a payment, receive payment status updates through IPN, and verify the final payment data before granting goods or crediting a balance.
Test checklist
Payment statuses
| Status | Meaning |
|---|---|
waiting | Waiting for the customer to send the payment. |
confirming | The transaction is being processed on the blockchain. |
confirmed | The process is confirmed by the blockchain. |
sending | The funds are being sent to your personal address or custody balance. |
finished | The funds have reached your personal address or custody balance and the payment is finished. |
partially_paid | A completed payment. This status means you've already received your funds, but the amount sent by your customer was less than the settled price. |
failed | The payment was not completed due to an error. |
expired | The user did not send funds within the payment window. |
confirming or confirmed statuses.5. Choose incoming payment logic
Select how incoming payments should be handled. Only the selected logic is shown.
Fixed-price payments
User pays for a product or service with a fixed price.
Balance top-ups
User deposits funds to credit an internal balance.
6. Configure dashboard features
Use dashboard features to solve payment processing cases before going live.
Repeated Payments
Set the default payment status for repeated payments made by your user to the same deposit address.
Wrong-asset deposits auto processing
Process or do not process wrong-asset deposits automatically. Payment status can be set to Partially Paid or Finished.
Payment Covering
Set the percentage of the payment that needs to be paid for it to be considered completed.
Network Fee Optimization
Among your wallets, a payment picks the most suitable one and undergoes a conversion resulting in the lowest network fee in total.
Payment Markup
Allows setting a markup percentage over the initial price, from 0% to 10%.
My Team
Add team members and customize their access to the main account. Team members need to have a NOWPayments account.
7. Send payouts
Choose how you want to send funds: to users by email with ChangeNOW Pro, or to crypto wallets through payouts.
ChangeNOW Pro Payouts
Payout to email with $0 fees and instant delivery.
Crypto Payouts
Send payouts from Custody to crypto wallet addresses.
Subscriptions
Create plans and customer subscriptions through the NOWPayments API. Customers choose how to pay on the invoice; your backend tracks payments and renewals through NOWPayments.
Complete account setup
Register or sign in, generate your API key, and follow the existing Setup and IPN steps in this guide. Use the authentication headers specified for each recurring API method; keep credentials on your backend.
merchant_name; use an interval_day of 1, 7, 30, 31 or 365 days.Create a subscription plan
POST /v1/subscriptions/plans — Create plan. Set the title, billing interval, amount and currency; configure notification and redirect URLs as described in the plan documentation. Save the returned plan ID.
| Additional request field | Use in Create plan / Update plan |
|---|---|
grace_period | 0–5 days, no greater than interval_day. The subscription stays active during this period if the first payment attempt fails. |
merchant_name | Your company name; can also be set as Company name in the merchant account. |
Example plan body — illustrative values
Send to https://api.nowpayments.io/v1/subscriptions/plans with the headers required by the documentation.
{
"title": "Monthly plan",
"interval_day": 30,
"amount": 49,
"currency": "usd",
"ipn_callback_url": "https://your-domain.example/subscription-ipn",
"grace_period": 3,
"merchant_name": "Your company"
}Plan responses also include grace_period and Merchant_name (the merchant company name).
Create the customer's subscription
POST /v1/subscriptions — Create an email subscription. Required fields: subscription_plan_id and email.
{
"subscription_plan_id": 76215585,
"email": "customer@example.com"
}Save the returned subscription ID and status, subscriber data, invoice_url and payment_type. Send the customer to invoice_url. No ChangeNOW Pro selection parameter is needed: the customer chooses on the invoice.
Customer pays on the invoice
The invoice offers standard crypto payment and, when available, ChangeNOW Pro. With ChangeNOW Pro, funds come from the customer's CHN Pro balance.
Invoice illustration · not a product screenshot
Your company
Monthly plan · illustrative amount
49 USD
From your CHN Pro balance · when available
Payment is completed on the actual invoice_url page.
How the payment type changes renewals
one-timeThe customer makes a single payment. It does not authorize future automatic charges; renewal requires another payment.
auto-renewThe customer authorizes recurring charges. Renewals charge the CHN Pro balance according to the plan, subject to permission and sufficient funds.
Read payment_type through the API to determine the subscription's payment mode. Invoice creation alone does not authorize auto-renewal.
Monitor payments and subscription status
Use Get many recurring payments and Get one recurring payment. Both return invoice_url and payment_type (one-time or auto-renew) alongside subscription data.
Continue using the NOWPayments API and the notifications configured in your integration. Update customer access after confirmed payment or renewal; handle failed attempts and the configured grace period.
Cancel a subscription
Call DELETE /v1/subscriptions/{sub_id} with the saved subscription ID. Use the existing cancellation method and check its result.
API methods at a glance
Base URL: https://api.nowpayments.io. Replace {plan_id} and {sub_id} with the saved IDs. See Recurring Payments API for each method's authentication, complete parameters and response schema.
| Method name | Request |
|---|---|
| Create plan | POST /v1/subscriptions/plans |
| Update plan | PATCH /v1/subscriptions/plans/{plan_id} |
| Get one plan | GET /v1/subscriptions/plans/{plan_id} |
| Get all plans | GET /v1/subscriptions/plans |
| Create an email subscription | POST /v1/subscriptions |
| Get many recurring payments | GET /v1/subscriptions |
| Get one recurring payment | GET /v1/subscriptions/{sub_id} |
| Cancel subscription | DELETE /v1/subscriptions/{sub_id} |
All four plan methods return the added plan fields. grace_period and merchant_name can be set through Create plan and Update plan.
8. Go live checklist
Complete the checklist before going live.
finished, unless your selected scenario uses partially_paid for balance top-ups.FAQ & troubleshooting
Short answers for setup, payments, callbacks, payouts and subscriptions. Use the search above to find words inside every answer, including closed questions.
Do I need a separate ChangeNOW Pro API integration?
No. Create subscriptions and email payouts through NOWPayments. For subscriptions, the customer selects ChangeNOW Pro on the invoice when it is available.
Where do I get my API key?
Sign in to the NOWPayments dashboard and open API keys in merchant settings. Keep the key on your backend, never in public frontend code. Follow the Setup section for the remaining account settings.
Open setup guide →When do I need Custody?
Enable Custody for payouts from your merchant balance and for the ChangeNOW Pro subscription flow. Complete the related whitelist and account settings before testing.
Open payouts guide →Can I use a hosted invoice instead of building checkout?
Yes. The guide supports invoices as an alternative to API payments. For subscriptions, creation returns invoice_url: send the customer to that page to pay.
Open create payment guide →The payment is confirmed. Can I deliver the order?
Do not deliver at confirming or confirmed. For fixed-price orders, wait for finished and check outcome_amount and outcome_currency against the expected price. Creating an invoice is not payment confirmation.
What should I do with an underpayment?
For fixed-price orders, do not deliver automatically unless your approved payment logic allows it. For balance top-ups, credit the actual outcome_amount in outcome_currency after finished or partially_paid. Payment Covering can be configured for your accepted threshold.
Open payment logic guide →How do I choose fixed-price payments or balance top-ups?
Choose fixed-price logic for a specific order or service price. Choose balance top-ups when a deposit credits the user’s internal balance. The delivery trigger and treatment of partially_paid differ; select your scenario in Payment logic.
Open payment logic guide →What happens if a customer sends another payment to the same address?
Repeated Payments sets the default status for subsequent payments to that deposit address. The guide recommends Partially Paid for fixed-price flows and Finished for balance top-ups. This setting is not an authorization for automatic subscription charges.
Open dashboard features guide →What does Payment Covering do?
It sets the payment percentage you accept as completed. Choose the threshold for your business model and continue checking final payment data before delivering an order or crediting a balance.
Open dashboard features guide →What is IPN and where do I configure it?
IPN sends payment updates to your backend. Include ipn_callback_url in the payment request, generate your IPN secret in the dashboard, and implement the receiving endpoint described in the IPN section.
How do I check that a callback is authentic?
Anyone can send a request to your callback URL. Reject missing, empty or invalid x-nowpayments-sig headers. Verify the signature with your IPN secret using constant-time comparison; IP whitelisting does not replace this check. Then check the payment status, outcome_amount and outcome_currency before updating the order or user balance.
Open ipn guide →Why am I not receiving payment notifications?
Check that ipn_callback_url points to the correct reachable endpoint and your server accepts POST requests. Review firewall settings and whitelist NOWPayments IP addresses where required. Contact support@nowpayments.io for help with the IP list.
Open ipn guide →What do I test before going live?
Create a payment, receive and validate its callback, verify the final status and settlement amount/currency, and check delivery or balance crediting. Complete the Go live checklist; test your selected payout and subscription scenarios if you use them.
Open go live guide →Can I pay a customer by email without collecting a wallet address?
Yes. Use ChangeNOW Pro payouts. Set address to the recipient’s email in the payout request. A ChangeNOW Pro account is created for a new recipient; they receive an email to access their funds.
Do email payouts and external crypto payouts use different endpoints?
No. Both use POST /v1/payout. For ChangeNOW Pro payouts, the address field contains an email. For an external crypto payout, it contains the recipient’s wallet address. Follow the correct configuration and verification steps for your route.
Open payouts guide →Where do the $0 payout fees apply?
The $0 fee and instant-delivery claim in this guide applies to payouts to ChangeNOW Pro by email. Do not apply that claim to external wallet transfers, conversions or fiat operations.
Open payouts guide →What should I check if a payout cannot be created or verified?
Check Custody balance, IP whitelist, recipient details and the authentication required by the method. For external crypto payouts, review wallet whitelist settings. Complete the documented 2FA verification step and inspect the payout status.
Open payouts guide →What must be enabled for ChangeNOW Pro subscriptions?
Enable Custody and specify your Company name in the merchant account or pass merchant_name. Supported interval_day values for this flow are 1, 7, 30, 31 and 365 days.
Open subscriptions guide →How do I create a customer subscription?
Create a plan with POST /v1/subscriptions/plans and save its ID. Then call POST /v1/subscriptions with subscription_plan_id and email. Save the subscription ID and send the customer to the returned invoice_url.
Should I send a parameter to select ChangeNOW Pro?
No. The customer selects an available payment method on the invoice page. You do not need a separate ChangeNOW Pro selection parameter when creating the subscription.
Open subscriptions guide →What is the difference between one-time and auto-renew?
one-time pays once and does not authorize future automatic charges. auto-renew allows recurring charges after the customer gives permission, according to the plan and subject to sufficient CHN Pro balance. Read payment_type through the NOWPayments API.
Open subscriptions guide →What happens if a renewal payment attempt fails?
Use the subscription status and configured notifications to handle the failed attempt. grace_period can keep the subscription active for 0–5 days after the first failed payment attempt; it must not exceed interval_day. Do not treat auto-renew as a guarantee of successful payment.
Open subscriptions guide →How do I monitor or cancel a subscription?
Use GET /v1/subscriptions for the list and GET /v1/subscriptions/{sub_id} for one subscription. Read status, invoice_url and payment_type. To cancel, call DELETE /v1/subscriptions/{sub_id} with the saved subscription ID and check the result.
Open subscriptions guide →Is my subscription active as soon as I receive invoice_url?
No. invoice_url means that a payment page has been created. Confirm payment and subscription status through NOWPayments before granting access, and update access after confirmed renewals.
Open subscriptions guide →