CoinWerx API Reference
Accept cryptocurrency payments from anywhere in the world.
The CoinWerx Payment Gateway API allows merchants to generate unique cryptocurrency deposit addresses, track payment status in real time, receive webhook notifications on confirmation, and query live coin prices — all through a simple REST interface.
Authentication
All merchant endpoints require your API key passed as a Bearer token in the Authorization header. Your API key is issued when your merchant account is created.
Authorization: Bearer cw_your_api_key_here
Error Codes
| HTTP Status | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad Request — missing or invalid parameters |
| 401 | Unauthorized — missing or invalid API key |
| 403 | Forbidden — merchant account is disabled |
| 404 | Not Found — resource does not exist |
| 429 | Too Many Requests — rate limit exceeded |
| 500 | Internal Server Error |
| 503 | Service Unavailable — price feed or blockchain service temporarily down |
All error responses include a JSON body with an error field describing the issue:
{ "error": "Missing required field: asset" }
Supported Assets
Pass the Symbol exactly as shown below in the asset field of payment requests. All stablecoins are pegged 1:1 to USD — the network variant determines which blockchain the deposit address is generated on.
Prices
Returns live USD prices (and optional fiat currency) for every supported asset. Prices are cached for 60 seconds and sourced from CoinGecko.
| Parameter | Type | Description |
|---|---|---|
| currencyoptional | string | Fiat currency for prices. Default: USD. Supported: USD, EUR, GBP, CAD, AUD, JPY, CHF |
GET https://coinwerx.com/api/prices?currency=USD Authorization: Bearer cw_your_api_key
{
"currency": "USD",
"prices": {
"BTC": { "price": 84250.00, "change_24h": 1.23, "last_updated": "2026-04-16T02:00:00.000Z" },
"ETH": { "price": 1598.40, "change_24h": -0.87, "last_updated": "2026-04-16T02:00:00.000Z" },
"USDT-ERC20": { "price": 1.00, "change_24h": 0.01, "last_updated": "..." },
...
},
"supported_assets": ["BTC","ETH","LTC","BNB","TRX","XRP","SOL","MATIC","USDT-ERC20","USDT-TRC20","USDT-BEP20","USDC-ERC20","USDC-SOL","USDC-MATIC","USDC-ARB"],
"cache": { "age_seconds": 12, "ttl_seconds": 60 }
}
| Parameter | Type | Description |
|---|---|---|
| assetrequired | string | Asset symbol, e.g. BTC, USDT-TRC20 |
GET https://coinwerx.com/api/prices/BTC Authorization: Bearer cw_your_api_key
{
"asset": "BTC",
"name": "Bitcoin",
"price": 84250.00,
"currency": "USD",
"change_24h": 1.23,
"last_updated": "2026-04-16T02:00:00.000Z"
}
Convert any amount between fiat and crypto (or crypto to crypto) using live prices.
| Field | Type | Description |
|---|---|---|
| fromrequired | string | Source currency, e.g. USD or BTC |
| torequired | string | Target currency, e.g. BTC or USD |
| amountrequired | number | Amount to convert (must be positive) |
POST https://coinwerx.com/api/prices/convert
Authorization: Bearer cw_your_api_key
Content-Type: application/json
{ "from": "USD", "to": "BTC", "amount": 100 }
{
"from": "USD",
"to": "BTC",
"input_amount": 100,
"output_amount": 0.00118694,
"rate": 84250.00,
"last_updated": "2026-04-16T02:00:00.000Z"
}
Payments
Creates a new payment intent and returns a unique cryptocurrency deposit address. The customer sends funds to this address. CoinWerx monitors the blockchain and fires a webhook to your webhook_url when the payment is detected and again when it is confirmed.
amount_fiat or amount_crypto (or both). If only amount_fiat is provided, the live price is used to calculate the exact crypto amount the customer must send.
| Field | Type | Description |
|---|---|---|
| assetrequired | string | Asset symbol from the supported assets list, e.g. BTC, USDT-TRC20 |
| webhook_urlrequired | string | Your HTTPS endpoint to receive payment event notifications |
| amount_fiatoptional* | number | Amount in fiat currency (e.g. 100 for $100 USD). Auto-converts to crypto using live price. |
| fiat_currencyoptional | string | Fiat currency code. Default: USD |
| amount_cryptooptional* | number | Exact crypto amount to request (e.g. 0.0015 BTC) |
| external_refoptional | string | Your internal order/invoice ID for reconciliation |
| labeloptional | string | A short, human-readable name you assign to help identify this payment in your merchant dashboard (e.g. "John Smith — Premium Plan"). Unlike external_ref which is machine-facing, label is purely for your own recognition. |
| descriptionoptional | string | Human-readable payment description |
| expires_minutesoptional | integer | Payment expiry in minutes. Default: 60 |
POST https://coinwerx.com/api/payments
Authorization: Bearer cw_your_api_key
Content-Type: application/json
{
"asset": "BTC",
"amount_fiat": 100,
"fiat_currency": "USD",
"external_ref": "ORDER-12345",
"webhook_url": "https://yourstore.com/webhooks/coinwerx",
"description": "Order #12345 — Premium Plan"
}
{
"asset": "USDT-TRC20",
"amount_crypto": 50,
"external_ref": "INV-9981",
"webhook_url": "https://yourstore.com/webhooks/coinwerx"
}
{
"id": "5937ae30-addd-4c9e-b28b-0a45afc8e3c0",
"status": "pending",
"asset": "BTC",
"network": "mainnet",
"address": "bc1qdggn96y6w6wz94e2uk8364wa7m0xqd9dvky6zj",
"amount_fiat": "100.00",
"amount_crypto": "0.00118694",
"fiat_currency": "USD",
"live_price_used": 84250.00,
"external_ref": "ORDER-12345",
"expires_at": "2026-04-16T03:00:00.000Z",
"instructions": "Send BTC to the address above. Payment confirmed after 2 block confirmation(s)."
}
| Parameter | Type | Description |
|---|---|---|
| idrequired | string (UUID) | Payment intent ID returned from the create endpoint |
| Status | Meaning |
|---|---|
pending | Awaiting payment — no transaction detected yet |
detected | Transaction seen on-chain, awaiting confirmations |
confirmed | Required confirmations reached — payment complete |
expired | Payment window closed with no transaction |
underpaid | Transaction received but amount was less than required |
GET https://coinwerx.com/api/payments/5937ae30-addd-4c9e-b28b-0a45afc8e3c0 Authorization: Bearer cw_your_api_key
| Parameter | Type | Description |
|---|---|---|
| statusoptional | string | Filter by status: pending, confirmed, expired, etc. |
| assetoptional | string | Filter by asset, e.g. BTC |
| limitoptional | integer | Results per page. Default: 50, Max: 200 |
| offsetoptional | integer | Pagination offset. Default: 0 |
GET https://coinwerx.com/api/payments?status=confirmed&limit=20 Authorization: Bearer cw_your_api_key
Ledger
GET https://coinwerx.com/api/ledger/balance Authorization: Bearer cw_your_api_key
{
"merchant": "Your Store Name",
"balances": {
"BTC": { "available": "0.00350000", "pending": "0.00118694" },
"USDT-TRC20": { "available": "250.000000", "pending": "0.000000" }
}
}
| Parameter | Type | Description |
|---|---|---|
| assetoptional | string | Filter by asset |
| limitoptional | integer | Results per page. Default: 50 |
| offsetoptional | integer | Pagination offset |
GET https://coinwerx.com/api/ledger/history?asset=BTC&limit=10 Authorization: Bearer cw_your_api_key
Webhook Events
CoinWerx sends a POST request to your webhook_url when payment or withdrawal events occur. Your endpoint must respond with HTTP 200 within 10 seconds.
payment_id and amount against your own records before fulfilling an order. Do not rely solely on the webhook payload.
payment.detected
Fired when a transaction to the deposit address is first seen on-chain (0 confirmations). Use this to show a "payment received, awaiting confirmation" message to your customer.
{
"event": "payment.detected",
"payment_id": "5937ae30-addd-4c9e-b28b-0a45afc8e3c0",
"external_ref": "ORDER-12345",
"asset": "BTC",
"amount": 0.00118694,
"tx_hash": "a1b2c3d4e5f6...",
"confirmations": 0,
"timestamp": "2026-04-16T02:05:00.000Z"
}
payment.received
Fired each time a confirmed on-chain receipt is credited to a payment — including partial payments. amount_received is the amount credited in this specific receipt only — add it to your own running total on your side. platform_fee is the CoinWerx fee deducted from this receipt. amount_net is what you receive after fees for this receipt. tx_hash is the on-chain hash for this specific receipt. tx_hashes is the full ordered list of all TX hashes received on this intent so far. transaction_count is the total number of on-chain receipts credited to this intent. explorer_url is a direct link to the transaction on the appropriate block explorer. If a customer sends funds in multiple transactions, this event fires for each one — always starting at transaction_count: 1.
{
"event": "payment.received",
"payment_id": "5937ae30-addd-4c9e-b28b-0a45afc8e3c0",
"external_ref": "ORDER-12345",
"asset": "USDT-BEP20",
"network": "BSC",
"amount_received": 30.00,
"platform_fee": 0.90,
"amount_net": 29.10,
"tx_hash": "a1b2c3d4e5f6...",
"tx_hashes": ["a1b2c3d4e5f6..."],
"transaction_count": 1,
"explorer_url": "https://bscscan.com/tx/a1b2c3d4e5f6...",
"confirmed_via": "balance_polling",
"timestamp": "2026-04-16T02:25:00.000Z"
}
payment.confirmed
Fired when the total amount received meets or exceeds the expected amount and the required number of block confirmations is reached. This is the event to use for fulfilling orders. If the full amount arrives in a single transaction, only payment.confirmed fires — no preceding payment.received. If it arrives in multiple transactions, each partial receipt fires payment.received and the final receipt that completes the payment fires payment.confirmed. amount_received is the amount of this final confirming receipt only — add it to your running total. tx_hash is the on-chain hash of the final confirming receipt. tx_hashes contains all TX hashes received on this intent. transaction_count is the total number of on-chain receipts. explorer_url is a direct link to the confirming transaction on the appropriate block explorer.
{
"event": "payment.confirmed",
"payment_id": "5937ae30-addd-4c9e-b28b-0a45afc8e3c0",
"external_ref": "ORDER-12345",
"asset": "USDT-BEP20",
"network": "BSC",
"amount_received": 20.00,
"platform_fee": 0.60,
"amount_net": 19.40,
"tx_hash": "def456abc789...",
"tx_hashes": ["a1b2c3d4e5f6...", "def456abc789..."],
"transaction_count": 2,
"explorer_url": "https://bscscan.com/tx/def456abc789...",
"confirmed_via": "balance_polling",
"timestamp": "2026-04-16T02:45:00.000Z"
}
withdrawal.pending
Fired immediately when a withdrawal request is accepted and the record is created. Use this to acknowledge the withdrawal in your system before broadcast begins.
{
"event": "withdrawal.pending",
"withdrawal_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"external_ref": "payout-2026-001",
"label": "Weekly supplier payment",
"asset": "USDT-TRC20",
"amount": 500,
"destination": "TXyz1234...",
"timestamp": "2026-04-16T12:00:00.000Z"
}
withdrawal.completed
Fired when the withdrawal transaction is confirmed on-chain. This is the definitive signal that funds have been delivered to the destination address. Always use this event — not withdrawal.broadcasting — to mark a payout as settled in your system.
{
"event": "withdrawal.completed",
"withdrawal_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"external_ref": "payout-2026-001",
"label": "Weekly supplier payment",
"asset": "USDT-TRC20",
"amount": "500.00000000",
"destination": "TXyz1234...",
"tx_hash": "abc123def456...",
"explorer_url": "https://tronscan.org/#/transaction/abc123def456...",
"timestamp": "2026-04-16T12:18:00.000Z"
}
withdrawal.failed
Fired when the broadcast to the network fails. The merchant's balance is automatically restored in full before this event is sent.
{
"event": "withdrawal.failed",
"withdrawal_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"external_ref": "payout-2026-001",
"label": "Weekly supplier payment",
"asset": "USDT-TRC20",
"amount": 500,
"destination": "TXyz1234...",
"error": "Insufficient funds for network fee",
"timestamp": "2026-04-16T12:00:45.000Z"
}
label field is only present when one was supplied in the original withdrawal request. Always check for its presence before using it.
Fee Estimation
Before submitting a withdrawal, call this endpoint to retrieve the estimated platform fee and network fee for a given asset and amount. This lets you display a full cost breakdown to your users before funds are committed.
asset field must include the network suffix for USDT and USDC. Use "USDT-ERC20", "USDT-TRC20", "USDC-ERC20", etc. Bare symbols like "USDT" or "USDC" will be rejected with a 400 error listing the valid options. This same rule applies to POST /api/withdrawals.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| asset | string | required | Asset symbol including network suffix. e.g. "BTC", "USDT-ERC20", "USDC-TRC20" |
| amount | number | required | The exact amount the destination will receive (not including fees) |
| destination_address | string | optional | If provided, the address format is validated against the asset's chain before the estimate is calculated. If the address is invalid, the call returns HTTP 400 with an error message. If valid, the estimate proceeds normally — no additional field is added to the response. |
Response Fields
| Field | Type | Description |
|---|---|---|
| asset | string | The asset symbol as submitted |
| amount | number | The send amount as submitted |
| platform_fee | string | CoinWerx platform fee, e.g. "0.75 USDC-ERC20" |
| estimated_network_fee | string | Estimated on-chain gas/network fee, e.g. "0.0012 USDC-ERC20" |
| total_required | string | Total balance needed to complete the withdrawal (amount + platform_fee + network_fee) |
| balance_available | string | Your current ledger balance for this asset |
| sufficient_balance | boolean | true if your balance covers total_required, false if not |
Response Codes
| Code | Meaning |
|---|---|
| 200 | Success. Fee estimate returned. If destination_address was provided, it passed format validation. |
| 400 | Request rejected. Check the error field in the response body. Common causes: missing required field, unsupported asset, ambiguous stablecoin symbol (e.g. "USDC" instead of "USDC-ERC20"), or invalid address format. |
| 401 | Missing or invalid API key. |
| 500 | Server error. Try again. If it persists, contact support. |
POST /api/estimate-fee
Authorization: Bearer cwx_your_api_key
Content-Type: application/json
{
"asset": "USDC-ERC20",
"amount": 75,
"destination_address": "0x0826095914873c4c1b1bfa73554829b588144a8b"
}
{
"asset": "USDC-ERC20",
"amount": 75,
"platform_fee": "0.75 USDC-ERC20",
"estimated_network_fee": "0.0012 USDC-ERC20",
"total_required": "75.7512 USDC-ERC20",
"balance_available": "120.50 USDC-ERC20",
"sufficient_balance": true
}
HTTP 400
{
"error": "Invalid destination address format for ETH network. Please check the address and try again."
}
HTTP 400
{
"error": "\"USDC\" is ambiguous — please specify the network. Valid symbols: \"USDC-ERC20\", \"USDC-TRC20\", \"USDC-BEP20\", \"USDC-SOL\", \"USDC-MATIC\""
}
Withdrawals
The Withdrawals API allows merchants to send funds from their CoinWerx ledger balance to any external wallet address on-chain. The destination receives exactly the amount requested — platform and network fees are charged separately on top from the merchant's balance.
amount + $1.00 platform fee + estimated network fee before a withdrawal can be submitted. The exact fee breakdown is returned in the error response if the balance is insufficient.
Initiates an on-chain transfer of the specified amount to the destination address. The ledger is debited immediately and the transaction is broadcast via Tatum. If the broadcast fails, the full balance is automatically restored.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| asset | string | Yes | Asset to withdraw, e.g. BTC, USDT-TRC20 |
| amount | number | Yes | Exact crypto amount to send to destination |
| destination_address | string | Yes | External wallet address to receive funds |
| external_ref | string | No | Your internal reference ID (e.g. payout-001) |
| label | string | No | A short, human-readable name you assign to help identify this withdrawal in your merchant dashboard (e.g. "Weekly supplier payment"). Unlike external_ref which is machine-facing, label is purely for your own recognition. |
| webhook_urlrequired | string | Yes | Your HTTPS endpoint to receive withdrawal event notifications (withdrawal.pending, withdrawal.broadcasting, withdrawal.completed) |
Example Request
POST /api/withdrawals
Authorization: Bearer cw_your_api_key
Content-Type: application/json
{
"asset": "USDT-TRC20",
"amount": 500,
"destination_address": "TXyz1234...",
"webhook_url": "https://yoursite.com/webhooks/coinwerx",
"external_ref": "payout-2026-001",
"label": "Weekly supplier payment"
}
Example Response
{
"success": true,
"withdrawal": {
"id": "a1b2c3d4-...",
"status": "broadcasting",
"asset": "USDT-TRC20",
"amount_sent": 500,
"destination_address": "TXyz1234...",
"tx_hash": "abc123def456...",
"platform_fee": "1.00 USDT",
"platform_fee_usd": "$1.00",
"estimated_network_fee": "1.0 TRX",
"total_deducted": "502.00 USDT",
"external_ref": "payout-2026-001",
"label": "Weekly supplier payment",
"created_at": "2026-04-16T12:00:00.000Z",
"message": "500 USDT-TRC20 sent. Awaiting 20 confirmation(s)."
}
}
Withdrawal Status Values
| Status | Meaning |
|---|---|
pending | Created, awaiting broadcast |
broadcasting | Transaction submitted to network |
completed | Required confirmations reached |
failed | Broadcast failed — balance restored automatically |
GET /api/withdrawals/a1b2c3d4-... Authorization: Bearer cw_your_api_key
Returns the full withdrawal record including current status, tx_hash, and fee breakdown.
Query Parameters
| Parameter | Description |
|---|---|
| status | Filter by status: pending, broadcasting, completed, failed |
| asset | Filter by asset, e.g. BTC |
| limit | Number of results (default 20) |
| offset | Pagination offset (default 0) |
GET /api/withdrawals?status=completed&asset=USDT-TRC20&limit=50 Authorization: Bearer cw_your_api_key
Batch Payouts
Batch Payouts allow you to send multiple withdrawals in a single API call. Instead of looping through individual
POST /api/withdrawals requests, you submit an array of recipients and CoinWerx processes each payout atomically — all from the same asset balance in your ledger.
How It Works
A batch payout request specifies a single asset and an array of recipients, each with their own destination address, amount, and optional reference. CoinWerx validates the total required balance (sum of all amounts + fees) before processing any individual payout. If the total balance is insufficient, the entire batch is rejected with a detailed breakdown.
Each recipient in the batch generates an individual withdrawal record, so you can track the status of each payout independently via GET /api/withdrawals/:id. A batch-level status endpoint lets you check the overall progress of the entire submission.
Fee Model for Batches
Each recipient in a batch is charged the same fee structure as a single withdrawal:
| Fee | Amount | Notes |
|---|---|---|
| Platform fee | $1.00 per recipient | Converted to the withdrawal asset at live rate |
| Network fee | Estimated per recipient | Actual fee deducted at broadcast; excess refunded |
| Transaction fee | 0.5% on inbound payments | Already deducted when payments confirmed — not charged again on withdrawal |
(500 × 10) + ($1.00 × 10 platform fees) + (1 TRX × 10 network fees) = 5,010 USDT + 10 TRX in your ledger.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| asset | string | Yes | Asset for all payouts in this batch, e.g. USDT-TRC20 |
| recipients | array | Yes | Array of recipient objects (max 100 per batch) |
| recipients[].address | string | Yes | Destination wallet address |
| recipients[].amount | number | Yes | Exact crypto amount to send to this recipient |
| recipients[].external_ref | string | No | Your reference for this individual payout |
| external_ref | string | No | Your internal reference ID for the entire batch (e.g. "batch-2026-04") |
| label | string | No | A short, human-readable name you assign to help identify this batch in your merchant dashboard (e.g. "April affiliate payouts"). Unlike external_ref which is machine-facing, label is purely for your own recognition and will appear in the dashboard transaction listing. |
| webhook_url | string | No | Webhook URL for batch-level status updates |
Example Request
POST /api/batch-payouts
Authorization: Bearer cw_your_api_key
Content-Type: application/json
{
"asset": "USDT-TRC20",
"recipients": [
{ "address": "TXyz1111...", "amount": 250.00, "external_ref": "affiliate-001" },
{ "address": "TXyz2222...", "amount": 500.00, "external_ref": "affiliate-002" },
{ "address": "TXyz3333...", "amount": 125.50, "external_ref": "affiliate-003" }
],
"webhook_url": "https://yoursite.com/webhooks/payouts"
}
Example Response
{
"success": true,
"batch_id": "b9f3e2a1-...",
"status": "processing",
"asset": "USDT-TRC20",
"total_recipients": 3,
"total_amount": 875.50,
"total_fees_usd": "$3.00",
"withdrawals": [
{ "id": "w1a2b3...", "address": "TXyz1111...", "amount": 250.00, "status": "broadcasting" },
{ "id": "w4d5e6...", "address": "TXyz2222...", "amount": 500.00, "status": "broadcasting" },
{ "id": "w7f8g9...", "address": "TXyz3333...", "amount": 125.50, "status": "broadcasting" }
],
"created_at": "2026-04-16T12:00:00.000Z"
}
Returns the status of the entire batch and a summary of each individual withdrawal within it.
GET /api/batch-payouts/b9f3e2a1-... Authorization: Bearer cw_your_api_key
Batch Status Values
| Status | Meaning |
|---|---|
processing | Batch accepted, payouts being broadcast |
partial | Some payouts completed, others still in progress |
completed | All payouts confirmed on-chain |
failed | All payouts failed — balances fully restored |
POST /api/batch-payouts endpoint will be available in the next release. Individual withdrawals via POST /api/withdrawals are fully live today.