Overview
https://nxtgatew.com
JSON API with UTF-8 encoding. CORS allows browser requests with the proper headers. Paths below are relative to the base URL.
Quick start
Get API credentials
At signup you receive an X-API-Key and X-API-Secret pair (merchant / PSP / admin).
Create a deposit wallet
Call POST /api/v1/wallets/create with your payout address, callback, and network.
Give the deposit address
Return data.address to the payer. Store ipn_token to verify callbacks.
Verify on EVM
Call GET /api/v1/wallets/check-config to confirm database vs on-chain split config.
curl -X POST "https://nxtgatew.com/api/v1/wallets/create" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_KEY" \
-H "X-API-Secret: YOUR_SECRET" \
-d '{
"address": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"callback": "https://your-site.com/webhooks/nxtgatew",
"network": "polygon",
"mode": "ephemeral"
}'
Authentication
Every merchant endpoint requires both headers:
X-API-Key: YOUR_KEY X-API-Secret: YOUR_SECRET
merchant, psp, or admin with status = active.
Missing or invalid credentials → HTTP 401.
Endpoints
All endpoints require X-API-Key + X-API-Secret.
Create deposit wallet
Creates or reuses a receive address controlled by the platform, tied to your account, with a callback URL and optional affiliate / sub-affiliate wallets. Client mode uses the same optional split fields (affiliate_address, affiliate_percent, subaff_address, subaff_percent) — send them on each POST /wallets/create, including when reusing a client_id.
Modes
| mode | Behavior |
|---|---|
ephemeral | Default. New deposit address on every call. |
client | Get-or-create by (account, network, client_id). Requires migration 015. Only one open inbound payment at a time (else 409). Response includes private_key for export / migration. |
Headers
| Parameter | Required | Type | Description |
|---|---|---|---|
X-API-Key | Yes | string | Your API key. |
X-API-Secret | Yes | string | Matching API secret. |
Content-Type | Yes | application/json | Request body must be JSON. |
Body
| Field | Required | Type | Description |
|---|---|---|---|
address | Yes | string | Merchant payout address (final destination after split). |
callback | Yes | URL | IPN / webhook URL. Alias: callback_url. |
network | No | ethereum · polygon · tron · solana | Default: ethereum. |
mode | No | ephemeral · client | Default: ephemeral. |
client_id | If client | string | Required when mode=client (1–128 chars). |
affiliate_address / affiliate_percent | No | string / number | Affiliate share as % of gross (e.g. 1 = 1%). Applies to ephemeral and client; on client reuse, updates DB when sent (otherwise keeps stored address / %). |
subaff_address / subaff_percent | No | string / number | Sub-affiliate share as % of gross. Same rules as affiliate fields. |
ipn_token | No | string | Your correlation token; otherwise platform generates 64 hex chars. |
transaction_id | No | string | Your payment / order id for this deposit (e.g. 183). Echoed in all wallet webhooks for this cycle. Alias: meta.transaction_id. Requires migration 024. |
meta | No | object | Optional metadata; meta.transaction_id is accepted like the root field. |
Success
201 new wallet · 200 client wallet reused (reused: true). Response includes address, ipn_token, wallet_mode, optional client_id, optional transaction_id (when sent on create), platform_percent, affiliate fields. In client mode only, private_key is also returned (plaintext deposit key for export / migration) — never returned for ephemeral wallets.
Verify split configuration
Returns database fields plus on-chain configuration (Ethereum / Polygon when the Node verification script is available).
Query parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
wallet_address | Yes | string | Deposit address from create (data.address). |
network | No | string | Default: polygon. Must match the wallet. |
Response includes database, on_chain, and match (true when on-chain merchant matches DB).
Webhooks
The callback URL receives POST JSON. If ipn_token was set, verify header X-IPN-Token.
When you send transaction_id on create, the same value is included on every webhook for that deposit cycle — use it to match IPNs to your internal order (especially client reusable wallets where wallet_id and client_id repeat).
| Event | When |
|---|---|
wallet.balance_changed | After each new indexed movement and ledger write. |
wallet.movements_snapshot | Once per sync cycle when movements are reconciled and split is complete. |
wallet.split_complete | After on-chain split succeeds (legacy split callback JSON). |
Common fields: wallet_id, deposit_address, ipn_token, wallet_mode, client_id (client mode), transaction_id (when provided on create).
Failed deliveries are retried via cron/dispatch-wallet-webhooks-web.php?token=… (same CRON_SECRET_TOKEN as other URL crons).
Content-Type: application/json X-IPN-Token: <ipn_token>
Common errors
| HTTP | Meaning |
|---|---|
| 400 | Invalid JSON, missing fields, unsupported network/mode, bad address/callback |
| 401 | Invalid or missing API credentials |
| 403 | Merchant account inactive |
| 404 | Wallet not found or not yours |
| 409 | Duplicate address, or client wallet still processing a previous deposit |
| 503 | transaction_id sent but migration 024 not applied |
| 500 | Wallet generation / DB / migration missing |
{
"success": false,
"error": "Human-readable message explaining the issue"
}
Wallet lifecycle
Explorer sync indexes deposits; split cron distributes to merchant / platform / affiliates. In client mode, reuse the same address only after the previous cycle reaches split. Send a new transaction_id on each POST /wallets/create so webhooks map to the correct merchant order.
NFT / SBT module
Self-serve NFT layer under /api/v1/nft/* for any registered merchant. Supported asset types: membership (soulbound), digital_license, order_receipt (one NFT per order), plus reward / certificate / collectible. It does not change POST /api/v1/wallets/create.
Sections below · OpenAPI tag NFT · API console
Collection NFT: Mode A mint, Mode B import, lifecycle, webhooks.
process-nft-operations-web.php (platform-managed in production).Mint modes A & B
Two complementary paths. Pick one per payment — never both for the same purchase (that would double-mint).
| Mode A — Platform mint | Mode B — External mint + import | |
|---|---|---|
| When | You confirm payment off-chain (card, on-ramp, invoice…), then ask NxtGateW to mint. | A third party already minted on-chain (payable SC call with your collection contract). |
| API | POST /api/v1/nft/nfts → 202 |
POST /api/v1/nft/nfts/import with tx_hash → indexes Transfer mint |
| On-chain actor | NxtGateW operator wallet | External minter (must be authorized on your contract if the SC uses a whitelist) |
| Truth signal | Webhook nft.minted after cron confirm |
Webhook nft.minted after successful import |
Mode A — typical flow
- Optional:
POST /wallets/createif you also settle native crypto to a deposit + split. POST /nft/wallets→ recipientwallet_id.- After payment confirmed →
POST /nft/nftswithIdempotency-Key= your order id. - Handle
nft.minted(or pollGET /operations/{id}).
Mode B — typical flow
- Collection
contract_addressset; external minter allowed on-chain if required. - External tx mints NFT to the user wallet (same contract as the collection).
POST /nft/nfts/importwithtx_hash,collection_id,asset_type, richattributes(name, order_ref, …).- Do not call
POST /nft/nftsfor that tx.
tokenURI (or attributes.name / description on import/mint). Explorers often ignore data: URIs. Suggested names: MembershipBronze_{user_id}, Order_{order_ref}.NFT quick start (Mode A)
Link wallet
POST /api/v1/nft/wallets with external_user_id (+ optional callback).
Create collection
POST /api/v1/nft/collections (membership / digital_license / order_receipt), then PATCH contract_address.
Mint (Mode A)
POST /api/v1/nft/nfts with Idempotency-Key → 202. Cron confirms mint.
Lifecycle
Activate / suspend / migrate / burn via POST /api/v1/nft/nfts/{id}/…. On-chain when token_id is set.
curl -X POST "$BASE/api/v1/nft/nfts" \
-H "Content-Type: application/json" \
-H "X-API-Key: KEY" -H "X-API-Secret: SECRET" \
-H "Idempotency-Key: order_89452_membership" \
-d '{
"asset_type": "membership",
"collection_id": "col_xxx",
"wallet_id": "wal_xxx",
"external_user_id": "usr_84521",
"external_reference": "order_89452",
"transfer_policy": "soulbound",
"attributes": {
"name": "MembershipBronze_usr_84521",
"membership_level": "bronze",
"user_id": "usr_84521"
}
}'
Mode B import example:
curl -X POST "$BASE/api/v1/nft/nfts/import" \
-H "Content-Type: application/json" \
-H "X-API-Key: KEY" -H "X-API-Secret: SECRET" \
-H "Idempotency-Key: import_0xabc…" \
-d '{
"tx_hash": "0x…",
"collection_id": "col_xxx",
"network": "polygon",
"asset_type": "order_receipt",
"external_user_id": "usr_84521",
"external_reference": "order_89452",
"attributes": {
"name": "Order_order_89452",
"order_ref": "order_89452",
"user_id": "usr_84521",
"amount_pol": "10.5",
"payment_rail": "external_checkout"
}
}'
NFT auth & HMAC
Same X-API-Key + X-API-Secret as deposit wallets. Write ops that create side effects also require Idempotency-Key.
Optional NxtGateW HMAC — if you send X-Api-Signature (or X-Signature), also send X-Timestamp (±5 min) and unique X-Nonce. Replay of a nonce → 401.
METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + NONCE + "\n" + SHA256(raw_body)
# HMAC-SHA256 hex with api_secret
# PATH example: /api/v1/nft/nfts
# macOS LibreSSL: use awk '{print $NF}' on openssl dgst -hex output
NFT endpoints (summary)
| Area | Paths |
|---|---|
| Wallets | POST/GET /nft/wallets, .../by-external-user/{id}, .../assets |
| Collections | CRUD-ish + /deploy, /pause, /unpause |
| NFTs | Mode A mint POST /nfts, Mode B POST /nfts/import, get, patch, lifecycle, history, by-token |
| Ops | GET /nft/operations/{operation_id} |
| Webhooks | POST/GET /nft/webhooks, POST .../test |
Paused collection → mint rejected. One active membership NFT per wallet (NFT_ALREADY_EXISTS).
NFT webhooks
Register with POST /api/v1/nft/webhooks (url, optional secret, subscribed_events). Manage with PATCH /webhooks/{id} (rotate_secret, status) or DELETE (soft-disable). Deliveries are signed:
X-NxtGateW-Event-Id: evt_… X-NxtGateW-Timestamp: <unix> X-NxtGateW-Signature: sha256=<HMAC(timestamp + "." + body, endpoint_secret)>
| Event | When |
|---|---|
nft.mint_pending | Mint queued |
nft.minted | Mode A cron confirm or Mode B import success |
nft.updated / nft.burned | Lifecycle changes |
nft.test | Manual test endpoint |
Local smoke catcher: /tools/webhook-catcher.php (writes logs/webhook-catcher.log). Prefer your own URL over httpbin (often times out).