Docs
Accept cryptocurrency payments directly through the 1nodes API. Create payments, redirect customers to checkout, receive payment notifications through webhooks, and securely verify completed transactions.
Introduction
The 1nodes API allows merchants and developers to integrate cryptocurrency payments directly into their own applications without using a pre-built plugin.
The integration consists of four main stages: creating a payment, redirecting the customer to checkout, receiving a webhook notification, and verifying the payment on your server.
Authentication
API requests are authenticated using your Merchant Key. Send the key using the HTTP Authorization header.
Authorization: Bearer YOUR_MERCHANT_KEY
🔵Merchant Key: Used to authenticate requests sent from your application to the 1nodes API.
🔴Secret Key: Used for webhook signature verification. Never expose it to the browser.
Create Payment
Create a new payment from your backend server. Authentication must be performed server-side.
Request
{
"amount": "120.00",
"order_id": "10025",
"callback": "https://example.com/webhooks/1nodes",
"return_url": "https://example.com/payment/complete",
"meta": {
"currency": "USD",
"customer_email": "Customer email address"
}
}
| Parameter | Type | Required | Description |
|---|---|---|---|
| amount | string | yes | Payment amount |
| order_id | string | yes | Your internal order identifier |
| callback | url | yes | Server-side webhook endpoint |
| return_url | url | yes | Customer browser return URL |
| meta | array | Optional | Additional merchant metadata |
Examples
curl -X POST "https://1nodes.com/wp-json/v1/api/create-payment" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_MERCHANT_KEY" \
-d '{
"amount": "120.00",
"order_id": "10025",
"callback": "https://example.com/webhooks/1nodes",
"return_url": "https://example.com/payment/complete",
"meta": {
"currency": "USD",
"customer_email": "[email protected]"
}
}'
$merchantKey = 'YOUR_MERCHANT_KEY';
$data = [
'amount' => '120.00',
'order_id' => '10025',
'callback' => 'https://example.com/webhooks/1nodes',
'return_url' => 'https://example.com/payment/complete',
'meta' => [
'currency' => 'USD',
'customer_email' => '[email protected]',
],
];
$ch = curl_init(
'https://1nodes.com/wp-json/v1/api/create-payment'
);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Accept: application/json',
'Content-Type: application/json',
'Authorization: Bearer ' . $merchantKey,
],
CURLOPT_POSTFIELDS => json_encode($data),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
const merchantKey = 'YOUR_MERCHANT_KEY';
const response = await fetch(
'https://1nodes.com/wp-json/v1/api/create-payment',
{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${merchantKey}`,
},
body: JSON.stringify({
amount: '120.00',
order_id: '10025',
callback: 'https://example.com/webhooks/1nodes',
return_url: 'https://example.com/payment/complete',
meta: {
currency: 'USD',
customer_email: '[email protected]',
},
}),
}
);
const data = await response.json();
console.log(data);
import requests
merchant_key = "YOUR_MERCHANT_KEY"
response = requests.post(
"https://1nodes.com/wp-json/v1/api/create-payment",
headers={
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": f"Bearer {merchant_key}",
},
json={
"amount": "120.00",
"order_id": "10025",
"callback": "https://example.com/webhooks/1nodes",
"return_url": "https://example.com/payment/complete",
"meta": {
"currency": "USD",
"customer_email": "[email protected]",
},
},
)
print(response.json())
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func main() {
merchantKey := "YOUR_MERCHANT_KEY"
payload := map[string]interface{}{
"amount": "120.00",
"order_id": "10025",
"callback": "https://example.com/webhooks/1nodes",
"return_url": "https://example.com/payment/complete",
"meta": map[string]string{
"currency": "USD",
"customer_email": "[email protected]",
},
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest(
http.MethodPost,
"https://1nodes.com/wp-json/v1/api/create-payment",
bytes.NewBuffer(body),
)
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
req.Header.Set(
"Authorization",
"Bearer "+merchantKey,
)
client := &http.Client{}
response, err := client.Do(req)
if err != nil {
panic(err)
}
defer response.Body.Close()
fmt.Println(response.StatusCode)
}
201 Payment Response
A successful payment creation request returns the checkout URL that should be opened by the customer.
{
"success": true,
"code": "PAYMENT_CREATED",
"message": "Payment created successfully",
"data": {
"payment_id": "01M2512KXS94WWT41MQA1EPEZC",
"checkout_url": "https://1nodes.com/i/..."
}
}
Checkout
After creating a payment, redirect the customer to the returned checkout_url.
🔵The checkout page is only responsible for collecting the payment. Your backend must rely on the webhook to confirm the final payment state.
Payment Status
The webhook currently provides the final payment notification. Your application should update its own order state after successfully validating the webhook.
| Status | Meaning |
|---|---|
| paid | Payment successfully confirmed |
Webhooks
Webhooks allow 1nodes to notify your backend when a payment has been successfully confirmed.
Content-Type: application/json
X-Webhook-Signature: YOUR_SIGNATURE
Signature Verification
Every webhook request must be verified using your Secret Key before processing the payload.
Signature algorithm
$rawRequestBody = file_get_contents('php://input');
$receivedSignature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$expectedSignature = hash_hmac(
'sha256',
$rawRequestBody,
$secretKey
);
if (!hash_equals($expectedSignature, $receivedSignature)) {
http_response_code(401);
exit('Invalid signature');
}
const crypto = require('crypto');
const expectedSignature = crypto
.createHmac('sha256', secretKey)
.update(rawRequestBody)
.digest('hex');
if (
!crypto.timingSafeEqual(
Buffer.from(expectedSignature),
Buffer.from(receivedSignature)
)
) {
return res.status(401).send('Invalid signature');
}
import hmac
import hashlib
expected_signature = hmac.new(
secret_key.encode(),
raw_request_body.encode(),
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected_signature, received_signature):
return "Invalid signature", 401
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
)
func generateSignature(rawRequestBody []byte, secretKey string) string {
mac := hmac.New(sha256.New, []byte(secretKey))
mac.Write(rawRequestBody)
return hex.EncodeToString(mac.Sum(nil))
}
expectedSignature := generateSignature(
rawRequestBody,
secretKey,
)
if !hmac.Equal(
[]byte(expectedSignature),
[]byte(receivedSignature),
) {
http.Error(w, "Invalid signature", http.StatusUnauthorized)
return
}
Webhook Payload
A successful webhook request contains payment and merchant information.
{
"gateway": "1nodes",
"asset": "bitcoin",
"payment_id": "01M0WDNXR9NK1JMZSNWEDVNY44",
"paid_at": "2026-08-25 12:20:40",
"total_paid": "0.00013906",
"merchant_received": "0.00013906",
"overpaid_amount": "0.00000000",
"remaining_amount": "0.00000000",
"tax": "0.00000000",
"status": "paid",
"payment_state": "exact",
"order_id": "35",
"meta_data": {
"currency": "USD",
"customer_email": "Customer email address"
},
"tx_ids": [
"88752662323215485124154152144jhiyugh...."
]
}
| Field | Description | Possible values |
|---|---|---|
| gateway | Payment gateway identifier | 1nodes |
| asset | Cryptocurrency asset used for payment | btc, dash, litecoin, bch, doge |
| payment_id | Unique 1nodes payment identifier | |
| paid_at | Payment confirmation timestamp | YYYY-MM-DD HH:mm:ss |
| merchant_received | The amount of cryptocurrency received by the merchant for this payment | |
| overpaid_amount | The amount of cryptocurrency paid above the required payment amount. Returns 0 when there is no overpayment | |
| remaining_amount | The amount of cryptocurrency still required to complete the payment. Returns 0 when the payment is fully covered | |
| total_paid | Total cryptocurrency amount paid | |
| merchant_received | Amount received by the merchant | |
| payment_state | Payment matching state | exact, over_paid, partial |
| status | Payment status | paid |
| order_id | Merchant's order identifier | |
| meta_data | Additional merchant metadata | |
| tx_ids | Blockchain transaction identifiers |
Webhook Response
After successfully verifying and processing the webhook, your endpoint should return a successful HTTP response.
HTTP/1.1 200 OK
Content-Type: application/json
http_response_code(200);
return res.sendStatus(200);
return '', 200
w.WriteHeader(http.StatusOK)
🟢 2xx : Webhook accepted and processed successfully.
🔴 4xx / 5xx : Webhook was rejected or could not be processed.
Return URL
The return URL is used to send the customer back to your website after the checkout process.
Recommended flow:
Customer
│
▼
1nodes Checkout
│
├──────────────► Webhook ──────► Your Server
│
▼
Return URL
│
▼
Your Frontend
│
└──► Read order status from your backend
Idempotency
Your webhook handler must be safe to execute more than once. Store the payment_id and prevent the same payment from being fulfilled multiple times.
$paymentId = $payload['payment_id'];
if (payment_already_processed($paymentId)) {
http_response_code(200);
exit;
}
mark_payment_as_processed($paymentId);
fulfill_order($payload['order_id']);
http_response_code(200);
const paymentId = payload.payment_id;
if (await paymentAlreadyProcessed(paymentId)) {
return res.sendStatus(200);
}
await markPaymentAsProcessed(paymentId);
await fulfillOrder(payload.order_id);
return res.sendStatus(200);
payment_id = payload["payment_id"]
if payment_already_processed(payment_id):
return "", 200
mark_payment_as_processed(payment_id)
fulfill_order(payload["order_id"])
return "", 200
paymentID := payload.PaymentID
if paymentAlreadyProcessed(paymentID) {
w.WriteHeader(http.StatusOK)
return
}
markPaymentAsProcessed(paymentID)
fulfillOrder(payload.OrderID)
w.WriteHeader(http.StatusOK)