Quick start
Integration flow
- Create a payment app → get a Payment ID and Secret Key
- User places an order → call the initiate payment API
- Redirect to payment → the user logs in on NodeLoc and pays
- Receive the callback → the browser redirects to your callback URL
- Query status (optional) → actively query the payment result
- Transfer to other users (optional) → call the transfer API to send the applicant’s points to a specified user
Create a payment app
Visit the management page
Creating a payment app requires Silver member (TL1) or above, and new apps must be approved by an admin before use.
Fill in the app info
Save your keys
After creation, the following will be displayed:- Payment ID:
pay_xxxxxxxxxxxxxxxxxx - Secret Key:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Initiate payment
API endpoint
Request parameters
Signature algorithm
- Prepare the parameters:
amount,description,order_id - Sort by key name: arrange the parameters in alphabetical order
- Build the string: in the format
key1=value1&key2=value2&key3=value3 - Compute the key:
token_hash = SHA256(your_token)// your token is in thetk_xxxformat - Generate the signature:
signature = HMAC-SHA256(token_hash, param_string)
your_tokenis the token obtained when the app was created (format:tk_xxx...)token_hashis the SHA256 hash of the token (64-character hex string)- Do not use the token directly as the HMAC key!
Response data
On success:Redirect to payment
Redirect the user to thepayment_url in the response. The user will:
- Be automatically redirected to the login page (if not logged in)
- Return to the payment page after logging in
- Confirm the order and complete payment
- Be redirected to your callback URL after a successful payment
Handle the callback
Callback method
After a successful payment, the user’s browser redirects to the callback URL you configured, with all parameters passed as a query string.Callback parameters (URL query parameters)
Callback URL example
Verify the signature
Verification steps:- Extract the signature parameter: get
signaturefrom the URL - Extract the other parameters: all parameters except
signatureitself - Sort by key name: arrange in alphabetical order
- Build the string: in the format
key1=value1&key2=value2... - Compute the signature:
HMAC-SHA256(secret_key, param_string) - Compare signatures: the computed signature must exactly match the received one
Process the order
After the signature verifies:- ✅ Check idempotency: make sure the order hasn’t already been processed
- ✅ Verify the amount: confirm
amountmatches the order amount - ✅ Update the order status: mark it as paid
- ✅ Execute business logic: deliver goods, activate services, etc.
- ✅ Show a confirmation page: display a payment success message to the user
Query status
If the callback fails or you need to actively confirm a payment status, use the query API.API endpoint
Request parameters
Signature algorithm
Same as initiating payment:- Parameters:
transaction_id - Build the string:
transaction_id=txn_xxx - Signature:
HMAC-SHA256(secret_key, param_string)
Response data
Transaction statuses
Recommended use cases
- Scheduled jobs checking the status of unpaid orders
- Users actively querying order status
- A fallback after callback failure
User transfer
Transfer points from the current payment app’s applicant to a specified NodeLoc user. Commonly used for external sites distributing rewards, prize draws, commission payouts, and similar scenarios.API endpoint
Request parameters
Fee rules
The fee is calculated automatically based on the applicant’s trust level (Trust Level), with rates following thediscourse-points-service settings:
The TL-specific
points_transfer_min_amount_tl{0..4} / points_transfer_max_amount_tl{0..4} limits also apply.
Formula:
Signature algorithm
- Prepare the parameters:
to_user_id,to_username,amount,order_id - Sort by key name in alphabetical order
- Build the string:
key1=value1&key2=value2&... - Compute the signature:
HMAC-SHA256(token_hash, param_string)token_hash = SHA256(your_token), same as initiating payment
Idempotency
- Transfers with the same
payment_id+order_idare treated as the same transfer. - If the order is already
completed, the original result is returned directly (no double charge). - If the order exists but its status is not
completed, the request is rejected.
Response data
On success (200 OK):
400 / 401):
Common errors
Recommended use cases
- External sites distributing rewards to NodeLoc users
- Prize draws and event payouts
- Commission and revenue-share settlement
- Returning points to a specified user after acquiring them
Security recommendations
1. Protect your keys
- ❌ Don’t hardcode them in code
- ✅ Use environment variables or a key management service
2. Use HTTPS
- ✅ Production environments must use HTTPS
- ✅ The callback URL must be an HTTPS address
3. Verify signatures
- ✅ Verify the signature on all callback requests
- ✅ Reject requests when the signature doesn’t match
4. Prevent duplicate processing
- ✅ Check order status to prevent duplicate processing
- ✅ Use a unique
order_idfor transfers to guarantee idempotency - ✅ Use database transactions to ensure atomicity
5. Verify amounts
- ✅ Verify that the callback amount matches the order amount
- ✅ Log and raise an alert when amounts don’t match
6. Verify the recipient
- ✅ Before transferring, confirm that
to_user_idandto_usernamecome from a trusted source - ✅ Never transfer based on username alone — always validate the ID as well
7. Logging
- ✅ Log all payment/transfer-related operations
- ✅ Log all callback requests (including those that fail signature verification)
FAQ
Q: Signature verification fails?
Q: Signature verification fails?
Check the following:
- Are the parameters sorted by key name in alphabetical order?
- Is the parameter string in the
key=value&key=valueformat? - Is the Secret Key correct?
- Did you exclude the
signatureparameter itself when verifying? - Is the character encoding consistent (UTF-8)?
Q: Callback not received?
Q: Callback not received?
Possible causes:
- The callback URL is configured incorrectly
- The user closed the browser window
- A network issue caused the redirect to fail
Q: How do I test?
Q: How do I test?
Testing in a development environment:
- Use a tool like ngrok to expose your local server
- Create a test app on NodeLoc
- Set the callback URL to the ngrok address
- Create small-amount orders for testing
Q: Are refunds supported?
Q: Are refunds supported?
Automatic refunds are not currently supported; contact an admin for manual handling.
Q: Do orders expire?
Q: Do orders expire?
Yes. Orders expire automatically after 30 minutes if unpaid.
Q: Can I transfer to any user?
Q: Can I transfer to any user?
Yes, as long as the
to_user_id and to_username you provide are both correct and point to the same NodeLoc user. The sender is fixed as the user who applied for the Payment app — you cannot use this API to transfer other people’s points.Q: What is the transfer fee?
Q: What is the transfer fee?
The fee is calculated based on the applicant’s current trust level (TL0–TL4), corresponding to the site settings
points_transfer_fee_rate_tl0 through points_transfer_fee_rate_tl4. The applicant is charged amount + fee; the recipient receives amount.API reference
Initiate payment
- URL:
POST /payment/pay/:payment_id/process - Authentication: signature verification
- Request:
amount,description,order_id,signature - Response:
payment_url,transaction_id,status,amount
Query status
- URL:
POST /payment/query/:payment_id - Authentication: signature verification
- Request:
transaction_id,signature - Response: full transaction info (see above)
User transfer
- URL:
POST /payment/transfer/:payment_id - Authentication: signature verification
- Sender: fixed as the Payment app applicant
- Request:
to_user_id,to_username,amount,order_id,signature - Response:
transaction_id,order_id,status,amount,fee,total_deduction,from_user_id,from_username,to_user_id,to_username,paid_at
Payment callback
- Method: browser GET redirect
- URL: the
callback_urlyou configured - Authentication: signature verification
- Parameters:
transaction_id,external_reference,amount,platform_fee,merchant_points,status,paid_at,signature
EPay-compatible API (V2, RSA signatures)
If your system already integrates with an EPay (易支付) gateway, there is no need to rewrite it against the HMAC API above: NodeLoc serves the EPay V2 protocol directly — swap the gateway URL for NodeLoc and the currency becomes points. Anything that supports EPay (shops, card sellers, WHMCS modules, …) works as is.Integration parameters
Signing follows EPay exactly: take every non-empty parameter except
sign and sign_type, sort by name in ASCII order, join as k1=v1&k2=v2, sign with the merchant private key (SHA256WithRSA) and base64-encode. NodeLoc signs its responses and callbacks the same way with the platform private key; verify them with the platform public key. Every request carries a 10-digit timestamp in seconds; more than 5 minutes of drift is refused.
Endpoints
Parameter and response names match the EPay documentation, with these differences:
moneyis an amount in your currency (say"9.90"); NodeLoc converts it to points at the app’s rate (at the default 100 points per unit, 9.90 becomes 990 points), rounded to a whole number, and refuses anything under one point. Callbacks and queries echo themoneyyou sent; the balance and takings in merchant info are converted back the same way. The platform fee comes out of the points the merchant receives.typeis echoed back as sent (alipay,wxpayor empty);methodanddeviceare ignored andpay_typeis alwaysjump.- Re-creating the same
out_trade_noreturns the sametrade_no; creating one that is already paid answerscode: 1. buyerin a query is the paying user’s NodeLoc username.
V1 legacy API (MD5 signatures)
Many programs (card sellers, shops, WHMCS gateway modules, …) speak EPay V1:submit.php / mapi.php / api.php, signed with the merchant KEY by MD5 and without timestamps. NodeLoc serves that too, at the same gateway URL https://www.nodeloc.com/payment/api; the key is the “Merchant KEY (EPay V1 / MD5)” on the app card and can be reset at any time.
MD5 signing: drop
sign, sign_type and empty values, sort the rest by name in ASCII order, join as a=b&c=d (values not URL-encoded), append the merchant key and take the lowercase MD5. Notify and return callbacks for V1 orders carry pid, trade_no, out_trade_no, type, name, money, trade_status, param, sign, sign_type=MD5, signed the same way; answer the notify with success.
One application can use V1 and V2 side by side: a request with sign_type=RSA is verified as V2, anything else as V1 MD5.
Payment notification
Once the buyer has paid:- Asynchronous notify: NodeLoc sends a GET to your
notify_urlwithpid,trade_no,out_trade_no,api_trade_no,type,trade_status=TRADE_SUCCESS,addtime,endtime,name,money,param,buyer,timestamp,sign,sign_type. After verifying the signature your server must answer with the stringsuccess; otherwise NodeLoc retries after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours. - Synchronous return: the buyer’s browser is sent back to
return_urlwith the same parameters.
sign and check that trade_status is TRADE_SUCCESS; fields may be added to callbacks in future, so include every non-empty parameter when verifying.
Happy integrating! 🚀
