<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mobile Money API Documentation</title>
    <link rel="icon" href="/favicon.svg" type="image/svg+xml">
    <link rel="icon" href="/favicon.ico" sizes="any">
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f5f5f5;
        }
        .container {
            background: white;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        h1 {
            color: #333;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }
        h2 {
            color: #007bff;
            margin-top: 30px;
        }
        .endpoint {
            background: #f8f9fa;
            border-left: 4px solid #007bff;
            padding: 15px;
            margin: 15px 0;
            border-radius: 4px;
        }
        .method {
            display: inline-block;
            padding: 4px 8px;
            border-radius: 4px;
            font-weight: bold;
            margin-right: 10px;
        }
        .post { background: #28a745; color: white; }
        .get { background: #007bff; color: white; }
        .url {
            font-family: monospace;
            background: #e9ecef;
            padding: 2px 6px;
            border-radius: 3px;
        }
        pre {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 4px;
            overflow-x: auto;
            border: 1px solid #dee2e6;
        }
        .response {
            background: #d4edda;
            border: 1px solid #c3e6cb;
            padding: 15px;
            border-radius: 4px;
            margin: 10px 0;
        }
        .error {
            background: #f8d7da;
            border: 1px solid #f5c6cb;
            padding: 15px;
            border-radius: 4px;
            margin: 10px 0;
        }
        .note {
            background: #fff3cd;
            border: 1px solid #ffeaa7;
            padding: 15px;
            border-radius: 4px;
            margin: 15px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Mobile Money API Documentation</h1>
        
        <div class="note">
            <strong>✅ Live API Status:</strong> This API is connected to the live Relworx payment gateway and has been verified as of October 10, 2025. The API is designed for in-house applications with no additional API keys required.
        </div>

        <div class="note" style="background: #d1ecf1; border: 1px solid #bee5eb;">
            <strong>⚠️ Important:</strong> Some endpoints (price lists) may take 30+ seconds to respond. Implement appropriate timeout handling in your applications.
        </div>

        <h2>Base URL</h2>
        <p><span class="url"><?= base_url() ?>api/mobile-money/</span></p>

        <h2>Endpoints</h2>

        <div class="endpoint">
            <h3><span class="method post">POST</span> /pay</h3>
            <p>Request a mobile money payment</p>
            
            <h4>Request Body:</h4>
            <pre>{
    "msisdn": "+256701345672",
    "amount": 500.00,
    "currency": "UGX",
    "description": "Payment for services",
    "reference": "optional-custom-reference"
}</pre>

            <h4>Required Fields:</h4>
            <ul>
                <li><strong>msisdn</strong> - Phone number (supports +256 format or local format like 0701345672)</li>
                <li><strong>amount</strong> - Payment amount (positive number)</li>
            </ul>

            <h4>Optional Fields:</h4>
            <ul>
                <li><strong>currency</strong> - Currency code (default: UGX)</li>
                <li><strong>description</strong> - Payment description (default: "Mobile Money Payment")</li>
                <li><strong>reference</strong> - Custom reference (auto-generated if not provided)</li>
            </ul>

            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "message": "Request payment in progress.",
    "internal_reference": "d3ae5e14f05fcc58427331d38cb11d42",
    "reference": "MM_64f8a1b2c3d4e_1699123456"
}</pre>
            </div>

            <h4>Error Response:</h4>
            <div class="error">
                <pre>{
    "success": false,
    "message": "Invalid phone number format"
}</pre>
            </div>
        </div>

        <div class="endpoint">
            <h3><span class="method post">POST</span> /send</h3>
            <p>Send payment (disbursement) to mobile money account</p>
            
            <h4>Request Body:</h4>
            <pre>{
    "msisdn": "+256701345672",
    "amount": 500.00,
    "currency": "UGX",
    "description": "Send Payment to John Doe",
    "reference": "optional-custom-reference"
}</pre>

            <h4>Required Fields:</h4>
            <ul>
                <li><strong>msisdn</strong> - Phone number (supports +256 format or local format like 0701345672)</li>
                <li><strong>amount</strong> - Payment amount (positive number)</li>
            </ul>

            <h4>Optional Fields:</h4>
            <ul>
                <li><strong>currency</strong> - Currency code (default: UGX)</li>
                <li><strong>description</strong> - Payment description (default: "Send Payment")</li>
                <li><strong>reference</strong> - Custom reference (auto-generated if not provided)</li>
            </ul>

            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "message": "Send payment in progress.",
    "internal_reference": "d3ae5e14f05fcc58427331d38cb11d42"
}</pre>
            </div>

            <h4>Error Response:</h4>
            <div class="error">
                <pre>{
    "success": false,
    "message": "Invalid phone number format"
}</pre>
            </div>
        </div>

        <div class="endpoint">
            <h3><span class="method post">POST</span> /validate</h3>
            <p>Validate mobile number and get customer information</p>
            
            <h4>Request Body:</h4>
            <pre>{
    "msisdn": "+256768464016"
}</pre>

            <h4>Required Fields:</h4>
            <ul>
                <li><strong>msisdn</strong> - Phone number to validate (supports +256 format or local format like 0701345672)</li>
            </ul>

            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "message": "Msisdn +256768464016 successfully validated.",
    "customer_name": "HUSSEIN MWINYI",
    "msisdn": "+256768464016"
}</pre>
            </div>

            <h4>Error Response:</h4>
            <div class="error">
                <pre>{
    "success": false,
    "message": "Invalid phone number format"
}</pre>
            </div>
        </div>

        <div class="endpoint">
            <h3><span class="method post">POST</span> /payment-session</h3>
            <p>Request payment session for VISA/Mastercard</p>
            
            <h4>Request Body:</h4>
            <pre>{
    "amount": 10000.00,
    "currency": "UGX",
    "description": "VISA/Mastercard Payment",
    "reference": "optional-custom-reference"
}</pre>

            <h4>Required Fields:</h4>
            <ul>
                <li><strong>amount</strong> - Payment amount (positive number)</li>
            </ul>

            <h4>Optional Fields:</h4>
            <ul>
                <li><strong>currency</strong> - Currency code (default: UGX)</li>
                <li><strong>description</strong> - Payment description (default: "VISA/Mastercard Payment")</li>
                <li><strong>reference</strong> - Custom reference (auto-generated if not provided)</li>
            </ul>

            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "message": "Visa/Mastercard payment url generated successfully.",
    "payment_url": "https://payments.relworx.com/merchant-payment/1573621698448/visa-mastercard",
    "reference": "52750b30ffbc7de3b36"
}</pre>
            </div>

            <h4>Error Response:</h4>
            <div class="error">
                <pre>{
    "success": false,
    "message": "Amount must be a positive number"
}</pre>
            </div>
        </div>

        <div class="endpoint">
            <h3><span class="method get">GET</span> /balance</h3>
            <p>Check wallet balance</p>
            
            <h4>Query Parameters:</h4>
            <ul>
                <li><strong>currency</strong> - Omit for UGX+TZS+KES in one response; or a single ISO code (<code>UGX</code>, <code>TZS</code>, <code>KES</code>, etc.); <code>all</code> (same as omitting); comma-separated (e.g. <code>UGX,TZS</code>)</li>
            </ul>

            <h4>Example URLs:</h4>
            <ul>
                <li><code>GET /api/mobile-money/balance</code> - UGX, TZS, and KES (multi-currency response)</li>
                <li><code>GET /api/mobile-money/balance?currency=UGX</code> - Single-currency: UGX only</li>
                <li><code>GET /api/mobile-money/balance?currency=all</code> - Same as omitting <code>currency</code></li>
                <li><code>GET /api/mobile-money/balance?currency=USD</code> - Check balance in USD</li>
            </ul>

            <h4>Success Response (single currency):</h4>
            <div class="response">
                <pre>{
    "success": true,
    "balance": 0.0,
    "currency": "UGX",
    "account_no": "REL4737AB23A9"
}</pre>
                <p><strong>Note:</strong> The Relworx API returns only <code>success</code> and <code>balance</code>. Our wrapper adds <code>currency</code> and <code>account_no</code> for your convenience.</p>
            </div>

            <h4>Success Response (<code>currency=all</code> or comma-separated):</h4>
            <div class="response">
                <pre>{
    "success": true,
    "account_no": "REL4737AB23A9",
    "balances": [
        { "currency": "UGX", "success": true, "balance": 1000.0 },
        { "currency": "TZS", "success": true, "balance": 50000.0 },
        { "currency": "KES", "success": false, "balance": null, "message": "Failed to check wallet balance" }
    ]
}</pre>
                <p><strong>Note:</strong> <code>success</code> is true if at least one currency balance was retrieved. Failed currencies include <code>message</code> instead of a numeric <code>balance</code>.</p>
            </div>

            <h4>Error Response:</h4>
            <div class="error">
                <pre>{
    "success": false,
    "message": "API disabled for this account.",
    "error_code": "API_DISABLED"
}</pre>
            </div>
        </div>

        <div class="endpoint">
            <h3><span class="method get">GET</span> /history</h3>
            <p>Get transaction history from Relworx API</p>
            
            <h4>Description:</h4>
            <p>Retrieves all transactions for the account from the Relworx API. This provides a comprehensive view of all payment requests and their current status.</p>

            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "transactions": [
        {
            "customer_reference": "52750b30ffbc7de3b3745678sdaiop11",
            "provider": "MTN_UGANDA",
            "msisdn": "+25677XXXXXXX",
            "transaction_type": "collection",
            "currency": "UGX",
            "amount": 500.0,
            "status": "pending",
            "created_at": "2025-06-24T12:50:14+03:00"
        },
        {
            "customer_reference": "5sfgbsrgbskjmsldkrtgsbtrtr54",
            "provider": "MTN_UGANDA",
            "msisdn": "+25677XXXXXXX",
            "transaction_type": "collection",
            "currency": "UGX",
            "amount": 2000.0,
            "status": "failed",
            "created_at": "2025-06-13T05:00:29+03:00"
        }
    ],
    "count": 2,
    "account_no": "REL4737AB23A9"
}</pre>
                <p><strong>Note:</strong> The Relworx API returns only <code>success</code> and <code>transactions</code>. Our wrapper adds <code>count</code> and <code>account_no</code> for your convenience.</p>
            </div>

            <h4>Error Response:</h4>
            <div class="error">
                <pre>{
    "success": false,
    "message": "API disabled for this account.",
    "error_code": "API_DISABLED"
}</pre>
            </div>
        </div>

        <div class="endpoint">
            <h3><span class="method get">GET</span> /check-status/{internal_reference}</h3>
            <p>Check request status using internal reference from Relworx API</p>
            
            <h4>URL Parameters:</h4>
            <ul>
                <li><strong>internal_reference</strong> - Internal reference returned from pay/send endpoints</li>
            </ul>

            <h4>Example URLs:</h4>
            <ul>
                <li><code>GET /api/mobile-money/check-status/d3ae5e14f05fcc58427331d38cb11d42</code></li>
            </ul>

            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "status": "success",
    "message": "Request payment completed successfully.",
    "customer_reference": "xxxxxxxxxxxxxxxxx",
    "internal_reference": "xxxxxxxxxxxxxxxxx",
    "msisdn": "+256701000098",
    "amount": 500.0,
    "currency": "UGX",
    "provider": "AIRTEL_UGANDA",
    "charge": 12.5,
    "request_status": "success",
    "remote_ip": "102.85.4.217",
    "provider_transaction_id": "1080783XXXXX",
    "completed_at": "2025-04-10T15:12:58.977+03:00"
}</pre>
            </div>

            <h4>Error Response:</h4>
            <div class="error">
                <pre>{
    "success": false,
    "message": "API disabled for this account.",
    "error_code": "API_DISABLED"
}</pre>
            </div>
        </div>

        <div class="endpoint">
            <h3><span class="method get">GET</span> /status/{reference}</h3>
            <p>Get transaction status by reference</p>
            
            <h4>URL Parameters:</h4>
            <ul>
                <li><strong>reference</strong> - Transaction reference returned from /pay endpoint</li>
            </ul>

            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "transaction": {
        "reference": "MM_64f8a1b2c3d4e_1699123456",
        "internal_reference": "d3ae5e14f05fcc58427331d38cb11d42",
        "msisdn": "+256701345672",
        "amount": 500.00,
        "status": "PENDING",
        "created_at": "2023-11-04 10:30:45"
    }
}</pre>
            </div>

            <h4>Error Response:</h4>
            <div class="error">
                <pre>{
    "success": false,
    "message": "Transaction not found"
}</pre>
            </div>
        </div>

        <div class="endpoint">
            <h3><span class="method get">GET</span> /health</h3>
            <p>Check API health status</p>
            
            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "message": "Mobile Money service is running",
    "timestamp": "2023-11-04 10:30:45"
}</pre>
            </div>
        </div>

        <h2>Transaction Statuses</h2>
        <ul>
            <li><strong>PENDING</strong> - Payment request sent, waiting for user confirmation</li>
            <li><strong>SUCCESS</strong> - Payment completed successfully</li>
            <li><strong>FAILED</strong> - Payment failed or was cancelled</li>
        </ul>

        <h2>Example Usage</h2>
        
        <h3>JavaScript/Fetch Example:</h3>
        <pre>// Request payment
const response = await fetch('<?= base_url() ?>api/mobile-money/pay', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        msisdn: '+256701345672',
        amount: 1000,
        description: 'Service payment'
    })
});

const result = await response.json();
console.log(result);

// Check status
const statusResponse = await fetch(`<?= base_url() ?>api/mobile-money/status/${result.reference}`);
const status = await statusResponse.json();
console.log(status);</pre>

        <h3>cURL Example:</h3>
        <pre># Request payment
curl -X POST "<?= base_url() ?>api/mobile-money/pay" \
  -H "Content-Type: application/json" \
  -d '{
    "msisdn": "+256701345672",
    "amount": 1000,
    "description": "Service payment"
  }'

# Send payment (disbursement)
curl -X POST "<?= base_url() ?>api/mobile-money/send" \
  -H "Content-Type: application/json" \
  -d '{
    "msisdn": "+256701345672",
    "amount": 500,
    "description": "Send Payment to John Doe"
  }'

# Validate mobile number
curl -X POST "<?= base_url() ?>api/mobile-money/validate" \
  -H "Content-Type: application/json" \
  -d '{
    "msisdn": "+256768464016"
  }'

# Request VISA/Mastercard payment session
curl -X POST "<?= base_url() ?>api/mobile-money/payment-session" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 10000,
    "currency": "UGX",
    "description": "VISA/Mastercard Payment"
  }'

# Check wallet balance (UGX+TZS+KES if currency omitted)
curl "<?= base_url() ?>api/mobile-money/balance"
curl "<?= base_url() ?>api/mobile-money/balance?currency=UGX"

# Get transaction history (Relworx API)
curl "<?= base_url() ?>api/mobile-money/history"

# Check request status (Relworx API)
curl "<?= base_url() ?>api/mobile-money/check-status/d3ae5e14f05fcc58427331d38cb11d42"

# Check status (local database)
curl "<?= base_url() ?>api/mobile-money/status/MM_64f8a1b2c3d4e_1699123456"

# Get all available services
curl "<?= base_url() ?>api/mobile-money/services"

# Get categorized services
curl "<?= base_url() ?>api/mobile-money/services/categorized"

# Get price list for MTN Internet
curl "<?= base_url() ?>api/mobile-money/services/price-list/MTN_UG_INTERNET"

# Get price list for DSTV
curl "<?= base_url() ?>api/mobile-money/services/price-list/DSTV"

# Validate product before purchase
curl -X POST "<?= base_url() ?>api/mobile-money/validate-product" \
  -H "Content-Type: application/json" \
  -d '{
    "msisdn": "+256701454887",
    "amount": 1000,
    "currency": "UGX",
    "product_code": "MTN_UG_AIRTIME",
    "contact_phone": "+256701454832"
  }'

# Purchase product using validation reference
curl -X POST "<?= base_url() ?>api/mobile-money/purchase-product" \
  -H "Content-Type: application/json" \
  -d '{
    "validation_reference": "416b358df57e82a6uyd"
  }'</pre>

        <h2>Service Catalog</h2>
        
        <div class="endpoint">
            <h3><span class="method get">GET</span> /services</h3>
            <p>Get all available products/services from Relworx API</p>
            
            <h4>Description:</h4>
            <p>Retrieves all available services including internet, TV, airtime, bank transfers, and utilities with their details and capabilities.</p>

            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "products": [
        {
            "name": "MTN Uganda Internet",
            "code": "MTN_UG_INTERNET",
            "category": "INTERNET",
            "has_price_list": true,
            "has_choice_list": false,
            "billable": false
        },
        {
            "name": "DSTV - Multichoice",
            "code": "DSTV",
            "category": "TV",
            "has_price_list": true,
            "has_choice_list": false,
            "billable": true
        }
    ],
    "count": 41
}</pre>
            </div>
        </div>

        <div class="endpoint">
            <h3><span class="method get">GET</span> /services/categorized</h3>
            <p>Get categorized services with intelligent grouping</p>
            
            <h4>Description:</h4>
            <p>Retrieves all services organized by categories (Internet & Data, TV & Entertainment, Airtime & Voice, Bank Transfers, Utilities, Other Services) with provider grouping.</p>

            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "categories": [
        {
            "category": "INTERNET",
            "category_name": "Internet & Data",
            "services": [
                {
                    "name": "MTN Uganda Internet",
                    "code": "MTN_UG_INTERNET",
                    "provider": "MTN",
                    "has_price_list": true,
                    "has_choice_list": false,
                    "billable": false
                },
                {
                    "name": "Airtel Uganda Internet",
                    "code": "AIRTEL_UG_INTERNET",
                    "provider": "Airtel",
                    "has_price_list": true,
                    "has_choice_list": false,
                    "billable": false
                }
            ],
            "count": 3
        }
    ],
    "total_categories": 6,
    "total_services": 41
}</pre>
            </div>
        </div>

        <div class="endpoint">
            <h3><span class="method get">GET</span> /services/price-list/{product_code}</h3>
            <p>Get price list for a specific service</p>
            
            <h4>URL Parameters:</h4>
            <ul>
                <li><strong>product_code</strong> - Product code from services list (e.g., MTN_UG_INTERNET, DSTV)</li>
            </ul>

            <h4>Example URLs:</h4>
            <ul>
                <li><code>GET /api/mobile-money/services/price-list/MTN_UG_INTERNET</code></li>
                <li><code>GET /api/mobile-money/services/price-list/DSTV</code></li>
            </ul>

            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "product_code": "MTN_UG_INTERNET",
    "price_list": [
        {
            "code": "MTN_UG_INTERNET:23734852",
            "name": "MTN Monthly 1.5GB - 5,000/=",
            "price": 5000
        },
        {
            "code": "MTN_UG_INTERNET:23734851",
            "name": "MTN Monthly 22GB - 50,000/=",
            "price": 50000
        }
    ],
    "count": 23
}</pre>
            </div>

            <h4>Error Response:</h4>
            <div class="error">
                <pre>{
    "success": false,
    "message": "Product code is required"
}</pre>
            </div>
        </div>

        <div class="endpoint">
            <h3><span class="method post">POST</span> /validate-product</h3>
            <p>Validate product before purchase</p>
            
            <h4>Description:</h4>
            <p>Validates a product before purchase. This is required before every product purchase to ensure customer details are correct. Returns customer information and validation reference.</p>

            <h4>Request Body:</h4>
            <pre>{
    "msisdn": "+256701454887",
    "amount": 1000,
    "currency": "UGX",
    "product_code": "MTN_UG_AIRTIME",
    "contact_phone": "+256701454832",
    "reference": "optional-custom-reference",
    "location_id": "optional-location-id"
}</pre>

            <h4>Required Fields:</h4>
            <ul>
                <li><strong>msisdn</strong> - Product receiver account number (e.g., Yaka meter number, phone number)</li>
                <li><strong>amount</strong> - Product purchase amount/price (positive number)</li>
                <li><strong>product_code</strong> - Code for the product (e.g., MTN_UG_AIRTIME, DSTV)</li>
                <li><strong>contact_phone</strong> - Contact phone number for SMS notifications</li>
            </ul>

            <h4>Optional Fields:</h4>
            <ul>
                <li><strong>currency</strong> - Currency code (default: UGX) - <strong style="color: #856404;">Required by API, defaults to UGX if not provided</strong></li>
                <li><strong>reference</strong> - Custom reference (auto-generated if not provided)</li>
                <li><strong>location_id</strong> - Required for NATIONAL_WATER product validation</li>
            </ul>

            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "message": "Product validation successful",
    "customer_name": "JOHN DOE",
    "validation_reference": "416b358df57e82a6",
    "reference": "MM_64f8a1b2c3d4e_1699123456",
    "product_code": "MTN_UG_AIRTIME",
    "msisdn": "+256701454887",
    "amount": 1000
}</pre>
            </div>

            <h4>Error Response:</h4>
            <div class="error">
                <pre>{
    "success": false,
    "message": "Invalid MSISDN format"
}</pre>
            </div>
        </div>

        <div class="endpoint">
            <h3><span class="method post">POST</span> /purchase-product</h3>
            <p>Purchase product using validation reference</p>
            
            <h4>Description:</h4>
            <p>Purchases a product using the validation reference obtained from the validate-product endpoint. This completes the product purchase workflow.</p>

            <h4>Request Body:</h4>
            <pre>{
    "validation_reference": "416b358df57e82a6uyd"
}</pre>

            <h4>Required Fields:</h4>
            <ul>
                <li><strong>validation_reference</strong> - Validation reference obtained from validate-product endpoint</li>
            </ul>

            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "message": "Product purchase in progress.",
    "internal_reference": "ae84c6691c6b9706061b2f093d25ced5",
    "validation_reference": "416b358df57e82a6uyd"
}</pre>
            </div>

            <h4>Error Response:</h4>
            <div class="error">
                <pre>{
    "success": false,
    "message": "Validation reference is required"
}</pre>
            </div>
        </div>

        <h2>Transaction Management</h2>
        
        <div class="endpoint">
            <h3><span class="method get">GET</span> /transaction/{reference}</h3>
            <p>Get comprehensive transaction details including chargeback and refund information</p>
            
            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "transaction": {
        "id": 1,
        "transaction_id": "MM_64f8a1b2c3d4e_1699123456",
        "reference": "d3ae5e14f05fcc58427331d38cb11d42",
        "gateway_reference": "d3ae5e14f05fcc58427331d38cb11d42",
        "msisdn": "+256701345672",
        "amount": 1000.00,
        "currency": "UGX",
        "status": "SUCCESS",
        "description": "Service payment",
        "payment_method": "mobile_money",
        "client_ip": "192.168.1.1",
        "failure_reason": null,
        "created_at": "2023-11-04 10:30:45",
        "processed_at": "2023-11-04 10:31:15",
        "updated_at": "2023-11-04 10:31:15",
        "chargeback_status": "none",
        "chargeback_reason": null,
        "chargeback_date": null,
        "refund_status": "none",
        "refund_amount": 0.00,
        "refund_reference": null,
        "webhook_attempts": 2,
        "last_webhook_attempt": "2023-11-04 10:31:20",
        "metadata": {...}
    }
}</pre>
            </div>
        </div>

        <div class="endpoint">
            <h3><span class="method post">POST</span> /chargeback</h3>
            <p>Initiate a chargeback for a successful transaction</p>
            
            <h4>Request Body:</h4>
            <pre>{
    "transaction_id": "MM_64f8a1b2c3d4e_1699123456",
    "reason": "Customer dispute - unauthorized transaction",
    "additional_data": {
        "customer_complaint": "I did not authorize this payment"
    }
}</pre>
        </div>

        <div class="endpoint">
            <h3><span class="method post">POST</span> /refund</h3>
            <p>Process a refund for a successful transaction</p>
            
            <h4>Request Body:</h4>
            <pre>{
    "transaction_id": "MM_64f8a1b2c3d4e_1699123456",
    "amount": 500.00,
    "reason": "Service not provided"
}</pre>
        </div>

        <div class="endpoint">
            <h3><span class="method get">GET</span> /report?start_date=YYYY-MM-DD&end_date=YYYY-MM-DD</h3>
            <p>Generate comprehensive transaction report with statistics</p>
            
            <h4>Example:</h4>
            <pre>GET /api/mobile-money/report?start_date=2023-11-01&end_date=2023-11-30</pre>
        </div>

        <h2>Webhook Integration</h2>
        <p>Transactions are automatically posted to configured webhooks when status changes occur. The webhook will receive the same transaction data structure as returned by the status endpoint.</p>

        <div class="note">
            <strong>Important:</strong> Make sure to configure webhook URLs in the admin panel to receive real-time payment notifications.
        </div>

        <h2>Comprehensive Transaction Tracking</h2>
        <p>All transactions are recorded with comprehensive data for:</p>
        <ul>
            <li><strong>Chargeback Management:</strong> Track and manage chargebacks with full audit trail</li>
            <li><strong>Refund Processing:</strong> Handle partial and full refunds with proper tracking</li>
            <li><strong>Audit Trail:</strong> Complete transaction history with timestamps and metadata</li>
            <li><strong>Reporting:</strong> Generate detailed reports for accounting and compliance</li>
            <li><strong>Webhook Tracking:</strong> Monitor webhook delivery attempts and failures</li>
        </ul>

        <h1 style="margin-top: 40px;">Paytota API</h1>
        <p>Simplified wrapper for the <a href="https://gate.paytota.com/" target="_blank" rel="noopener">Paytota payment gateway</a>. Use these endpoints for simple checkout (redirect), balance, payouts (bank or mobile), and webhooks. Authentication is server-side via <code>paytota.secret_key</code> and <code>paytota.brand_id</code> in your .env.</p>
        <div class="note">
            <strong>Configuration:</strong> Set <code>paytota.base_url</code>, <code>paytota.secret_key</code>, and <code>paytota.brand_id</code> in .env. Optional: <code>paytota.success_redirect</code>, <code>paytota.failure_redirect</code> as defaults for checkout.
        </div>
        <h2>Base URL</h2>
        <p><span class="url"><?= base_url() ?>api/paytota/</span></p>
        <h2>Endpoints</h2>
        <div class="endpoint">
            <h3><span class="method post">POST</span> /checkout</h3>
            <p>Create a purchase (simple checkout) and get a <code>checkout_url</code> to redirect the customer. One API call; no Step 2 required.</p>
            <h4>Request Body:</h4>
            <pre>{
    "email": "customer@example.com",
    "phone": "256770123456",
    "country": "UG",
    "currency": "UGX",
    "products": [
        { "name": "Item", "price": "500" }
    ],
    "reference": "your-unique-ref-123",
    "success_redirect": "https://yoursite.com/success",
    "failure_redirect": "https://yoursite.com/failure"
}</pre>
            <h4>Required Fields:</h4>
            <ul>
                <li><strong>email</strong>, <strong>phone</strong>, <strong>country</strong>, <strong>currency</strong>, <strong>products</strong> (array of <code>{name, price}</code>), <strong>reference</strong>, <strong>success_redirect</strong>, <strong>failure_redirect</strong></li>
            </ul>
            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "message": "Purchase created",
    "data": {
        "id": "05b0b12b-1702-4719-8e53-e3a2ee2d5e20",
        "checkout_url": "https://payments.paytota.com/p/05b0b12b-.../",
        "reference": "your-unique-ref-123",
        "status": "created"
    }
}</pre>
            </div>
            <p>Redirect the customer to <code>data.checkout_url</code>. After payment they are sent to your success or failure URL; you also receive a webhook (<code>purchase.paid</code> or <code>purchase.error</code>).</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /balance</h3>
            <p>Get account balance (per currency).</p>
            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "message": "OK",
    "data": {
        "UGX": {
            "balance": 2710,
            "available_balance": 1210,
            "gross_balance": 5300,
            ...
        }
    }
}</pre>
            </div>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /purchase/status/{id}</h3>
            <p>Get purchase status by Paytota purchase ID.</p>
            <h4>Success Response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "message": "OK",
    "data": {
        "id": "...",
        "status": "paid",
        "reference": "...",
        "checkout_url": "...",
        "payment": { ... }
    }
}</pre>
            </div>
        </div>
        <div class="endpoint">
            <h3><span class="method post">POST</span> /payout</h3>
            <p>Create a payout (Step 1). Optionally include <code>execute</code> in the body to run Step 2 in one call (bank or mobile).</p>
            <h4>Request Body (Step 1 only):</h4>
            <pre>{
    "email": "recipient@example.com",
    "phone": "256700123123",
    "country": "UG",
    "currency": "UGX",
    "amount": "500",
    "description": "Payout",
    "reference": "payout-ref-123"
}</pre>
            <h4>Request Body (Step 1 + execute):</h4>
            <p>Add <code>execute</code> for bank or mobile:</p>
            <pre>{
    "email": "...",
    "phone": "...",
    "country": "UG",
    "currency": "UGX",
    "amount": "500",
    "description": "Payout",
    "reference": "payout-ref-123",
    "execute": {
        "payout_type": "bank",
        "bank_name": "Stanbic Bank",
        "bank_code": "SBICUGKX",
        "bank_account_name": "Jane Rose",
        "bank_account_number": "123456789012"
    }
}</pre>
            <p>For mobile: <code>"execute": { "payout_type": "mobile" }</code></p>
            <h4>Success Response (Step 1):</h4>
            <div class="response">
                <pre>{
    "success": true,
    "message": "Payout initiated",
    "data": {
        "id": "...",
        "execution_url": "https://gate.paytota.com/po/.../paytota_proxy/",
        "reference": "...",
        "status": "initialized"
    }
}</pre>
            </div>
        </div>
        <div class="endpoint">
            <h3><span class="method post">POST</span> /payout/execute</h3>
            <p>Execute payout Step 2 (use when you did not pass <code>execute</code> in /payout).</p>
            <h4>Request Body:</h4>
            <pre>{
    "execution_url": "https://gate.paytota.com/po/.../paytota_proxy/",
    "payload": {
        "payout_type": "bank",
        "bank_name": "Stanbic Bank",
        "bank_code": "SBICUGKX",
        "bank_account_name": "Jane Rose",
        "bank_account_number": "123456789012"
    }
}</pre>
            <p>Or <code>"payload": { "payout_type": "mobile" }</code> for mobile payout.</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /payout/status/{id}</h3>
            <p>Get payout status by Paytota payout ID.</p>
        </div>
        <div class="endpoint">
            <h3><span class="method post">POST</span> /webhook</h3>
            <p>Paytota sends purchase and payout events here. Configure this URL in your Paytota developer settings. Returns 200 to acknowledge.</p>
        </div>
        <div class="endpoint">
            <h3><span class="method post">POST</span> /stk</h3>
            <p>Trigger STK push for a purchase (Step 2 after creating a purchase). Use when you want server-to-server PIN prompt instead of redirect.</p>
            <h4>Request Body:</h4>
            <pre>{
    "purchase_id": "05b0b12b-1702-4719-8e53-e3a2ee2d5e20"
}</pre>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /health</h3>
            <p>Check if Paytota is configured (<code>paytota.secret_key</code> and base URL set).</p>
            <div class="response">
                <pre>{
    "success": true,
    "message": "OK",
    "data": { "configured": true, "service": "paytota" }
}</pre>
            </div>
        </div>

                <h1 style="margin-top: 40px;">NOWPayments API</h1>
        <p>Server-side proxy for the <a href="https://nowpayments.io/" target="_blank" rel="noopener">NOWPayments</a> REST API (<a href="https://documenter.getpostman.com/view/7907941/2s93JusNJt" target="_blank" rel="noopener">Postman docs</a>). Upstream auth: <code>x-api-key</code> for payments, balance, validate-address, and payout status. <strong>Crypto payout create/verify</strong> and <strong>fiat account + fiat payout request</strong> also require <code>Authorization: Bearer</code> (JWT from NOWPayments). Fiat catalog and fiat payout list use <strong>Bearer only</strong>.</p>
        <div class="note">
            <strong>Configuration:</strong> <code>nowpayments.api_key</code> (required for payment collection and most payout calls). <strong>Bearer JWT</strong> (required for crypto payout create/verify, fiat catalog, fiat payouts list, etc.): either set <code>nowpayments.bearer_token</code> manually, or set <code>nowpayments.auth_email</code> and <code>nowpayments.auth_password</code> (same as NOWPayments dashboard login) so the server calls <code>POST .../v1/auth</code> and caches the JWT for 4 minutes (tokens expire after 5 minutes). <strong>IPN:</strong> set <code>nowpayments.ipn_secret</code> to the same secret as in the NOWPayments dashboard; the server verifies <code>x-nowpayments-sig</code> (HMAC-SHA512 over recursively key-sorted JSON of the body). If the secret is empty, signatures are not verified (development only). Optional: <code>nowpayments.base_url</code> (default <code>https://api.nowpayments.io/v1</code>).
        </div>
        <p>Upstream <code>POST https://api.nowpayments.io/v1/auth</code> returns JSON with a top-level <code>token</code> string (JWT). This app reads that field when using dashboard credentials; example shape:</p>
        <pre>{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}</pre>
        <h2>Base URL</h2>
        <p><span class="url"><?= base_url() ?>api/nowpayments/</span></p>

        <h2>Instant Payment Notification (IPN)</h2>
        <div class="endpoint">
            <h3><span class="method post">POST</span> /ipn</h3>
            <p>Webhook endpoint for NOWPayments payment callbacks. Configure this URL in the NOWPayments dashboard (same path as <code>ipn_callback_url</code> on created payments). Header <code>x-nowpayments-sig</code>: hex HMAC-SHA512 of the JSON body with object keys sorted recursively (see NOWPayments IPN documentation). Body: JSON payment object (includes <code>payment_id</code>, <code>payment_status</code>, <code>order_id</code>, etc.).</p>
            <p>When <code>order_id</code> matches a local <code>payment_transactions.transaction_id</code> or <code>reference</code>, the row is updated: <code>status</code> maps from <code>finished</code>/<code>confirmed</code> to <code>SUCCESS</code>, <code>failed</code>/<code>expired</code>/<code>refunded</code> to <code>FAILED</code>, otherwise left <code>PENDING</code>; <code>gateway_reference</code> stores <code>payment_id</code>; <code>metadata</code> gains <code>nowpayments_ipn</code>.</p>
            <p><strong>Responses:</strong> <code>200</code> when accepted; <code>400</code> empty/invalid JSON; <code>403</code> when <code>nowpayments.ipn_secret</code> is set and the signature is missing or invalid.</p>
        </div>

        <h2>Payments (x-api-key)</h2>
        <div class="endpoint">
            <h3><span class="method post">POST</span> /payment</h3>
            <p>Creates a payment. This wrapper requires <code>price_amount</code>, <code>price_currency</code>, <code>pay_currency</code>. Optional: <code>ipn_callback_url</code>, <code>order_id</code>, <code>order_description</code>, etc. (see NOWPayments docs).</p>
            <h4>Example body:</h4>
            <pre>{
    "price_amount": 3999.5,
    "price_currency": "usd",
    "pay_currency": "btc",
    "ipn_callback_url": "https://yoursite.com/api/nowpayments/ipn",
    "order_id": "RGDBP-21314",
    "order_description": "Apple Macbook Pro 2019 x 1"
}</pre>
            <h4>Typical upstream response fields:</h4>
            <p><code>payment_id</code>, <code>payment_status</code>, <code>pay_address</code>, <code>pay_amount</code>, <code>pay_currency</code>, <code>created_at</code>, <code>expiration_estimate_date</code>, etc.</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /payment/{payment_id}</h3>
            <p>Payment status. Returns JSON such as <code>payment_status</code> (e.g. <code>finished</code>), <code>actually_paid</code>, <code>pay_currency</code>, hashes, etc.</p>
        </div>

        <h2>Crypto payouts</h2>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /balance</h3>
            <p><strong>x-api-key only.</strong> Wallet-style balances per currency (<code>amount</code>, <code>pendingAmount</code>).</p>
        </div>
        <div class="endpoint">
            <h3><span class="method post">POST</span> /payout/validate-address</h3>
            <p><strong>x-api-key only.</strong> Body must include <code>address</code>, <code>currency</code>; <code>extra_id</code> optional (send <code>null</code> if unused).</p>
            <pre>{
    "address": "0x...",
    "currency": "eth",
    "extra_id": null
}</pre>
        </div>
        <div class="endpoint">
            <h3><span class="method post">POST</span> /payout</h3>
            <p><strong>x-api-key + Bearer JWT.</strong> Body must include non-empty <code>withdrawals</code> array; each item needs <code>address</code>, <code>currency</code>, <code>amount</code>. Optional per row: <code>ipn_callback_url</code>, <code>fiat_amount</code>, <code>fiat_currency</code>, etc.</p>
            <pre>{
    "ipn_callback_url": "https://yoursite.com/ipn",
    "withdrawals": [
        { "address": "T...", "currency": "trx", "amount": 200, "ipn_callback_url": "https://yoursite.com/ipn" },
        { "address": "0x...", "currency": "eth", "amount": 0.1 }
    ]
}</pre>
        </div>
        <div class="endpoint">
            <h3><span class="method post">POST</span> /payout/{batch_withdrawal_id}/verify</h3>
            <p><strong>x-api-key + Bearer JWT.</strong> Body: <code>{ "verification_code": "123456" }</code>. Upstream may return plain text <code>OK</code>; this API wraps it as <code>data.raw</code> when not JSON.</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /payout/{payout_id}</h3>
            <p><strong>x-api-key only.</strong> Returns an array of payout objects (status, <code>batch_withdrawal_id</code>, etc.).</p>
        </div>

        <h2>Fiat payouts (Bearer JWT; account + request also send x-api-key)</h2>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /fiat-payouts/providers</h3>
            <p>Lists providers (<code>result[].code</code>, <code>name</code>, <code>enabled</code>).</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /fiat-payouts/fiat-currencies</h3>
            <p>Lists fiat currencies per provider.</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /fiat-payouts/crypto-currencies?provider=&amp;currency=</h3>
            <p>Optional query filters. Omit params to list all (per NOWPayments).</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /fiat-payouts/payment-methods?provider=&amp;currency=</h3>
            <p>If query params are omitted, this proxy sends <code>provider=null</code> and <code>currency=null</code> like the official example.</p>
        </div>
        <div class="endpoint">
            <h3><span class="method post">POST</span> /fiat-payouts/account</h3>
            <p>Requires <code>currency</code>, <code>paymentCode</code>, <code>fields</code> (object), <code>provider</code>, <code>countryCode</code>.</p>
            <pre>{
    "currency": "php",
    "paymentCode": "php_aib",
    "fields": {
        "iban": "qwerty1234567890",
        "accountNumber": "1234567890",
        "country": "PH"
    },
    "provider": "transfi",
    "countryCode": "PH"
}</pre>
        </div>
        <div class="endpoint">
            <h3><span class="method post">POST</span> /fiat-payouts</h3>
            <p>Requires <code>fiatCurrency</code>, <code>cryptoCurrency</code>, <code>amount</code>, <code>provider</code>.</p>
            <pre>{
    "fiatCurrency": "eur",
    "cryptoCurrency": "bnbbsc",
    "amount": 500,
    "provider": "transfi"
}</pre>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /fiat-payouts</h3>
            <p>List payouts. Optional query: <code>id</code>, <code>provider</code>, <code>requestId</code>, <code>fiatCurrency</code>, <code>cryptoCurrency</code>, <code>status</code>, <code>filter</code>, <code>provider_payout_id</code>, <code>limit</code>, <code>page</code>, <code>orderBy</code>, <code>sortBy</code>, <code>dateFrom</code>, <code>dateTo</code>.</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /health</h3>
            <p><code>configured</code> (API key set), <code>bearer_configured</code> (JWT set).</p>
        </div>

        <h1 style="margin-top: 40px;">YEMScan / YEMChain API</h1>
        <p>Simplified wrapper for the <a href="https://yemscan.com/api/" target="_blank" rel="noopener">YEMChain blockchain API</a>. Authentication is server-side via environment variables; no API keys are required in requests.</p>
        <div class="note">
            <strong>Rate limit:</strong> The upstream YEMScan API allows 10 requests per minute per API key. Configure <code>yemscan.api_key</code>, <code>yemscan.custom_domain</code>, and <code>yemscan.pernum</code> (or <code>yemscan.uid</code>) in your .env.
        </div>
        <div class="note" style="background: #f8d7da; border: 1px solid #f5c6cb;">
            <strong>Payment security:</strong> <code>transaction-statuses</code> returns only &quot;confirmed&quot; and does not include amount or recipient. Always verify with <code>/transaction/verify?hash=...&amp;expected_amount=...&amp;expected_to_uid=YOUR_UID</code> (or use <code>include_details=1</code> and compare on your side) so you do not accept underpayment or payment to the wrong address.
        </div>
        <h2>Base URL</h2>
        <p><span class="url"><?= base_url() ?>api/yemscan/</span></p>
        <h2>Endpoints</h2>
        <div class="endpoint">
            <h3><span class="method post">POST</span> /transactions</h3>
            <p>Create one or more YEM transactions (max 100 per request).</p>
            <h4>Request Body (single):</h4>
            <pre>{
    "from_uid": 123,
    "to_uid": 456,
    "value": 12.34,
    "reason": "Payment for order #12345",
    "asset": "YEM",
    "from_curr": "EUR",
    "to_curr": "USD"
}</pre>
            <h4>Request Body (batch):</h4>
            <pre>{
    "transactions": [
        { "from_uid": 123, "to_uid": 456, "value": 12.34, "reason": "...", "asset": "YEM", "from_curr": "EUR", "to_curr": "USD" }
    ]
}</pre>
            <p><code>value</code> is always in <strong>decimal YEM</strong> (e.g. <code>10</code> = 10 YEM, <code>12.34</code> = 12.34 YEM). It is converted to the chain hundredths format (10 → 1000) before sending; do not send hundredths yourself.</p>
            <p><strong>Important — <code>reason</code> and order IDs:</strong> Always send <code>reason</code> in the <strong>JSON request body</strong>, not in the URL. If <code>reason</code> contains <code>#</code> (e.g. &quot;Payment for order #TX-260312-EDB563&quot;), anything after <code>#</code> is treated as a URL fragment by browsers and is not sent to the server. You would then only store &quot;Payment for order #&quot; and lose the FinFlo transaction ID. Use a POST body with <code>Content-Type: application/json</code> so the full reason is received and recorded.</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /uid or /uid?pernum=1001296648</h3>
            <p>Get UID from pernum: <code>uid = pernum - 1000000000</code>. With no query param, returns this app's UID (from configured <code>yemscan.pernum</code>). With <code>pernum=...</code>, returns the UID for that pernum so consumers can resolve their own.</p>
            <h4>Success response:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "uid": 1296648,
    "pernum": 1001296648
}</pre>
            </div>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /balances?uids=123,456&tokenSymbol=YEM</h3>
            <p>Get balances for up to 100 UIDs.</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /globals</h3>
            <p>Get global blockchain statistics (total accounts, total transactions).</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /volume?tokenSymbol=YEM</h3>
            <p>Get transaction volume (1d and 7d).</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /transaction-statuses?hashes=0x...,0x...&amp;include_details=1</h3>
            <p>Get statuses for up to 100 transaction hashes. Status values: <code>not_found</code>, <code>failed</code>, <code>confirmed</code>.</p>
            <p><strong>Security:</strong> A status of <code>confirmed</code> alone does not prove amount or recipient. Add <code>include_details=1</code> to get <code>details</code> (value, from_uid, to_uid) for each confirmed hash so you can verify amount and that payment was to your UID. Or use <code>/transaction/verify</code> with expected amount and recipient.</p>
            <h4>Query parameters:</h4>
            <ul>
                <li><strong>hashes</strong> – Comma-separated transaction hashes (max 100).</li>
                <li><strong>include_details</strong> – Set to <code>1</code> or <code>true</code> to include a <code>details</code> object with value (decimal), from_uid, to_uid for each confirmed hash.</li>
            </ul>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /transaction/verify?hash=0x...&amp;expected_amount=100&amp;expected_to_uid=123</h3>
            <p><strong>Recommended for payments.</strong> Verifies that a transaction is confirmed and (optionally) matches the expected amount and your recipient UID. Prevents accepting underpayment or payment to the wrong address.</p>
            <h4>Query parameters:</h4>
            <ul>
                <li><strong>hash</strong> – Transaction hash (or use path: <code>/transaction/{hash}/verify</code>).</li>
                <li><strong>expected_amount</strong> – Expected amount in <strong>decimal YEM</strong> (e.g. <code>1.25</code> for 1.25 YEM, <code>125</code> for 125 YEM). If provided, response is <code>verified: true</code> only when the on-chain amount matches (within 0.01). Compare <code>expected_amount</code> to <code>transaction.value</code> or <code>transaction.amount_yem</code> — both are in decimal YEM.</li>
                <li><strong>expected_to_uid</strong> – Your merchant/recipient UID. If provided, response is <code>verified: true</code> only when the transaction recipient is this UID.</li>
            </ul>
            <h4>Success response (verified):</h4>
            <p><code>transaction.value</code> and <code>transaction.amount_yem</code> are always in <strong>decimal YEM</strong> (e.g. 1.25 = 1.25 YEM). Use these for display and for comparing to <code>expected_amount</code>. Do not use any raw chain integer.</p>
            <div class="response">
                <pre>{
    "success": true,
    "message": "Transaction verified",
    "verified": true,
    "hash": "0x...",
    "status": "confirmed",
    "transaction": { "value": 1.25, "amount_yem": 1.25, "from_uid": 456, "to_uid": 123 }
}</pre>
            </div>
            <h4>Response when amount or recipient mismatch:</h4>
            <div class="response">
                <pre>{
    "success": true,
    "message": "Amount mismatch",
    "verified": false,
    "transaction": { "value": 10, "from_uid": 456, "to_uid": 123 },
    "expected_amount": 100,
    "mismatch_reason": "amount"
}</pre>
            </div>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /asset-stats?tokenSymbol=YEM</h3>
            <p>Get asset price and number of wallets holding the asset.</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /public-key/{uid} or /public-key?uid=123</h3>
            <p>Get Ethereum public key for a UID.</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /transaction/{hash} or /transaction?hash=0x...</h3>
            <p>Get transaction details by hash.</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /validate-access?uid=789&platform_name=FinFlo</h3>
            <p>Validate whether a UID (Pernum) is allowed to access the platform (e.g. FinFlo). Call when the user opens the app with a stored Pernum/UID or when they add their Pernum. Uses YEM Foundation third-party access check; same auth headers as other YEMScan endpoints.</p>
            <h4>Query parameters:</h4>
            <ul>
                <li><strong>uid</strong> (required) – User ID to check</li>
                <li><strong>platform_name</strong> (optional) – Platform name; default from server config (e.g. FinFlo)</li>
            </ul>
            <h4>Success (access granted):</h4>
            <pre>{"success": true, "access_granted": true, "uid": 789, "platform_name": "FinFlo", "message": "Access granted"}</pre>
            <h4>Access not granted or error:</h4>
            <pre>{"success": false, "access_granted": false, "uid": 789, "platform_name": "FinFlo", "message": "Access not granted"}</pre>
            <p>Also available as <code>GET /third-party-access?uid=...</code> (alias).</p>
        </div>
        <div class="endpoint">
            <h3><span class="method get">GET</span> /health</h3>
            <p>Check configuration and connectivity to YEMScan API.</p>
        </div>
    </div>
</body>
</html>
