Introduction
The MagenPay API is built on REST. It uses standard HTTP verbs, returns JSON, and authenticates via bearer tokens. There is no SDK lock-in — anything that can speak HTTP can integrate with MagenPay.
https://api.magenpay.com. Use https://api.sandbox.magenpay.com for the sandbox environment. Quickstart
Three steps and you're charging customers in crypto.
- 1
Get a merchant token
Sign up at magenpay.com, complete onboarding, then generate a token from Dashboard → Developers → API Keys.
- 2
Create a payment
POST a payment request — receive a checkout URL.
- 3
Listen for webhooks
When payment confirms on-chain, we POST to your webhook endpoint with a signed payload.
Authentication
All requests authenticate with a bearer token in the Authorization header.
Authorization: Bearer YOUR_MERCHANT_TOKENTest vs live tokens
Sandbox tokens are prefixed with test_ — production tokens with live_. Both look like UUIDs.
Create order
Create a new payment order. The response contains a checkout URL you can redirect the customer to, plus an on-chain address they can pay directly.
Body parameters
| Field | Type | Description |
|---|---|---|
| amount* | number | Amount to charge in the chosen currency. |
| currency* | string | USDT · BNB · ETH · TRX |
| network* | string | BEP20 · TRC20 · ERC20 |
| redirect | string | URL to redirect the customer to after payment. |
| reference1 | string | Your internal order ID (max 80 chars). |
| expires_in | integer | Seconds until expiration (default 1800). |
* required
Request
curl "text-amber-300">-X POST https://api.magenpay.com/v1/create-order \
"text-amber-300">-H "Authorization: Bearer $MERCHANT_TOKEN" \
"text-amber-300">-H "Content-Type: application/json" \
"text-amber-300">-d '{
"amount": 100,
"currency": "USDT",
"network": "BEP20",
"redirect": "https://shop.example/return",
"reference1": "order-1234"
}'Response
{
300">"id": 12345,
300">"payment_id": 300">"pay_abc123xyz",
300">"status": 300">"NEW",
300">"amount": 100,
300">"currency": 300">"USDT",
300">"network": 300">"BEP20",
300">"address": 300">"0x1234567890abcdef1234567890abcdef12345678",
300">"expires_at": 300">"2025-04-22T15:30:00Z",
300">"checkout_url": 300">"https://pay.magenpay.com/c/pay_abc123xyz",
300">"created_at": 300">"2025-04-22T15:00:00Z"
}Retrieve order
curl https://api.magenpay.com/v1/get-order?payment_id=pay_abc123xyz \
"text-amber-300">-H 'Authorization: Bearer $MERCHANT_TOKEN'List orders
Returns up to 100 orders per page, sorted by created_at descending.
Cancel order
Webhooks
When a payment confirms on-chain we send a JSON payload to your merchant_webhook URL. Webhooks are signed, retried, and idempotent.
Event payload
{
300">"event": 300">"order.paid",
300">"id": 12345,
300">"payment_id": 300">"pay_abc123xyz",
300">"status": 300">"PAID",
300">"amount": 100,
300">"currency": 300">"USDT",
300">"network": 300">"BEP20",
300">"txid": 300">"0xabcdef...",
300">"block_number":42_000_000,
300">"confirmed_at": 300">"2025-04-22T15:02:18Z"
}Signature verification
Every request includes an X-MagenPay-Signature header with the HMAC-SHA256 of the raw body. Always compare in constant time.
"text-fuchsia-300">import crypto "text-fuchsia-300">from 'node:crypto'
"text-fuchsia-300">function verify(rawBody, header, secret) {
"text-fuchsia-300">const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex')
"text-fuchsia-300">return crypto.timingSafeEqual(
Buffer."text-fuchsia-300">from(header),
Buffer."text-fuchsia-300">from(`sha256=${expected}`)
)
}Retries & idempotency
- ✓ Retried with exponential backoff for up to 72 hours on non-2xx responses.
- ✓ Each delivery includes
Idempotency-Key— your handler should be safe to retry. - ✓ Failures surface in Dashboard → Webhooks with full request/response history.
Errors
Errors return a stable machine-readable code plus a human-readable message.
| HTTP | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Required field missing or malformed. |
| 401 | unauthorized | Token missing, malformed, or revoked. |
| 404 | not_found | Resource does not exist or is not yours. |
| 409 | conflict | State transition not allowed (e.g. cancel a paid order). |
| 429 | rate_limited | Too many requests. Inspect Retry-After. |
| 500 | server_error | Transient — safe to retry with idempotency. |
Rate limits
Default: 100 req / minute / token. Bursts up to 200 are allowed via token bucket. We expose the standard headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1714053600Testing & sandbox
The sandbox at api.sandbox.magenpay.com mirrors production but settles testnet stablecoins. Use it to test integration end-to-end before going live.
Changelog
2025-04-22Polygon & Arbitrum live. Two new low-fee networks now selectable innetwork.2025-04-08Webhook v2. Signed payloads + idempotency keys. Migration guide on the blog.2025-01-15v1 stabilized. Initial public release of the REST API.