Step 1 of 8

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.

Set up account
Create payment
Set up IPN
Test flow
Choose logic
Payouts

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.

1

Generate API key

Your API key is generated automatically and is required for API integration.

2

Set base currency

Base currency is the currency in which the price is displayed.

Dashboard > Settings > Payments > Payment details > Base currencyOpen Payment details
3

Generate IPN secret key

Generate and save the IPN Secret key in Payment Settings tab at the Dashboard.

Dashboard > Settings > Payments > Instant payment notificationsOpen IPN settings
4

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. Don't forget to add IPv-4 and IPv-6 addresses, if you have both. It's important.

2. Create your first payment

Use the Create Payment request and include your IPN callback URL.

You can also accept payments using invoices instead of API payments.

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.

API documentation snippet
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://nowpayments.io",
  "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.

IPN flow

Status changes
POST to callback URL
x-nowpayments-sig
Validate signature
RequirementDetails
EndpointSet up an endpoint which can receive POST requests from NOWPayments server.
HeaderThe POST request contains the x-nowpayments-sig parameter in the header.
BodyThe body is similar to a get payment status response body.
Before productionMake a test request to this endpoint to ensure it works properly.
We can't send POST requests to localhost. Do not use localhost (127.0.0.1) for IPN callbacks.

Server configuration

CheckRequirement
FirewallA 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 IPsWhitelist 51.89.194.21, 51.75.77.69, 138.201.172.58, 65.21.158.36.
Endpoint accessEndpoint must not be closed by authorisation, or other such requirements.
Response timeThe endpoint shall respond within 3000 ms.
Hosting / CloudflareNOWPayments does not recommend shared-based hosting services. Be extremely careful when setting up Cloudflare if it is an external firewall.

Rate limits

EndpointLimitIf exceeded
GET estimate7 requests per second from one outgoing IP address429 error code
POST payment3 requests per second from one outgoing IP address429 error code
GET /payment/:id10 requests per second429 error code

Signature validation steps

1

Sort the POST request by keys

Convert it to string using JSON.stringify(params, Object.keys(params).sort()) or the same function.

2

Sign the string

Sign a string with an IPN-secret key with HMAC and sha-512 key.

3

Compare signatures

Compare the signed string with x-nowpayments-sig, stored in the callback request header.

IPN validation examples

Webhook example: Payments

Payments webhook example
{
"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
}
}
ParameterUse
payment_statusUse payment status when processing payment updates.
outcome_amountCheck the actual amount received.
outcome_currencyCheck the currency actually received.
x-nowpayments-sigValidate the callback signature.
feeReview fee details when present in the webhook body.
Node.JS signed string example
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
    },
    {}
  )
}
const hmac = crypto.createHmac('sha512', notificationsKey);
hmac.update(JSON.stringify(sortObject(params)));
const signature = hmac.digest('hex');
PHP signed strings comparison example
function tksort(&$array)
  {
  ksort($array);
  foreach(array_keys($array) as $k)
    {
    if(gettype($array[$k])=="array")
      {
      tksort($array[$k]);
      }
    }
  }
function check_ipn_request_is_valid()
    {
        $error_msg = "Unknown error";
        $auth_ok = false;
        $request_data = null;
        if (isset($_SERVER['HTTP_X_NOWPAYMENTS_SIG']) && !empty($_SERVER['HTTP_X_NOWPAYMENTS_SIG'])) {
            $recived_hmac = $_SERVER['HTTP_X_NOWPAYMENTS_SIG'];
            $request_json = file_get_contents('php://input');
            $request_data = json_decode($request_json, true);
            tksort($request_data);
            $sorted_request_json = json_encode($request_data, JSON_UNESCAPED_SLASHES);
            if ($request_json !== false && !empty($request_json)) {
                $hmac = hash_hmac("sha512", $sorted_request_json, trim($this->ipn_secret));
                if ($hmac == $recived_hmac) {
                    $auth_ok = true;
                } else {
                    $error_msg = 'HMAC signature does not match';
                }
            } else {
                $error_msg = 'Error reading POST data';
            }
        } else {
            $error_msg = 'No HMAC signature sent.';
        }
    }
Python signed signatures comparison example
import json 
import hmac 
import hashlib

def np_signature_check(np_secret_key, np_x_signature, message):
    sorted_msg = json.dumps(message, separators=(',', ':'), sort_keys=True)
    digest = hmac.new(
    str(np_secret_key).encode(), 
    f'{sorted_msg}'.encode(),
    hashlib.sha512)
    signature = digest.hexdigest()
    if signature == np_x_signature:
        return
    else:
        print("HMAC signature does not match")

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

StatusMeaning
waitingWaiting for the customer to send the payment.
confirmingThe transaction is being processed on the blockchain.
confirmedThe process is confirmed by the blockchain.
sendingThe funds are being sent to your personal address or custody balance.
finishedThe funds have reached your personal address or custody balance and the payment is finished.
partially_paidA completed payment. This status means you've already received your funds, but the amount sent by your customer was less than the settled price.
failedThe payment was not completed due to an error.
expiredThe user did not send funds within the payment window.
Do not grant goods or services when the payment is in 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.

E-commerceServicesFixed-price items

Balance top-ups

User deposits funds to credit an internal balance.

CasinoBalance top-ups

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.

Partially Paid / FinishedOpen Payment details

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.

Dashboard > Settings > Account > My Team

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.

Email-based payoutsCSV upload$0 fees

Crypto Payouts

Send payouts from Custody to crypto wallet addresses.

Mass PayoutsAPICustody

8. Go live checklist

Complete the checklist before going live.

Do not recommend granting goods and services with any status other than finished, unless your selected scenario uses partially_paid for balance top-ups.