Quickstart
1 min read
From zero to a confirmed USDT payment in three steps.
Create a key in the dashboard, create a payment, then confirm via polling or a signed webhook. Sandbox keys (`mnt_test_sk_`) settle on local chain forks — no real funds move.
- ›1 — Create an API key: Dashboard → API Keys → Create key. Copy it once; only the hash is stored.
- ›2 — Create a payment with the call below. You get back a single-use deposit address and a hosted checkout URL.
- ›3 — Confirm: listen for the payment.confirmed webhook, or poll GET /v1/payments/:id until status is confirmed.
Create your first payment
Amounts are USDT with 6 decimal places: 25 USDT = "25.000000" (string). The API accepts decimal strings, not raw integers.
Request
curl -X POST https://api.nity0x.io/v1/payments \ -H "Authorization: Bearer mnt_test_sk_your_key_here" \ -H "Idempotency-Key: order_001" \ -H "Content-Type: application/json" \ -d '{"amount":"25.000000","chain":"eth"}'
Response
{
"id": "pay_3kf9d2a1b7c4",
"object": "payment",
"status": "awaiting_payment",
"chain": "eth",
"amount": "25.000000",
"currency": "USDT",
"deposit_address": "0x7a3f1d4c8b2e6a9f0d3c5b7e1a4f8d2c6b9e0a1f",
"checkout_url": "https://api.nity0x.io/checkout/pay_3kf9d2a1b7c4",
"expires_at": "2026-06-20T12:30:00Z",
"created_at": "2026-06-20T12:00:00Z"
}Authentication
1 min read
All API requests require a secret key passed as a Bearer token.
NITY0X uses API keys for authentication. Each key is prefixed `mnt_test_sk_` (sandbox) or `mnt_live_sk_` (production). Keys are hashed with SHA-256 before storage — we never retain the plaintext after initial display.
- ›Never commit API keys to version control.
- ›Rotate keys immediately if compromised — old keys are invalidated on rotation.
- ›Sandbox keys hit local chain forks — no real funds move.
- ›All responses include X-API-Version: 1 so you can detect future version changes.
/v1/paymentsAuthenticated request
Pass your secret key as a Bearer token in every request.
Request
curl https://api.nity0x.io/v1/payments \ -H "Authorization: Bearer mnt_test_sk_your_key_here"
GET /v1/payments HTTP/1.1 Host: api.nity0x.io Authorization: Bearer mnt_test_sk_your_key_here
Response
{
"error": {
"type": "unauthorized",
"message": "Invalid or missing API key",
"status": 401
}
}Idempotency
1 min read
Safely retry POST requests without creating duplicate resources.
All mutating endpoints (POST) support the `Idempotency-Key` header. If you retry a request with the same key, you receive the original response instead of creating a duplicate. Keys expire after 24 hours.
- ›Use a UUID or a stable identifier from your system (e.g. your order ID).
- ›An idempotency conflict (409) is returned if you reuse a key with different request parameters.
- ›Safe to retry on network timeouts or 5xx errors — the same key will return the cached result.
Idempotent payment creation
Retrying with the same Idempotency-Key returns the original payment, not a duplicate.
Request
# First call — creates payment curl -X POST https://api.nity0x.io/v1/payments \ -H "Authorization: Bearer mnt_test_sk_..." \ -H "Idempotency-Key: order_abc123" \ -H "Content-Type: application/json" \ -d '{"amount":"10.000000","chain":"polygon"}' # Retry (network failure, timeout, etc.) — returns same payment curl -X POST https://api.nity0x.io/v1/payments \ -H "Authorization: Bearer mnt_test_sk_..." \ -H "Idempotency-Key: order_abc123" \ -H "Content-Type: application/json" \ -d '{"amount":"10.000000","chain":"polygon"}'
Response
{
"error": {
"type": "idempotency_conflict",
"message": "Idempotency key already used with different request parameters.",
"status": 409
}
}Rate Limits
1 min read
NITY0X enforces per-key sliding-window rate limits.
Rate limits are applied per API key using a sliding 60-second window. Different endpoints have different limits based on their risk profile.
- ›Default: 60 requests/minute per API key.
- ›Payout endpoints: 10 requests/minute (write operations).
- ›Checkout (public): 30 requests/minute.
- ›When rate limited, wait for the window to reset before retrying — exponential backoff is recommended.
Rate limit response
When you exceed the rate limit you receive a 429 with a stable error code.
Response
{
"error": {
"type": "rate_limit_exceeded",
"message": "Too many requests. Please retry after 30 seconds.",
"status": 429
}
}Balances
1 min read
Retrieve USDT balances for your merchant accounts across all chains.
/v1/balancesList all balances
Returns confirmed USDT balances across all enabled chains. `available` is withdrawable now; `reserved` is held for in-flight payment intents.
Request
curl https://api.nity0x.io/v1/balances \ -H "Authorization: Bearer mnt_test_sk_..."
Response
{
"object": "list",
"data": [
{
"chain": "eth",
"symbol": "USDT",
"available": "1500.000000",
"reserved": "25.000000"
},
{
"chain": "polygon",
"symbol": "USDT",
"available": "250.000000",
"reserved": "0.000000"
},
{
"chain": "tron",
"symbol": "USDT",
"available": "800.000000",
"reserved": "0.000000"
}
]
}Payments
1 min read
Create and manage USDT payment intents across chains.
A payment moves through a deterministic state machine: `intent_created → awaiting_payment → pending → confirming → confirmed`. Terminal states are `expired` and `failed`. Subscribe to webhooks for real-time status changes rather than polling.
- ›Amounts are decimal strings with 6 decimal places (e.g. "25.000000" for 25 USDT).
- ›Each payment gets a unique single-use deposit address — never reuse addresses.
- ›Payments expire after a configurable TTL (default 30 minutes).
- ›Underpayments remain in awaiting_payment until the full amount is received or the intent expires.
/v1/paymentsCreate payment intent
Creates a deposit address and returns a payment object. The payer sends USDT to the returned `deposit_address`.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| amount | string | required | Amount in USDT decimal notation, 6dp. E.g. `"25.000000"` = 25 USDT. |
| chain | string | optional | Chain: `eth`, `bnb`, `polygon`, `tron`, `solana`. Omit to create a chain-agnostic intent (payer selects chain at checkout). |
| description | string | optional | Human-readable description shown on the checkout page. |
| metadata | object | optional | Arbitrary key/value pairs attached to the payment and included in webhook payloads. |
| expires_in | number | optional | TTL in seconds (default 1800, minimum 60, maximum 86400). |
Request
curl -X POST https://api.nity0x.io/v1/payments \ -H "Authorization: Bearer mnt_test_sk_..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: order_abc123" \ -d '{ "amount": "25.000000", "chain": "eth", "description": "Order #789", "metadata": { "order_id": "ord_789", "customer": "cus_xyz" } }'
Response
{
"id": "pay_01HXYZ",
"object": "payment",
"status": "awaiting_payment",
"chain": "eth",
"amount": "25.000000",
"currency": "USDT",
"deposit_address": "0xAbCd...1234",
"description": "Order #789",
"metadata": { "order_id": "ord_789", "customer": "cus_xyz" },
"checkout_url": "https://api.nity0x.io/checkout/pay_01HXYZ",
"tx_hash": null,
"confirmations": 0,
"expires_at": "2026-06-19T10:30:00Z",
"created_at": "2026-06-19T10:00:00Z"
}/v1/payments/:idRetrieve a payment
Returns the current state of a payment intent.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | string | required | Payment ID (`pay_…`). |
Request
curl https://api.nity0x.io/v1/payments/pay_01HXYZ \ -H "Authorization: Bearer mnt_test_sk_..."
Response
{
"id": "pay_01HXYZ",
"object": "payment",
"status": "confirmed",
"chain": "eth",
"amount": "25.000000",
"currency": "USDT",
"deposit_address": "0xAbCd...1234",
"tx_hash": "0xabc...def",
"confirmations": 12,
"confirmed_at": "2026-06-19T10:05:30Z",
"created_at": "2026-06-19T10:00:00Z"
}/v1/paymentsList payments
Returns a paginated list of payments ordered newest first. Use `starting_after` with the last returned `id` to fetch the next page.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| limit | number | optional | Max items per page (1–100, default 20). |
| starting_after | string | optional | Payment `id` to start after (exclusive cursor). Use the last `id` from the previous page. |
Request
curl "https://api.nity0x.io/v1/payments?limit=10" \ -H "Authorization: Bearer mnt_test_sk_..."
# Use the last id from the previous response as starting_after curl "https://api.nity0x.io/v1/payments?limit=10&starting_after=pay_01HXYZ" \ -H "Authorization: Bearer mnt_test_sk_..."
Response
{
"object": "list",
"data": [
{
"id": "pay_01HXYZ",
"object": "payment",
"status": "confirmed",
"chain": "eth",
"amount": "25.000000",
"currency": "USDT",
"created_at": "2026-06-19T10:00:00Z"
}
],
"has_more": true
}/v1/payments/:id/replayReplay webhook
Re-dispatches the current-status webhook for this payment to all active registered endpoints. Useful for recovering from missed deliveries. Rate-limited to 10 calls/minute.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | string | required | Payment ID (`pay_…`). |
Request
curl -X POST https://api.nity0x.io/v1/payments/pay_01HXYZ/replay \ -H "Authorization: Bearer mnt_test_sk_..."
Response
{
"event": "payment.confirmed",
"dispatched": 2,
"deliveries": [
{
"endpointId": "whe_01HQ9M3K2S",
"url": "https://merchant.example/webhooks/nityox",
"success": true,
"statusCode": 200
}
]
}Payment Links
1 min read
Create short-lived hosted checkout links without building a custom payment form.
Payment links open NITY0X's hosted checkout and expire 30 minutes after creation. A payer chooses an enabled network at checkout; completing the checkout creates a normal payment that follows the payment state machine and emits the same signed webhooks.
- ›Every link expires 30 minutes after creation and cannot be extended.
- ›Use a new Idempotency-Key for each intended link; retries with the same key return the original response.
- ›The `active` field is false after expiry even if the stored link has not been manually deactivated.
/v1/payment-linksCreate a payment link
Creates a hosted checkout URL for a fixed USDT amount. The link expires 30 minutes after creation.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| amount | string | required | Amount in USDT decimal notation with up to 6 decimal places. |
| description | string | optional | Customer-facing description, maximum 500 characters. |
Request
curl -X POST https://api.nity0x.io/v1/payment-links \ -H "Authorization: Bearer mnt_test_sk_..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: checkout_order_789" \ -d '{"amount":"49.000000","description":"Order #789"}'
Response
{
"id": "pl_01J2ZX8R7Q",
"object": "payment_link",
"url": "https://api.nity0x.io/pay/link_7Qm2p9Xk4A",
"amount": "49",
"currency": "USDT",
"description": "Order #789",
"active": true,
"created_at": "2026-07-14T10:00:00.000Z",
"expires_at": "2026-07-14T10:30:00.000Z"
}/v1/payment-linksList payment links
Returns every payment link owned by the authenticated merchant, newest first.
Request
curl https://api.nity0x.io/v1/payment-links \ -H "Authorization: Bearer mnt_test_sk_..."
Response
{
"object": "list",
"data": [
{
"id": "pl_01J2ZX8R7Q",
"object": "payment_link",
"amount": "49",
"url": "https://api.nity0x.io/pay/link_7Qm2p9Xk4A",
"description": "Order #789",
"active": true,
"expires_at": "2026-07-14T10:30:00.000Z"
}
]
}Payouts
1 min read
Withdraw confirmed USDT balances to an on-chain address.
Payouts debit your merchant balance and initiate an on-chain USDT transfer. The payout goes through `pending → processing → confirmed` states. A `payout.confirmed` webhook fires on settlement.
- ›Only confirmed (settled) balances can be withdrawn.
- ›Payout endpoints are rate-limited to 10 requests/minute.
- ›Always use Idempotency-Key to prevent duplicate payouts.
/v1/payoutsCreate payout
Initiates a USDT transfer from your merchant balance to an on-chain address.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| chain | string | required | Chain to send on: `eth`, `bnb`, `polygon`, `tron`, `solana`. |
| to_address | string | required | Destination on-chain address. |
| amount | string | required | Amount in USDT decimal notation (6dp). E.g. `"100.000000"`. |
| description | string | optional | Optional note for your records. |
| metadata | object | optional | Arbitrary key/value pairs retained on the payout and included in lifecycle events. |
Request
curl -X POST https://api.nity0x.io/v1/payouts \ -H "Authorization: Bearer mnt_test_sk_..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: payout_20260619_001" \ -d '{ "chain": "eth", "to_address": "0xYourWallet...1234", "amount": "100.000000", "description": "Weekly settlement" }'
Response
{
"id": "pay_out_01XYZ",
"object": "payout",
"status": "pending",
"chain": "eth",
"to_address": "0xYourWallet...1234",
"amount": "100.000000",
"currency": "USDT",
"tx_hash": null,
"created_at": "2026-06-19T10:00:00Z"
}/v1/payouts/:idRetrieve a payout
Returns the latest state and on-chain details for one payout owned by the authenticated merchant.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | string | required | Payout ID (`pay_out_…`). |
Request
curl https://api.nity0x.io/v1/payouts/pay_out_01XYZ \ -H "Authorization: Bearer mnt_test_sk_..."
Response
{
"id": "pay_out_01XYZ",
"object": "payout",
"status": "confirmed",
"chain": "eth",
"to_address": "0x7a3f...0a1f",
"amount": "100.000000",
"currency": "USDT",
"tx_hash": "0xabc...def",
"confirmations": 12,
"confirmed_at": "2026-06-19T10:10:00Z",
"created_at": "2026-06-19T10:00:00Z"
}/v1/payoutsList payouts
Returns a paginated list of payouts ordered newest first.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| limit | number | optional | Max items per page (1–100, default 20). |
| starting_after | string | optional | Payout `id` cursor — start after this record. |
| status | string | optional | Filter by status: `pending`, `review_required`, `processing`, `confirmed`, `failed`, or `blocked`. |
Request
curl "https://api.nity0x.io/v1/payouts?limit=10&status=confirmed" \ -H "Authorization: Bearer mnt_test_sk_..."
Response
{
"object": "list",
"data": [
{
"id": "pay_out_01XYZ",
"object": "payout",
"status": "confirmed",
"chain": "eth",
"amount": "100.000000",
"currency": "USDT",
"tx_hash": "0xabc...def",
"confirmed_at": "2026-06-19T10:10:00Z",
"created_at": "2026-06-19T10:00:00Z"
}
],
"has_more": false
}Webhooks
1 min read
Receive real-time payment lifecycle events via HMAC-signed HTTP callbacks.
NITY0X delivers events to your endpoint over HTTPS. Each request carries a `nityox-signature` header for verification. Failed deliveries are retried up to 5× with exponential backoff (5s, 10s, 20s, 40s, 80s).
- ›Always verify the signature before processing — reject requests with invalid signatures.
- ›Respond with HTTP 2xx within 10 seconds to acknowledge. Slow handlers should queue work and respond immediately.
- ›Handle deliveries idempotently — retries carry the same event id.
- ›Endpoint URLs must use HTTPS and resolve to a public IP (private/RFC1918 addresses are blocked).
/v1/webhooksRegister endpoint
Register an HTTPS endpoint to receive payment and payout events. The `secret` is returned only once — store it securely.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| url | string | required | Public HTTPS URL to receive events. |
| events | string[] | optional | Event filter. Omit (or pass `[]`) to receive all events. |
Request
curl -X POST https://api.nity0x.io/v1/webhooks \ -H "Authorization: Bearer mnt_test_sk_..." \ -H "Content-Type: application/json" \ -d '{ "url": "https://yourapp.com/webhooks/nityox", "events": ["payment.confirmed", "payment.failed", "payout.confirmed"] }'
Response
{
"id": "wh_01ABC",
"object": "webhook_endpoint",
"url": "https://yourapp.com/webhooks/nityox",
"events": ["payment.confirmed", "payment.failed", "payout.confirmed"],
"active": true,
"secret": "whsec_xyz...",
"created_at": "2026-06-19T10:00:00Z"
}/v1/webhooksList endpoints
Returns all registered webhook endpoints for your merchant. Secrets are never returned after creation.
Request
curl https://api.nity0x.io/v1/webhooks \ -H "Authorization: Bearer mnt_test_sk_..."
Response
{
"object": "list",
"data": [
{
"id": "wh_01ABC",
"object": "webhook_endpoint",
"url": "https://yourapp.com/webhooks/nityox",
"events": ["payment.confirmed", "payment.failed"],
"active": true,
"created_at": "2026-06-19T10:00:00Z"
}
],
"has_more": false
}Verify webhook signature
Reconstruct the HMAC-SHA256 signature from the raw request body and timestamp, then compare with the `nityox-signature` header value using a timing-safe comparison.
Request
Not yet available in this language — showing cURL.
import crypto from "crypto"; export async function POST(req: Request) { const body = await req.text(); const sig = req.headers.get("nityox-signature") ?? ""; // Header format: t=<unix_ts>,v1=<hex_hmac> const parts = Object.fromEntries( sig.split(",").map((p) => p.split("=") as [string, string]) ); const expected = crypto .createHmac("sha256", process.env.NITYOX_WEBHOOK_SECRET!) .update(`${parts.t}.${body}`) .digest("hex"); const valid = crypto.timingSafeEqual( Buffer.from(parts.v1 ?? "", "hex"), Buffer.from(expected, "hex"), ); if (!valid) return new Response("Forbidden", { status: 403 }); const event = JSON.parse(body); // event.type: "payment.confirmed" | "payment.failed" | ... // event.data.object → serialized payment or payout return new Response("OK"); }
{
"id": "evt_01XYZ",
"object": "event",
"type": "payment.confirmed",
"livemode": false,
"created": 1718791530,
"data": {
"object": {
"id": "pay_01HXYZ",
"object": "payment",
"status": "confirmed",
"chain": "eth",
"amount": "25.000000",
"currency": "USDT",
"tx_hash": "0xabc...def",
"confirmations": 12,
"confirmed_at": "2026-06-19T10:05:30Z"
}
}
}Event type reference
All event types emitted by NITY0X. Subscribe to specific events when registering an endpoint.
Response
{
"payment.awaiting_payment": "Deposit address allocated; waiting for funds.",
"payment.pending": "First on-chain detection; waiting for confirmations.",
"payment.confirming": "Threshold reached; counting confirmation blocks.",
"payment.confirmed": "Fully confirmed — balance credited to merchant.",
"payment.expired": "TTL elapsed before payment was received.",
"payment.failed": "Unrecoverable error during processing."
}{
"payout.confirmed": "On-chain transfer confirmed.",
"payout.failed": "Transfer could not be completed.",
"payout.blocked": "Transfer was blocked by compliance controls."
}Errors
1 min read
NITY0X uses conventional HTTP status codes and a consistent error envelope.
Every error response has the same shape. The machine-readable `type` field is stable across releases — use it for programmatic handling rather than matching on `message` strings.
Error response shape
All API errors return this JSON envelope.
Response
{
"error": {
"type": "rate_limit_exceeded",
"message": "Too many requests. Please retry after 30 seconds.",
"status": 429,
"param": null
}
}Error code reference
Stable machine-readable error types returned in the `type` field. See the full error catalog for every code, grouped by category.
Response
{
"unauthorized": "Missing or invalid API key (401)",
"forbidden": "Key lacks permission for this action (403)",
"not_found": "Resource not found (404)",
"invalid_request_error": "Request body failed validation (400)",
"idempotency_conflict": "Same key reused with different params (409)",
"insufficient_balance": "Balance too low for payout (422)",
"chain_disabled": "Requested chain is not enabled (400)",
"rate_limit_exceeded": "Too many requests (429)",
"internal_server_error": "Unexpected server error — use request_id to report (500)"
}