POST
/api/v1/projects/:projectId/webhooksBody: { "url": "https://…", "events": ["order.paid", "order.failed"] }
Permission:
webhooks:writeRegister HTTPS endpoints to receive real-time payment events. Always verify signatures before processing.
/api/v1/projects/:projectId/webhooksBody: { "url": "https://…", "events": ["order.paid", "order.failed"] }
webhooks:writecurl -s -X POST "https://pay.andgroupco.com/api/v1/projects/PROJECT_ID/webhooks" \
-H "Authorization: Bearer tp_test_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhooks/towanpay",
"events": ["order.paid", "order.failed"]
}'| Event | When to use |
|---|---|
order.paid | Order successfully paid — extend access, fulfill order |
order.failed | Payment failed or expired — notify customer, retry billing |
order.payment_pending_verify | Buyer reported payment or uploaded proof — awaiting merchant/admin verification |
transaction.completed | Ledger transaction recorded |
Subscription integrations
order.paid and order.failed. Order metadata (subscription_id, billing_period) is included in every order event payload.Verify X-TowanPay-Signature using HMAC-SHA256 of the raw request body with your webhook secret. Use constant-time comparison to prevent timing attacks.
import crypto from "crypto";
function verifyTowanPayWebhook(rawBody, signatureHeader, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody, "utf8")
.digest("hex");
if (!signatureHeader || expected.length !== signatureHeader.length) return false;
return crypto.timingSafeEqual(
Buffer.from(expected, "hex"),
Buffer.from(signatureHeader, "hex"),
);
}order.paid includes the order resource and project id. The gateway used is available on payment.session.created, order.payment_pending_verify (payment_session.gateway), and transaction.completed (transaction.gateway).
{
"id": "evt_xxxxxxxx",
"event": "order.paid",
"created_at": "2026-03-15T10:00:00.000Z",
"livemode": false,
"data": {
"order": {
"id": "ord_xxxxxxxx",
"reference": "TP-202603-001",
"status": "paid",
"amount_minor": 9900,
"currency": "CNY",
"metadata": {
"subscription_id": "sub_abc123",
"plan": "pro",
"billing_period": "2026-03"
},
"paid_at": "2026-03-15T10:00:00.000Z"
},
"project_id": "clxxxxxxxxxxxxxxxx"
}
}{
"event": "payment.session.created",
"livemode": false,
"data": {
"order": { "id": "ord_xxxxxxxx", "status": "unpaid" },
"payment_session": {
"id": "ps_xxxxxxxx",
"gateway": "wechatpay",
"status": "pending",
"amount_minor": 9900,
"currency": "CNY"
},
"project_id": "clxxxxxxxxxxxxxxxx"
}
}/api/v1/projects/:projectId/webhookswebhooks:read/api/v1/projects/:projectId/webhooks/:idwebhooks:write/api/v1/projects/:projectId/webhooks/:id/testSend a test event to your endpoint.
webhooks:write/api/v1/projects/:projectId/webhooks/:id/attemptsDelivery attempt history.
webhooks:read