.. _external_payments_api: External Payments API ===================== The External Payments API allows you to create payment prompts programmatically from your backend. When a payment is created, you receive a checkout URL to redirect your customer. Authentication -------------- All API requests require HTTP Basic Authentication using your **Client ID** and **API Key**: .. code-block:: text Authorization: Basic base64(clientId:apiKey) The credentials must belong to a **Merchant Admin** user with an active account. See :ref:`prerequisites` for details on obtaining and using your credentials. Create Payment Prompt --------------------- Creates a new payment prompt and returns a checkout URL. **Endpoint:** ``POST /external/payments/prompt`` **Headers:** .. list-table:: :widths: 20 15 65 :header-rows: 1 * - Header - Required - Description * - ``Content-Type`` - Yes - Must be ``application/json`` * - ``Authorization`` - Yes - Basic authentication (Base64 encoded ``clientId:apiKey``) **Request Body:** .. list-table:: :widths: 18 12 10 60 :header-rows: 1 * - Field - Type - Required - Description * - ``amount`` - number - Yes - Payment amount in USD (e.g., ``100.50``) * - ``blockchainIds`` - array of strings - Yes - Allowed blockchain networks for payment (e.g., ``["eth", "btc"]``). See :ref:`prerequisites` for available IDs. * - ``payer`` - string - Yes - Who pays the transaction fee: ``merchant`` or ``customer`` * - ``note`` - string - No - Optional description or reference (e.g., order ID) * - ``redirectUrl`` - string - No - URL to redirect the customer to after payment completion. Query parameters ``promptId`` and ``status`` will be appended automatically. Max 2048 characters. The domain must be in your allowed redirect domains list. **Payer Options:** - ``customer``: The customer pays the network fee (added to the payment amount) - ``merchant``: You absorb the network fee (deducted from your settlement) .. warning:: Every blockchain ID in the ``blockchainIds`` array must have a payment address configured for your merchant account. If any of the requested blockchains are missing a payment address, the request will be rejected. Use ``GET /external/blockchains/active`` to check which blockchains are available, and configure payment addresses in your merchant dashboard. **Example Request:** .. code-block:: bash curl -X POST https://api.miraclecash.info/external/payments/prompt \ -H "Content-Type: application/json" \ -H "Authorization: Basic $(echo -n 'your_client_id:your_api_key' | base64)" \ -d '{ "amount": 100.50, "blockchainIds": ["eth"], "payer": "customer", "note": "Order #12345", "redirectUrl": "https://shop.example.com/order/12345/complete" }' **Example Response:** .. code-block:: json { "prompt": { "id": "550e8400-e29b-41d4-a716-446655440000", "amount": 103.52, "commissionAmount": "3.02", "status": "pending", "sessionStatus": "pending", "expiresAt": "2025-01-29T14:30:00.000Z", "createdAt": "2025-01-28T14:30:00.000Z", "redirectUrl": "https://shop.example.com/order/12345/complete" }, "checkoutUrl": "https://checkout.miraclepay.com/?sessionId=550e8400-e29b-41d4-a716-446655440000" } **Response Fields:** .. list-table:: :widths: 25 12 63 :header-rows: 1 * - Field - Type - Description * - ``prompt.id`` - string - Unique payment prompt ID (UUID) * - ``prompt.amount`` - number - Final amount including commission (if payer is customer) * - ``prompt.commissionAmount`` - string - Commission fee amount in USD * - ``prompt.status`` - string - Payment status: ``pending`` * - ``prompt.sessionStatus`` - string - Checkout session status: ``pending`` * - ``prompt.expiresAt`` - string - ISO 8601 timestamp when payment expires (24 hours) * - ``prompt.createdAt`` - string - ISO 8601 timestamp when payment was created * - ``prompt.redirectUrl`` - string or null - The redirect URL provided in the request, or ``null`` if not provided * - ``checkoutUrl`` - string - URL to redirect the customer for payment Get Payment Status ------------------ Retrieves the current status of a payment prompt. **Endpoint:** ``GET /external/payments/prompt/:id`` **Headers:** .. list-table:: :widths: 20 15 65 :header-rows: 1 * - Header - Required - Description * - ``Authorization`` - Yes - Basic authentication (Base64 encoded ``clientId:apiKey``) **Path Parameters:** .. list-table:: :widths: 15 15 70 :header-rows: 1 * - Parameter - Type - Description * - ``id`` - string - The payment prompt UUID **Example Request:** .. code-block:: bash curl -X GET https://api.miraclecash.info/external/payments/prompt/550e8400-e29b-41d4-a716-446655440000 \ -H "Authorization: Basic $(echo -n 'your_client_id:your_api_key' | base64)" **Example Response:** .. code-block:: json { "id": "550e8400-e29b-41d4-a716-446655440000", "blockchainId": "eth", "status": "successful", "createdAt": "2025-01-28T14:30:00.000Z" } **Payment Status Values:** .. list-table:: :widths: 20 80 :header-rows: 1 * - Status - Description * - ``pending`` - Payment initiated, awaiting customer action * - ``successful`` - Payment confirmed on the blockchain * - ``unsuccessful`` - Payment failed (e.g., insufficient funds) * - ``expired`` - Customer did not complete payment within 24 hours * - ``cancelled`` - Payment was cancelled Error Responses --------------- **HTTP Status Codes:** .. list-table:: :widths: 15 25 60 :header-rows: 1 * - Status - Error - Description * - 400 - Bad Request - Invalid request body or parameters * - 401 - Basic authorization header is required - Missing or malformed ``Authorization`` header * - 401 - Invalid client ID - User ID not found in system * - 401 - Invalid API key - API Key does not match the user's credentials * - 401 - User is not active - Merchant account is deactivated * - 401 - User is not a merchant admin - API key belongs to non-admin user * - 400 - Main branch not found - Merchant configuration issue - contact support * - 400 - No redirect domains configured - Merchant has not added any allowed redirect domains. Configure them in the dashboard. * - 400 - Redirect URL domain not allowed - The redirect URL domain is not in the merchant's allowed domains list * - 400 - Invalid redirect URL format - The redirect URL is not a valid URL * - 400 - No payment addresses configured - No payment addresses exist for any of the requested blockchain IDs. Configure payment addresses in your merchant dashboard before creating prompts. * - 400 - Missing payment addresses for some blockchains - One or more of the requested blockchain IDs do not have payment addresses configured. Either add addresses for all requested blockchains or remove unsupported ones from the request. * - 404 - Payment prompt not found - The payment prompt ID does not exist **Error Response Format:** .. code-block:: json { "statusCode": 401, "message": "Invalid client ID", "error": "Unauthorized" } Integration Examples -------------------- Node.js / TypeScript ~~~~~~~~~~~~~~~~~~~~ .. code-block:: typescript import axios from 'axios'; const MIRACLEPAY_CLIENT_ID = process.env.MIRACLEPAY_CLIENT_ID; const MIRACLEPAY_API_KEY = process.env.MIRACLEPAY_API_KEY; const MIRACLEPAY_BASE_URL = 'https://api.miraclecash.info'; // Create Basic Auth header const authHeader = `Basic ${Buffer.from(`${MIRACLEPAY_CLIENT_ID}:${MIRACLEPAY_API_KEY}`).toString('base64')}`; interface CreatePaymentResponse { prompt: { id: string; amount: number; status: string; createdAt: string; }; checkoutUrl: string; } async function createPayment( amount: number, blockchainIds: string[], note?: string, redirectUrl?: string ): Promise { const response = await axios.post( `${MIRACLEPAY_BASE_URL}/external/payments/prompt`, { amount, blockchainIds, payer: 'customer', note, redirectUrl, }, { headers: { 'Content-Type': 'application/json', 'Authorization': authHeader, }, } ); return response.data; } async function getPaymentStatus(promptId: string) { const response = await axios.get( `${MIRACLEPAY_BASE_URL}/external/payments/prompt/${promptId}`, { headers: { 'Authorization': authHeader, }, } ); return response.data; } // Usage async function handleCheckout(orderId: string, amount: number) { const returnUrl = `https://shop.example.com/orders/${orderId}/complete`; const payment = await createPayment(amount, ['eth'], `Order #${orderId}`, returnUrl); // Store prompt.id in your database linked to the order await savePaymentToOrder(orderId, payment.prompt.id); // Redirect customer to checkout return { redirectUrl: payment.checkoutUrl }; } Best Practices -------------- 1. **Store payment IDs**: Always save the ``prompt.id`` in your database linked to the corresponding order for reconciliation. 2. **Handle errors gracefully**: Implement retry logic with exponential backoff for transient failures. 3. **Validate amounts**: Ensure payment amounts are valid numbers with up to 2 decimal places. 4. **Test first**: Always test your integration using testnet blockchain IDs before going live. 5. **Do not trust the redirect**: When using ``redirectUrl``, the customer is redirected with ``?promptId=...&status=...`` query parameters. **Never use these parameters as proof of payment.** Always verify the payment status server-side via ``GET /external/payments/prompt/:id`` before fulfilling orders. 6. **Configure allowed redirect domains**: Before using ``redirectUrl``, you must add the domain to your allowed redirect domains list in the MiraclePay dashboard. Only fully qualified domain names (e.g., ``shop.example.com``) are allowed, up to 20 domains maximum. Allowed Redirect Domains ------------------------ For security reasons, redirect URLs are validated against an allowlist of domains configured in your merchant account. **Dashboard Configuration:** Configure your allowed redirect domains in the MiraclePay merchant dashboard under **Developer Settings**. Each domain must be a valid fully qualified domain name (FQDN). **Example allowed domains:** - ``shop.example.com`` - ``store.mysite.com`` - ``checkout.yourdomain.com`` **Limits:** - Maximum 20 domains per merchant account - Only FQDNs are accepted (no paths, protocols, or wildcards) - The hostname of your ``redirectUrl`` must exactly match one of the configured domains