Redirect to Checkout
After creating a payment prompt, redirect your customer to the MiraclePay hosted checkout page where they can complete the payment.
Checkout URL Structure
The checkoutUrl returned from the Create Payment Prompt API depends on your account type. For standard accounts it has this format:
https://checkout.miraclecash.info/?sessionId=<prompt.id>
Example:
https://checkout.miraclecash.info/?sessionId=550e8400-e29b-41d4-a716-446655440000
US merchant accounts receive a different format:
https://checkout.miraclecash.info/checkout/pay/<prompt.id>
Note
Always redirect to the checkoutUrl value returned by the API — never construct the URL yourself. The host or format may change; the returned value is authoritative.
Redirect Methods
Server-Side Redirect (Recommended)
Redirect the user from your backend after creating the payment:
Node.js / Express:
app.post('/checkout', async (req, res) => {
// createPayment wraps POST /external/v1/payments/prompt (amount in cents)
const { prompt, checkoutUrl } = await createPayment(
req.body.amountCents,
['eth-usdc']
);
// Store payment ID with order
await Order.update(req.body.orderId, {
paymentPromptId: prompt.id
});
// Redirect to checkout
res.redirect(checkoutUrl);
});
Client-Side Redirect
If your frontend calls your API, return the checkout URL for client-side redirect:
API Response:
{
"success": true,
"checkoutUrl": "https://checkout.miraclecash.info/?sessionId=550e8400..."
}
Frontend JavaScript:
async function handlePayment() {
const response = await fetch('/api/create-payment', {
method: 'POST',
body: JSON.stringify({ amountCents: 5000, orderId: 'ORD-123' }),
});
const { checkoutUrl } = await response.json();
// Redirect to MiraclePay checkout
window.location.href = checkoutUrl;
}
Warning
Never call the External Payments API from the browser — the API secret must stay on your backend. The frontend should only ever receive the checkoutUrl.
Checkout Flow
Once redirected, the customer experiences this flow:
Your Site ──► MiraclePay Checkout ──► Select Wallet ──► Connect Wallet
│
▼
Confirm Payment
│
▼
Transaction Status
/ \
Success Failed
│ │
▼ ▼
Payment Complete Retry/Cancel
Checkout Page Features:
Wallet Selection: Customer chooses their crypto wallet
Amount Display: Shows payment amount in USD and crypto equivalent
QR Code: For mobile wallet scanning
Transaction Confirmation: Real-time status updates
Expiration Timer: Shows remaining time to complete payment
Note
On US merchant accounts the checkout steps differ: the customer verifies their email, picks a network, and sends the displayed amount to the shown deposit address. The outcome is reported through the same payment statuses and webhooks.
Post-Payment Handling
Automatic Redirect (Recommended)
If you provide a redirectUrl when creating the payment prompt, MiraclePay will redirect the customer back to your site after payment:
Successful payment: Customer is auto-redirected after 5 seconds, with a "Return to store" button for immediate redirect
Failed, expired, or cancelled: A "Return to store" button is shown (no auto-redirect)
Note
Automatic redirect applies to standard accounts. On US merchant accounts the customer completes the payment on the hosted page and is not redirected back — track the outcome with Webhooks or by polling, as described under Manual Polling (Without Redirect URL).
The redirect URL will have query parameters appended:
https://shop.example.com/order/123/complete?promptId=550e8400-...&status=successful
Query parameters:
Parameter |
Description |
|---|---|
|
The payment prompt UUID |
|
Payment result: |
Warning
Do not trust the redirect query parameters as proof of payment. A customer could manually navigate to your redirect URL with a forged status=successful parameter. Always verify the payment server-side via GET /external/v1/payments/:id before fulfilling the order.
Manual Polling (Without Redirect URL)
If you don't provide a redirectUrl, you need to verify the payment status yourself. The checkout page will show "You can now safely close this window" after completion.
Recommended approach:
Before redirect: Show a "Processing payment..." page
Track the outcome: Subscribe to Webhooks, or poll the payment status every few seconds
Update order: Mark order as paid when status is
successfulShow confirmation: Display order confirmation to customer
Example polling implementation (getPayment is the signed helper from Checking Payment Status):
async function pollPaymentStatus(promptId) {
const maxAttempts = 60; // 5 minutes at 5-second intervals
let attempts = 0;
while (attempts < maxAttempts) {
const payment = await getPayment(promptId);
switch (payment.status) {
case 'successful':
return { success: true, payment };
case 'unsuccessful':
case 'expired':
case 'cancelled':
return { success: false, payment };
case 'pending':
// Continue polling
break;
}
await new Promise(resolve => setTimeout(resolve, 5000));
attempts++;
}
throw new Error('Payment status polling timeout');
}
Tip
For server-to-server notification without polling, use Webhooks.
Payment Expiration
Every payment prompt carries an expiresAt timestamp; the expiry window is configured per blockchain network (typically minutes, not hours). If the customer doesn't complete payment in time:
The payment status changes to
expiredThe checkout URL becomes invalid
You should create a new payment prompt if the customer wants to retry
Tip
Read expiresAt from the payment object rather than assuming a fixed duration, and display the remaining time to customers.