This document describes the REST API endpoints and webhook events for ZeroPay.
All API requests require authentication using an API key. Include your API key as a query parameter:
?apikey=your-api-key-here
Security Note: For production environments, consider using header-based authentication or implement OAuth 2.0.
http://your-domain:9000
https://api.zpaynow.com
Platform deployment includes additional features such as a public payment UI and automatic chain configuration, with a commission deducted as gas fee handling.
Create a new payment session for a customer.
Endpoint: POST /sessions
Query Parameters:
apikey(required): Your API key
Request Body:
{
"customer": "string",
"amount": integer
}Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
customer |
string | Yes | Unique identifier for the customer |
amount |
integer | Yes | Payment amount in cents (e.g., 1000 = $10.00) |
Response: 200 OK
{
"session_id": 12345,
"customer": "neo",
"pay_eth": "0x1234567890abcdef1234567890abcdef12345678",
"amount": 1000,
"expired": "2025-10-13T12:00:00Z",
"completed": false,
"session_url": "https://zpaynow.com/sessions/abc123",
"merchant": "Your Store Name",
"chains": [
{
"name": "ethereum",
"estimation": 72,
"commission": 5,
"commission_min": 50,
"commission_max": 200,
"tokens": {
"USDT": {
"identity": "ethereum:usdt",
"name": "Tether USD",
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
},
"USDC": {
"identity": "ethereum:usdc",
"name": "USD Coin",
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
}
}
}
]
}Response Fields:
| Field | Type | Description |
|---|---|---|
session_id |
integer | Unique session identifier |
customer |
string | Customer identifier |
pay_eth |
string | Payment address for EVM-compatible chains |
amount |
integer | Payment amount in cents |
expired |
string (ISO 8601) | Session expiration timestamp |
completed |
boolean | Whether payment has been completed |
session_url |
string | Public payment page URL (platform only)* |
merchant |
string | Merchant name (platform only)* |
chains |
array | List of supported blockchain networks (platform only)* |
Note: Fields marked with * are only available when using the managed platform service.
Chain Object:
| Field | Type | Description |
|---|---|---|
name |
string | Blockchain network name |
estimation |
integer | Estimated confirmation time in seconds |
commission |
integer | Commission rate percentage (1-100) |
commission_min |
integer | Minimum commission in cents |
commission_max |
integer | Maximum commission in cents |
tokens |
object | Supported tokens on this chain |
Token Object:
| Field | Type | Description |
|---|---|---|
identity |
string | Unique token identifier |
name |
string | Human-readable token name |
address |
string | Token contract address |
Example Request:
curl -X POST "https://api.zpaynow.com/sessions?apikey=your-api-key" \
-H "Content-Type: application/json" \
-d '{
"customer": "neo",
"amount": 1000
}'Retrieve the current status of a payment session.
Endpoint: GET /sessions/{session_id}
Query Parameters:
apikey(required): Your API key
Path Parameters:
session_id(required): The session ID to query
Response: 200 OK
Returns the same response structure as the Create Payment Session endpoint.
Example Request:
curl "https://api.zpaynow.com/sessions/12345?apikey=your-api-key"ZeroPay sends HTTP POST requests to your configured webhook URL when payment events occur.
All webhook requests are secured using HMAC-SHA256 signatures to verify authenticity.
Verification Process:
- Secret Key: Your API key serves as the HMAC secret
- Signature Header: The
X-HMACheader contains the signature - Message: The raw request body is the signed message
Example Verification (Node.js):
const crypto = require('crypto');
function verifyWebhook(apiKey, signature, body) {
const hmac = crypto.createHmac('sha256', apiKey);
hmac.update(body);
const computed = hmac.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(computed)
);
}
// In your webhook handler
app.post('/webhook', (req, res) => {
const signature = req.headers['x-hmac'];
const body = JSON.stringify(req.body);
if (!verifyWebhook(process.env.APIKEY, signature, body)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process the webhook event
const { event, params } = req.body;
// ...
});Example Verification (Python):
import hmac
import hashlib
def verify_webhook(api_key: str, signature: str, body: bytes) -> bool:
computed = hmac.new(
api_key.encode(),
body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, computed)
# In your webhook handler
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-HMAC')
body = request.get_data()
if not verify_webhook(os.environ['APIKEY'], signature, body):
return {'error': 'Invalid signature'}, 401
data = request.json
event = data['event']
params = data['params']
# ...Example Verification (Rust):
use hmac::{Hmac, Mac};
use sha2::Sha256;
type HmacSha256 = Hmac<Sha256>;
fn verify_webhook(api_key: &str, signature: &str, body: &[u8]) -> bool {
let mut mac = HmacSha256::new_from_slice(api_key.as_bytes())
.expect("HMAC can take key of any size");
mac.update(body);
let computed = hex::encode(mac.finalize().into_bytes());
signature == computed
}Triggered when a customer completes payment for a session.
Payload:
{
"event": "session.paid",
"params": [12345, "neo", 1000]
}Parameters:
params[0](integer): Session IDparams[1](string): Customer identifierparams[2](integer): Deposited amount in cents
Triggered when funds (minus commission) are transferred to your merchant account.
Payload:
{
"event": "session.settled",
"params": [12345, "neo", 9500]
}Parameters:
params[0](integer): Session IDparams[1](string): Customer identifierparams[2](integer): Settled amount in cents (after commission)
Note: The settled amount is less than the paid amount due to commission fees for gas and platform services.
Triggered when payment is received but cannot be linked to a session (e.g., customer paid to a reused address).
Payload:
{
"event": "unknown.paid",
"params": ["neo", 1000]
}Parameters:
params[0](string): Customer identifier (if available)params[1](integer): Deposited amount in cents
Triggered when unlinked funds are transferred to your merchant account.
Payload:
{
"event": "unknown.settled",
"params": ["neo", 9500]
}Parameters:
params[0](string): Customer identifier (if available)params[1](integer): Settled amount in cents (after commission)
| Code | Description |
|---|---|
200 |
Success |
400 |
Bad Request - Invalid parameters |
401 |
Unauthorized - Invalid or missing API key |
404 |
Not Found - Session does not exist |
500 |
Internal Server Error |
Create a payment session and receive a unique deposit address:
curl -X POST "http://localhost:9000/sessions?apikey=your-api-key" \
-H "Content-Type: application/json" \
-d '{
"customer": "user123",
"amount": 1000
}'Check payment status:
curl "http://localhost:9000/sessions/12345?apikey=your-api-key"- Create a payment session:
curl -X POST "https://api.zpaynow.com/sessions?apikey=your-api-key" \
-H "Content-Type: application/json" \
-d '{
"customer": "user123",
"amount": 5000
}'-
Display payment information to customer:
- Show the
pay_ethaddress - Display the
amountto be paid - List available
chainsandtokens - Show
expiredtime
- Show the
-
Monitor session status (polling):
curl "https://api.zpaynow.com/sessions/12345?apikey=your-api-key"- Receive webhook notifications:
session.paid: Customer completed paymentsession.settled: Funds transferred to your account
- Session Expiration: Always check the
expiredfield and handle expired sessions appropriately - Polling vs Webhooks: Use webhooks for real-time updates, polling as a fallback
- Idempotency: Store session IDs to prevent duplicate session creation
- Error Handling: Implement retry logic with exponential backoff for API calls
- Testing: Use testnet chains during development
- Webhook Endpoint: Ensure your webhook endpoint:
- Responds quickly (< 5 seconds)
- Returns 2xx status on success
- Handles duplicate events idempotently
- Verifies HMAC signatures before processing
Currently, there are no enforced rate limits, but we recommend:
- Max 100 requests per second per API key
- Max 1000 session creations per hour
For higher limits, contact support or consider self-hosting.
For questions and issues:
- GitHub: https://github.com/zpaynow/zeropay/issues
- Platform Support: https://zpaynow.com/support