Integration Guide
This guide explains how to integrate MiraclePay into your application to accept cryptocurrency payments. The External Payments API (base path /external/v1) lets you create payment requests programmatically and redirect customers to a hosted checkout page. All requests are signed with your API key — see Authentication.
Merchant partners can also create payments for assigned merchants and use signed reporting routes under /external/partner; see Merchant-Partner API. This guide reflects the current backend controller, DTO, authentication, idempotency and webhook implementations as reviewed on 2026-09-14.
Contents:
Quick Start
Create an API key in the merchant panel under Settings → Developer → API Keys — you get a key ID (
mpay_pk_...), a secret (mpay_sk_..., shown only once) and a passphraseSign your requests with HMAC-SHA512 — see Authentication
Create a payment prompt via
POST /external/v1/payments/prompt— amounts are in cents (1099= $10.99). Networks are optional: omitblockchainIdsand the customer is offered everything your account can be paid on — see External Payments APIRedirect your customer to the returned
checkoutUrlConfirm the outcome via Webhooks or
GET /external/v1/payments/:id— never from redirect query parameters
import { createHmac, randomUUID } from "node:crypto";
const BASE_URL = "https://api.miraclecash.info";
async function createPayment(idempotencyKey: string) {
// Persist one key per intended payment and pass it again on retries.
const method = "POST";
const path = "/external/v1/payments/prompt";
const rawBody = JSON.stringify({
amount: 1099, // $10.99 in cents
});
const timestamp = Math.floor(Date.now() / 1000).toString();
const nonce = randomUUID();
const signature = createHmac("sha512", process.env.MPAY_SECRET!)
.update([timestamp, nonce, method, path, rawBody].join("\n"))
.digest("hex");
const response = await fetch(`${BASE_URL}${path}`, {
method,
headers: {
"Content-Type": "application/json",
"X-MP-KEY-ID": process.env.MPAY_KEY_ID!,
"X-MP-PASSPHRASE": process.env.MPAY_PASSPHRASE!,
"X-MP-TIMESTAMP": timestamp,
"X-MP-NONCE": nonce,
"X-MP-SIGNATURE": signature,
"Idempotency-Key": idempotencyKey,
},
body: rawBody,
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.errorCode}: ${error.message}`);
}
const { prompt, checkoutUrl } = await response.json();
// Redirect your customer to checkoutUrl
}