Developers

Accept USDT with a single API call.

A small REST API, signed webhooks and a hosted checkout. Everything you need to take Solana USDT payments is on this page.

Overview

The flow is the same for every integration:

  1. Your server calls POST /deposit/initiate and gets back a unique Solana address and a hosted page_url.
  2. You send the customer to page_url (or show the address / QR yourself).
  3. The customer sends USDT. We confirm it on-chain and call your webhook.
  4. You mark the order paid. Funds settle to your wallet.

Base URL: https://api.hexpaid.com · All requests and responses are JSON over HTTPS.

Authentication

Sign up, then copy your API key from Dashboard → Developers. Send it in the X-API-Key header from your server — never from browser code.

X-API-Key: merch_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Keys are deliberately limited. An API key can create and read payments, balances and transactions. It cannot withdraw, change your settlement wallet or roll keys — those need a dashboard login and your password. If a key leaks, roll it in the dashboard and the old key stops working immediately.

Create a payment

POST /merchants/solana/deposit/initiate reserves a Solana address for 10 minutes and starts monitoring it.

FieldTypeDescription
expected_amountnumberOptional. USDT you expect. Enables partial / over-payment detection. Omit to accept any amount.
order_idstringOptional. Your order reference, returned in webhooks and visible in the dashboard.
deposit_idstring | numberOptional. Your own idempotency-style identifier, echoed back as merchant_deposit_id.
webhook_urlstringOptional. Overrides your account webhook for this payment. Must be https.
notesstringOptional. Free text for your records.
Request
curl -X POST https://api.hexpaid.com/merchants/solana/deposit/initiate \
  -H "X-API-Key: $HEXPAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "expected_amount": 25,
    "order_id": "ORD-1042"
  }'
{
  "deposit_id": 128,
  "status": "pending",
  "message": "Deposit initiated. Share the page URL with your customer.",
  "page_url": "https://api.swapuzi.com/merchants/solana/deposit/128/page",
  "address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
  "order_id": "ORD-1042",
  "expires_at": "2026-10-08T12:10:00Z",
  "created_at": "2026-10-08T12:00:00Z"
}

Payment lifecycle

statusMeaning
pendingAddress reserved; waiting for the customer’s transfer.
confirmedUSDT received. With an expected_amount this means the full amount arrived.
expiredThe 10-minute window ended with no (or insufficient) payment. The address is recycled.
failedThe payment could not be processed. Contact support with the deposit_id.

When an expected_amount is set, webhooks also carry payment_status: paid (exact), partial (less — keep waiting or top up) or overpaid (more — refund the difference if you wish).

Retrieve & list payments

Poll GET /merchants/solana/deposit/:id as a fallback to webhooks, or list payments with GET /merchants/solana/deposits (filters: status, limit ≤ 200, before_id for paging).

curl https://api.hexpaid.com/merchants/solana/deposit/128 \
  -H "X-API-Key: $HEXPAY_API_KEY"

Webhooks

Set an account-wide URL in Dashboard → Developers, or pass webhook_url per payment. URLs must be public https endpoints. Return any 2xx within 10 seconds to acknowledge; otherwise we retry after 5 s, 30 s and 2 min (4 attempts total). Every attempt appears in your delivery log.

EventSent when
deposit.confirmedThe full expected amount (or any amount, if none was set) is received.
deposit.partialLess than the expected amount has been received so far.
deposit.overpaidMore than the expected amount was received.
deposit.expiredThe payment window closed without completion.
deposit.failedProcessing failed.
webhook.testYou pressed “Send test event” in the dashboard.
HeaderValue
X-HexPay-EventEvent name, e.g. deposit.confirmed
X-HexPay-DeliveryUnique ID, identical across retries — use it to de-duplicate
X-HexPay-TimestampUnix seconds when the attempt was signed
X-HexPay-SignatureHex HMAC-SHA256 of "<timestamp>.<raw body>" with your webhook secret
{
  "event": "deposit.confirmed",
  "merchant_id": 42,
  "deposit_id": 128,
  "order_id": "ORD-1042",
  "tx_id": "5VqK…Zk",
  "solana_address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
  "amount": 25,
  "received_amount": 25,
  "expected_amount": 25,
  "payment_status": "paid",
  "status": "confirmed",
  "asset": "USDT",
  "timestamp": 1791460800
}

Webhooks may arrive more than once or out of order. Make your handler idempotent on deposit_id / X-HexPay-Delivery.

Verify signatures

Always verify the signature against the raw request body, compare in constant time, and reject timestamps older than five minutes to block replays.

import crypto from "node:crypto";

app.post("/webhooks/sonrails", express.raw({ type: "application/json" }), (req, res) => {
  const ts  = req.get("X-HexPay-Timestamp");
  const sig = req.get("X-HexPay-Signature");
  const expected = crypto.createHmac("sha256", process.env.HEXPAY_WEBHOOK_SECRET)
    .update(ts + "." + req.body).digest("hex");

  const valid = sig && sig.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
  if (!valid || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(401);

  const event = JSON.parse(req.body);
  if (event.event === "deposit.confirmed") markOrderPaid(event.order_id, event.tx_id);
  res.sendStatus(200); // acknowledge fast, do heavy work async
});

Settlement

Set the Solana wallet your USDT should land in under Dashboard → Settlement. Changing it needs your password and sends you an email alert.

  • Manual withdraw: move your balance to your wallet any time from the dashboard.
  • Auto-forward to TRC20: route Solana USDT to your Tron address through Binance.

SOL gas for settlement is sponsored — you never need to hold SOL.

Plugins

Ready-made plugins let you accept crypto on popular e-commerce platforms without writing code. Each one creates a payment for the order, redirects the customer to checkout and marks the order paid when the webhook arrives.

SComing soon

Shopify

Let Shopify customers pay in USDT at checkout, with orders marked paid automatically.

WComing soon

WooCommerce

A payment gateway for WooCommerce and WordPress stores, with automatic order updates.

WpComing soon

WordPress

Payment buttons and links you can drop into any page or post.

WxComing soon

Wix

Accept crypto on Wix stores and booking sites.

MComing soon

Magento

A checkout extension for Magento and Adobe Commerce.

PComing soon

PrestaShop

A payment module for PrestaShop merchants.

Don’t want to wait? Every platform that can show a link or run a small script can already take payments: create payment links from your dashboard, or call the API from your store’s backend as described above.

Errors & limits

HTTPMeaning
400Invalid body or parameter. The error field explains what to fix.
401Missing or invalid API key / token.
403The endpoint needs a dashboard login (not an API key), or a required password is wrong.
404Payment not found for your account.
429Too many attempts on login / registration endpoints. Wait a minute.
503All deposit addresses are briefly busy. Retry in a few seconds.

Errors are returned as { "error": "message" }.

Go-live checklist

  • Create a payment and send a small USDT amount to see it confirm
  • Receive and verify a webhook on your server (use “Send test event”)
  • Handle partial, overpaid and expired events
  • Store the API key and webhook secret in environment variables, not in source control
  • Set your settlement wallet