Creating Payments
Create a payment and redirect your customer to the hosted checkout.
Endpoint
POST
/v1/paymentRate limit: 60 requests per minute. Requires authentication.
Request
curl -X POST https://api.cloakd.ai/v1/payment \
-H "X-API-Key: sk_live_your_api_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2026-001-1735905600" \
-d '{
"pay_amount": "100.00",
"order_id": "ORDER-2026-001",
"order_description": "Premium Subscription",
"success_url": "https://yoursite.com/success",
"cancel_url": "https://yoursite.com/cancel",
"expiration_minutes": 60
}'| Field | Required | Description |
|---|---|---|
| pay_amount | Yes | Amount in your settlement currency (string, e.g. "100.00") |
| order_id | Yes | Your internal order or invoice ID (max 255 chars) |
| order_description | No | Human-readable description shown on the checkout (max 1000 chars) |
| callback_url | No | Webhook URL for this payment (overrides your default) |
| success_url | No | Redirect URL after successful payment |
| cancel_url | No | Redirect URL if the customer cancels |
| expiration_minutes | No | Expiration time in minutes (5–1440, default: 60) |
| customer_email | No | Customer email for receipts |
Response
{
"id": "cm9x8y7z6a5b4c3d2e1f0g1h",
"token_id": "abc123def456",
"order_id": "ORDER-2026-001",
"checkout_url": "https://pay.cloakd.ai/checkout/abc123def456",
"status": "WAITING",
"pay_amount": "100.00",
"pay_currency": "USDT",
"pay_network": "ethereum",
"actually_paid": null,
"actually_paid_currency": null,
"created_at": "2026-01-03T10:00:00.000Z",
"expires_at": "2026-01-03T11:00:00.000Z",
"settled_at": null
}Redirect your customer to the checkout_url to complete payment.
Store the id in your database alongside your order. You will need it to check status and match webhook events.
Payment lifecycle
| Status | Meaning | What to do |
|---|---|---|
| WAITING | Payment created, waiting for customer | Show the checkout_url to the customer |
| PENDING | Customer initiated payment, awaiting blockchain confirmation | Monitor via webhook |
| CONFIRMING | Transaction detected, waiting for confirmations | Wait — do not fulfill yet |
| SETTLED | Payment fully confirmed and settled | Deliver goods or services |
| EXPIRED | Payment expired before completion | Create a new payment if needed |
| FAILED | Technical failure | Contact support or retry |
Idempotency
Always include an Idempotency-Key header when creating payments. If a network timeout causes you to retry the same request, the key prevents duplicate payments being created.
// Node.js example
const idempotencyKey = `order-${orderId}-${Date.now()}`;
await fetch('https://api.cloakd.ai/v1/payment', {
method: 'POST',
headers: {
'X-API-Key': process.env.CLOAKD_API_KEY,
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey,
},
body: JSON.stringify(paymentData),
});Checking payment status
Use GET /v1/payment/:id to query a specific payment. For ongoing status updates, prefer webhooks over polling.
curl -X GET https://api.cloakd.ai/v1/payment/cm9x8y7z6a5b4c3d2e1f0g1h \ -H "X-API-Key: sk_live_your_api_key"
Best practices
- ✓Store the payment id in your database alongside your order ID as soon as you create it.
- ✓Never calculate the amount client-side — always compute it on your server before calling the API.
- ✓Use webhooks for settlement detection instead of polling GET /v1/payment/:id repeatedly.
- ✓Set expiration_minutes based on your use case: 15–30 minutes for digital goods, 60+ for physical items.
- ✓Implement exponential backoff and respect the Retry-After header when you receive a 429 response.