Create Order
Create payment orders that generate unique payment links for your customers.
Overview
Payment orders define the payment amount, currency, and blockchain network. Each order generates a unique payment link that customers can use to complete their payment.
Quick Start
- JavaScript
- Python
- API
import { HashNutClient, HashNutService, CreatePayOrderRequest } from '@hashnut/sdk';
const client = new HashNutClient(secretKey, true);
const service = new HashNutService(client);
const request = new CreatePayOrderRequest.Builder()
.withAccessKeyId(accessKeyId)
.withMerchantOrderId(`order-${Date.now()}`)
.withChainCode('erc20')
.withCoinCode('usdt')
.withAmount('0.01')
.build();
const response = await service.createPayOrder(request);
console.log('Payment URL:', response.data.paymentUrl);
from hashnut import HashNutClient, HashNutService, CreatePayOrderRequest
from decimal import Decimal
client = HashNutClient(secret_key, True)
service = HashNutService(client)
request = CreatePayOrderRequest.Builder() \
.with_access_key_id(access_key_id) \
.with_merchant_order_id(f'order-{int(time.time())}') \
.with_chain_code('erc20') \
.with_coin_code('usdt') \
.with_amount(Decimal('0.01')) \
.build()
response = service.create_pay_order(request)
print(f'Payment URL: {response.data.payment_url}')
curl -X POST 'https://testnet.hashnut.io/api/v3.0.0/pay/createPayOrderOnSplitWalletWithApiKey' \
-H 'hashnut-request-uuid: <uuid>' \
-H 'hashnut-request-timestamp: <timestamp>' \
-H 'hashnut-request-sign: <signature>' \
-H 'Content-Type: application/json' \
-d '{
"accessKeyId": "YOUR_ACCESS_KEY_ID",
"merchantOrderId": "order-123",
"chainCode": "erc20",
"coinCode": "usdt",
"amount": 0.01,
"callBackUrl": "https://your-site.com/api/webhook",
"frontendCallbackUrl": "https://your-site.com/payment/success"
}'
Order Creation Flow
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
merchantOrderId | string | Unique order ID in your system | "order-123" |
chainCode | string | Blockchain network code | "erc20", "polygon-erc20" |
coinCode | string | Currency code (case-sensitive) | "usdt", "usdc" |
amount | decimal | Payment amount (minimum 0.01) | 0.01, 1.5 |
Optional Parameters
| Parameter | Type | Description | When to Use |
|---|---|---|---|
callBackUrl | string | Webhook URL for payment notifications | Always recommended |
frontendCallbackUrl | string | Redirect URL after payment | For customer redirect |
receiptAddress | string | Custom receiving address | If not using default |
splitterAddress | string | Custom smart contract address | Advanced use cases |
Step-by-Step Guide
Step 1: Choose Chain and Currency
First, query available options:
// Get supported chains
import { QueryChainsRequest } from '@hashnut/sdk';
const chainsRequest = new QueryChainsRequest.Builder().build();
const chainsResponse = await service.queryAllChainInfo(chainsRequest);
// Get supported tokens for a chain
import { QuerySupportCoinRequest } from '@hashnut/sdk';
const coinsRequest = new QuerySupportCoinRequest.Builder()
.withChainCode('erc20')
.build();
const coinsResponse = await service.querySupportCoin(coinsRequest);
Common Combinations:
- Ethereum + USDT:
chainCode: "erc20",coinCode: "usdt" - Polygon + USDC:
chainCode: "polygon-erc20",coinCode: "usdc" - TRON + USDT:
chainCode: "tron-trc20",coinCode: "usdt"
Step 2: Set Payment Amount
Important:
- Minimum: 0.01
- Format: Base unit (e.g.,
0.01for 0.01 USDT, not10000) - Precision: Round to 2 decimal places
// ✅ Correct
amount: 0.01 // 0.01 USDT
// ❌ Wrong
amount: 10000 // This would be 10,000 USDT!
Step 3: Generate Merchant Order ID
Requirements:
- Must be unique per merchant
- Max 255 characters
- Use descriptive format
Good Examples:
`order-${Date.now()}`
`payment-${userId}-${timestamp}`
`${productId}-${orderNumber}`
Bad Examples:
`order-1` // Not unique
`test` // Not descriptive
Step 4: Configure Callbacks
Backend Webhook (callBackUrl):
- Receives payment status updates
- Must be HTTPS
- Should verify signatures
Frontend Redirect (frontendCallbackUrl):
- Customer redirected here after payment
- Can include order parameters
- Should show success/failure page
Step 5: Create the Order
- JavaScript
- Python
try {
const request = new CreatePayOrderRequest.Builder()
.withAccessKeyId(accessKeyId)
.withMerchantOrderId(`order-${Date.now()}`)
.withChainCode('erc20')
.withCoinCode('usdt')
.withAmount('0.01')
.build();
const response = await service.createPayOrder(request);
const order = response.data;
// Store order.payOrderId in your database
// Redirect customer to order.paymentUrl
window.location.href = order.paymentUrl;
} catch (error) {
console.error('Order creation failed:', error);
}
try:
request = CreatePayOrderRequest.Builder() \
.with_access_key_id(access_key_id) \
.with_merchant_order_id(f'order-{int(time.time())}') \
.with_chain_code('erc20') \
.with_coin_code('usdt') \
.with_amount(Decimal('0.01')) \
.build()
response = service.create_pay_order(request)
order = response.data
# Store order.pay_order_id in your database
# Redirect customer to order.payment_url
return redirect(order.payment_url)
except Exception as e:
print(f'Order creation failed: {e}')
Order Response
Response Fields
{
"code": 0,
"msg": "success",
"data": {
"payOrderId": "01KBZ292SK2GKFK97916F5EC3B",
"accessSign": "D3DE7E4002057C0EAED1BE2268DA53CC9058DCFC9DCAF50D999AF270A7B033C5",
"merchantOrderId": "order-123"
}
}
Payment URL Construction
Construct the payment URL:
https://testnet.hashnut.io/pay?accessSign={accessSign}&merchantOrderId={merchantOrderId}&payOrderId={payOrderId}&chainCode={chainCode}
SDK Method:
const paymentUrl = order.paymentUrl; // SDK handles construction
Order Types
DeFi Orders
Smart Contract Mode:
- Uses address pool from smart contract
- Funds held in contract until withdrawal
- Supports multi-party fee splitting
Use When:
- You need maximum security
- You want address pool management
- You need on-chain verification
CeFi Orders
Direct Wallet Mode:
- Uses your direct wallet address
- Funds sent directly to wallet
- Simplified fund management
Use When:
- You want immediate fund access
- You prefer simpler operations
- You don't need address pools
Best Practices
Order ID Management
- Use UUIDs or Timestamps: Ensure uniqueness
- Store in Database: Save
payOrderIdandmerchantOrderIdmapping - Idempotency: Check for existing orders before creating
- Format: Use consistent naming convention
Amount Handling
- Validate Minimum: Ensure amount >= 0.01
- Round to 2 Decimals: Avoid floating point issues
- Currency Precision: Consider token decimals (USDT = 6, ETH = 18)
- Display Format: Show user-friendly amounts
Error Handling
try {
const request = new CreatePayOrderRequest.Builder()
.withAccessKeyId(accessKeyId)
.withMerchantOrderId(`order-${Date.now()}`)
.withChainCode('erc20')
.withCoinCode('usdt')
.withAmount('0.01')
.build();
const response = await service.createPayOrder(request);
} catch (error) {
if (error.errorCode === -2) {
// Authentication or parameter error
console.error('Invalid request:', error.message);
} else {
// Other errors
console.error('Order creation failed:', error);
}
}
Common Use Cases
E-Commerce Checkout
// In checkout flow
const request = new CreatePayOrderRequest.Builder()
.withAccessKeyId(accessKeyId)
.withMerchantOrderId(`checkout-${cartId}-${Date.now()}`)
.withChainCode('erc20')
.withCoinCode('usdt')
.withAmount(cartTotal.toString())
.build();
const response = await service.createPayOrder(request);
// Redirect to payment
router.redirect(response.data.paymentUrl);
Subscription Payment
// Recurring payment
const request = new CreatePayOrderRequest.Builder()
.withAccessKeyId(accessKeyId)
.withMerchantOrderId(`subscription-${userId}-${subscriptionId}-${billingCycle}`)
.withChainCode('polygon-erc20')
.withCoinCode('usdc')
.withAmount(subscriptionAmount.toString())
.build();
const response = await service.createPayOrder(request);
Donation/One-Time Payment
// Simple donation
const request = new CreatePayOrderRequest.Builder()
.withAccessKeyId(accessKeyId)
.withMerchantOrderId(`donation-${Date.now()}`)
.withChainCode('erc20')
.withCoinCode('usdt')
.withAmount(donationAmount.toString())
.build();
const response = await service.createPayOrder(request);
Order Expiration
Orders may expire after a certain time period. Check order status regularly if payment is delayed.
Next Steps
- Manage Orders: View and filter orders
- Order States: Understand order lifecycle
- Webhook Integration: Set up payment notifications
Order created? Learn about Order Management →