Quick Start
Go from zero to accepting USDT payments in under 5 minutes. This guide walks through registering a merchant account, generating an API key, creating a payment order, and receiving a webhook notification.
Register as a merchant
Create a merchant account by posting to /v1/merchants. You'll receive a merchant_id that identifies your account in all subsequent requests.
curl -X POST https://api.mpchat.com/v1/merchants \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Store",
"email": "[email protected]"
}'{
"id": "mer_01HQ...",
"name": "Acme Store",
"email": "[email protected]",
"status": "PENDING_KYB",
"tier": "BASIC",
"environment": "test",
"created_at": "2024-01-15T10:00:00Z"
}⚠️ KYB Required for Live Payments
PENDING_KYB status. You can test with sandbox keys immediately, but live payments require KYB verification. Contact support to start the process.Generate an API key
Generate your first API key. The response includes both key_id (public) and secret (private). Store the secret safely — it is only shown once.
curl -X POST https://api.mpchat.com/v1/merchants/api-keys \
-H "Authorization: Bearer {session_token}" \
-H "Content-Type: application/json" \
-d '{"name": "Production Key", "environment": "live"}'{
"key_id": "mk_live_01HQ...",
"secret": "sk_live_a1b2c3d4e5f6...",
"name": "Production Key",
"environment": "live",
"created_at": "2024-01-15T10:01:00Z"
}🚨 Save your secret immediately
secret value is shown only once and cannot be retrieved again. Store it in an environment variable or secrets manager before closing this response.Use mk_test_ prefix keys for sandbox testing — they behave identically but don't require real blockchain transactions.
Create a payment order
Create an order specifying the amount in USDT and the preferred network. The API returns a payment_url — redirect your customer there.
curl -X POST https://api.mpchat.com/v1/orders \
-H "Authorization: Bearer mk_live_01HQ...:{timestamp}:{signature}" \
-H "Content-Type: application/json" \
-d '{
"amount": "99.99",
"currency": "USDT",
"network": "TRC20",
"description": "Pro Plan - Monthly",
"return_url": "https://acme.com/payment/return",
"webhook_url": "https://acme.com/webhooks/mpchat"
}'{
"id": "ord_01HQ...",
"order_number": "ord_a1b2c3",
"status": "OPEN",
"order_amount": "99.99",
"received_amount": "0.00",
"currency": "USDT",
"network": "TRC20",
"payment_url": "https://pay.mpchat.com/pay/ord_01HQ...",
"expire_at": "2024-01-15T10:31:00Z",
"created_at": "2024-01-15T10:01:00Z"
}Redirect the customer
Redirect your customer to the payment_url. MPChat hosts the entire checkout experience — displaying the USDT address, QR code, amount, and countdown timer.
// After creating the order:
window.location.href = order.payment_url;💡 Mobile & bot integration
Handle the webhook
When the customer pays, MPChat sends a payment.confirmed event to yourwebhook_url. Verify the signature before processing.
const crypto = require('crypto');
app.post('/webhooks/mpchat', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-merchant-signature'];
const [tPart, v1Part] = sig.split(',');
const timestamp = tPart.replace('t=', '');
const receivedHash = v1Part.replace('v1=', '');
const payload = `${timestamp}.${req.body.toString()}`;
const expected = crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(payload)
.digest('hex');
if (expected !== receivedHash) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
if (event.event === 'payment.confirmed') {
// Fulfill the order: event.data.order_id
console.log('Payment confirmed:', event.data.order_id);
}
res.status(200).send('OK');
});Poll order status (alternative)
If you prefer polling over webhooks, check order status with a GET request. Poll at most every 5 seconds.
curl https://api.mpchat.com/v1/orders/ord_01HQ... \
-H "Authorization: Bearer mk_live_01HQ...:{timestamp}:{signature}"Order statuses
| Status | Description |
|---|---|
PENDING | Order created, address not yet assigned |
OPEN | Address assigned, awaiting payment |
CONFIRMING | Transaction detected, waiting for confirmations |
PAID | Payment confirmed — fulfill the order |
EXPIRED | Order expired with no payment received |
EXPIRED_PAID | Payment received after expiry — contact support |
UNDERPAID | Payment received but amount is insufficient |
FROZEN | Order flagged for compliance review |
GET /v1/orders/{id}/events. See the Payment Integration guide.Next steps
- Payment Integration — mobile apps, bots, SSE updates
- Webhooks — full event reference and retry policy
- API Reference — every endpoint documented