# MakyPay API Integration Skill for AI Agents

> **Live Specification Version:** 1.0.0  
> **Last Updated:** 2026-08-15 09:41:17 UTC  
> **Source of Truth:** Generated directly from MakyPay Wire-API route definitions & OpenAPI specs.

---

## 1. Overview & Gateway Adapters

MakyPay (`wire-api`) is a white-label unified payment gateway API providing mobile money collections, payouts/disbursements, bank transfers, utility bill payments, and webhooks across Africa (Uganda primary, extended via multi-gateway orchestration).

### Product Catalog & Gateway Adapters

| Product / Feature | Description | Gateway Adapters Supported | Country & Currency | Min / Max Amount (UGX) |
| :--- | :--- | :--- | :--- | :--- |
| **Collections (Mobile Money)** | Push USSD payment prompt to MTN & Airtel phones | pawaPay, Flutterwave, Paystack, Hubtel, M-Pesa Daraja, Pesapal, DPO Pay, Peach Payments | UG (`UGX`) | 500 – 10,000,000 |
| **Collections (Card Payments)** | Hosted credit/debit card (Visa / Mastercard) checkout | Flutterwave, Paystack, Pesapal, DPO Pay, Peach Payments | UG (`UGX`) | 500 – 10,000,000 |
| **Disbursements (Send Money)** | Transfer funds directly to customer Mobile Money wallets | pawaPay, Flutterwave, Hubtel, M-Pesa Daraja | UG (`UGX`) | 500 – 10,000,000 |
| **Bank Transfers** | Direct bank account payouts (supported banks list endpoint) | MarzPay, Flutterwave | UG (`UGX`) | Min 5,000 |
| **Bill Payments** | Pay utilities: LIGHT, UMEME, NWSC Water, DSTV, GOTV | MarzPay (White-Label) | UG (`UGX`) | Min 1,000 |
| **Wallet & Balance** | Check available merchant wallet balances (`main`, `card`) | MakyPay Core | UG (`UGX`) | N/A |
| **Webhooks** | Event notifications for completion or failure | MakyPay Event Engine | Global | N/A |

---

## 2. Authentication Setup

All API requests to `/api/v1/*` endpoints require **HTTP Basic Authentication** headers unless explicitly stated (e.g. public bank list).

### Credentials
- **API Public Key** (Username): `MAKYPAY_CLIENT_API_KEY`  
- **API Secret Key** (Password): `MAKYPAY_CLIENT_API_SECRET`  

### Header Format
```http
Authorization: Basic <base64(API_KEY:API_SECRET)>
Content-Type: application/x-www-form-urlencoded (or application/json)
Accept: application/json
```

*Example in Python:*
```python
import base64

credentials = f"{api_key}:{api_secret}"
encoded = base64.b64encode(credentials.encode()).decode()
headers = {"Authorization": f"Basic {encoded}"}
```

---

## 3. API Endpoints Reference

### 3.1 Collections (Mobile Money & Card)

#### `POST /api/v1/collections/collect-money`
Initiate a collection request. Accepts `application/x-www-form-urlencoded` or `JSON`.

* **Headers:** `Authorization: Basic <base64>`
* **Parameters / Request Body:**
  * `reference` (string, **REQUIRED**): Unique UUID v4 reference (e.g., `f47ac10b-58cc-4372-a567-0e02b2c3d479`). Must be valid UUID.
  * `amount` (integer, **REQUIRED**): Amount in UGX. Constraint: `500 <= amount <= 10,000,000`.
  * `phone_number` (string, **REQUIRED for Mobile Money**): Payer phone number (e.g. `+256770000000` or `0770000000`). Auto-detects MTN vs Airtel from prefix.
  * `method` (string, optional): Set to `'card'` for card payments. Omit or set to `'mobile_money'` for mobile money.
  * `country` (string, optional): Country code, default `'UG'`.
  * `description` (string, optional): Payment description (max 255 chars).
  * `callback_url` (string, optional): Webhook HTTPS URL to receive `collection.completed` or `collection.failed` notification.
  * `charge_payer` (string, optional): `'customer'` (fee added on top of amount) or `'business'` (fee deducted from merchant). Default: `'customer'`.

* **Response (200 OK):**
```json
{
  "status": "success",
  "message": "Payment prompt sent to customer phone",
  "data": {
    "transaction": {
      "uuid": "8f8b8989-1234-4567-89ab-cdef01234567",
      "reference": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "status": "pending",
      "provider_reference": "MP-987654"
    },
    "collection": {
      "amount": { "formatted": "10,000.00", "raw": 10000, "currency": "UGX" },
      "provider": "MTN",
      "phone_number": "+256770000000"
    }
  }
}
```

#### `GET /api/v1/collections/collect-money/{transaction_id}`
Get collection status details by UUID or client reference.
* **Headers:** `Authorization: Basic <base64>`
* **Response (200 OK):** Contains transaction `status` (`pending`, `processing`, `completed`, `failed`), timeline timestamps, and payment metadata.

#### `GET /api/v1/collections/collect-money/services`
List supported collection countries, providers, phone prefixes, and limits.

---

### 3.2 Disbursements (Send Money / Payouts)

#### `GET /api/v1/disbursements/send-money/services`
Get send-money providers (MTN, AIRTEL) and withdrawal fee tier structure.

#### `POST /api/v1/disbursements/send-money/initiate`
Initiate a payout to a mobile money wallet.
* **Parameters:**
  * `reference` (string, **REQUIRED**): UUID v4 reference.
  * `phone_number` (string, **REQUIRED**): Recipient phone number (MTN or Airtel Uganda).
  * `amount` (integer, **REQUIRED**): Amount in UGX (500 to 10,000,000).
  * `description` (string, optional): Transfer purpose.
  * `callback_url` (string, optional): HTTPS notification URL.

#### `POST /api/v1/disbursements/send-money/verify-pin`
Verify withdrawal PIN challenge and execute pending payout.
* **Parameters:** `transaction_id` (string), `pin` (string).

---

### 3.3 Bank Transfers

#### `GET /api/v1/bank-transfer/banks` (Public)
List supported banks with bank codes and names in Uganda.

#### `POST /api/v1/bank-transfer/validate`
Validate a bank account before initiating transfer.
* **Parameters:** `bank_name` (string), `account_number` (string).
* **Returns:** Verified account holder name and validity status.

#### `POST /api/v1/bank-transfer`
Initiate a bank transfer.
* **Parameters:** `amount` (integer), `description` (string), `bank_name` (string), `bank_account_number` (string), `bank_account_name` (optional), `wallet_source` (`'main'` or `'card'`).

#### `GET /api/v1/bank-transfer/{reference}`
Poll bank transfer transaction status by reference UUID.

---

### 3.4 Bill Payments & Utility Verification

#### `GET /api/v1/bill-payment/services`
List supported utility billers (`LIGHT`, `UMEME`, `NWSC`, `DSTV`, `GOTV`).

#### `POST /api/v1/bill-payment/verify`
Validate meter number or customer account before paying.
* **Parameters:** `utility_code` (`LIGHT` | `UMEME` | `NWSC` | `DSTV` | `GOTV`), `meter_number` (string), `area` (required for NWSC), `bouquet_code` (optional for DSTV/GOTV).
* **Returns:** Verified customer name, account status, and outstanding amount.

#### `POST /api/v1/bill-payment`
Execute utility bill payment.
* **Parameters:** `reference` (UUID v4), `utility_code`, `meter_number`, `phone_number`, `amount` (min 1,000 UGX), `area`, `bouquet_code`, `customer_name`.

---

### 3.5 Wallet & Webhooks

#### `GET /api/v1/wallet/balance`
Fetch current balance across all merchant wallets.

#### `GET /api/v1/webhooks` & `POST /api/v1/webhooks`
List or register webhook notifications (`collection.completed`, `collection.failed`, `disbursement.completed`, `disbursement.failed`).

---

## 4. Error Code Reference Table

| HTTP Status | Error Code | Description | Action Required / Fix |
| :--- | :--- | :--- | :--- |
| `400 Bad Request` | `INVALID_UUID` | `reference` parameter is not a valid UUID v4 string | Generate a fresh UUID v4 string using standard UUID generator |
| `400 Bad Request` | `COOLDOWN_ACTIVE` | Phone number attempted multiple collections within 5-min window | Wait 5 minutes before submitting a new collection prompt to the same phone number |
| `400 Bad Request` | `INVALID_PHONE` | Unrecognized phone prefix or unsupported country | Ensure phone number is a valid MTN (+25677/78/76/79/39) or Airtel (+25670/75/74/73) Uganda number |
| `401 Unauthorized` | `INVALID_CREDENTIALS` | Missing or invalid Basic Auth header / API key secret | Verify `MAKYPAY_CLIENT_API_KEY` and `MAKYPAY_CLIENT_API_SECRET` credentials |
| `403 Forbidden` | `INSUFFICIENT_FUNDS` | Merchant wallet balance is insufficient for payout/bill payment | Top up merchant main wallet before retrying disbursement or bill payment |
| `404 Not Found` | `TRANSACTION_NOT_FOUND` | No transaction matches the requested UUID or reference | Verify reference string or check transaction creation status |
| `422 Unprocessable` | `VALIDATION_ERROR` | Required body/form parameters missing or out of bounds | Check amount limits (min 500 UGX) and required parameter schemas |
| `429 Rate Limit` | `RATE_LIMIT_EXCEEDED` | Request rate limit exceeded | Implement exponential backoff retry logic |
| `502 Bad Gateway` | `GATEWAY_ERROR` | Downstream mobile money or bank gateway adapter failed | Retry transaction with same reference ID (idempotent retry) |

---

## 5. Rules for AI Agents

> [!IMPORTANT]
> **Strict Integration Rules for AI Agents:**
>
> 1. **Idempotency & References:**
>    * Every request that creates a collection, disbursement, bank transfer, or bill payment **MUST** include a unique UUID v4 in the `reference` parameter.
>    * Never hardcode or reuse `reference` UUIDs across different payments.
>
> 2. **Never Mark Payments Paid Synchronously:**
>    * Mobile money collections return `status: "pending"` immediately while pushing a USSD prompt to the customer's phone.
>    * **Do NOT** mark an order as paid until receiving a `collection.completed` webhook OR polling `GET /api/v1/collections/collect-money/{reference}` and receiving `status: "completed"`.
>
> 3. **5-Minute Phone Cooldown Rule:**
>    * MakyPay enforces a strict 5-minute per-phone cooldown on collection prompts to protect customers from spam.
>    * Do not retry collection prompts to the same phone number within 5 minutes.
>
> 4. **HTTPS Webhooks Requirement:**
>    * Callback URLs passed to `callback_url` must use secure `https://` URLs.
>
> 5. **Pre-validation Before Execution:**
>    * Call `/bill-payment/verify` before `/bill-payment`.
>    * Call `/bank-transfer/validate` before `/bank-transfer`.

---

## 6. Code Snippets

### Node.js / TypeScript (Using fetch or `@mhl/makypay-sdk`)

```typescript
import { marzPay } from '@mhl/makypay-sdk';

const API_KEY = process.env.MAKYPAY_CLIENT_API_KEY!;
const API_SECRET = process.env.MAKYPAY_CLIENT_API_SECRET!;
const authHeader = 'Basic ' + Buffer.from(`${API_KEY}:${API_SECRET}`).toString('base64');

async function createMobileMoneyCollection(phone: string, amountUGX: number) {
  const reference = crypto.randomUUID(); // Strict UUID v4
  
  const response = await fetch('https://paydb.makycloud.com/api/v1/collections/collect-money', {
    method: 'POST',
    headers: {
      'Authorization': authHeader,
      'Content-Type': 'application/x-www-form-urlencoded',
      'Accept': 'application/json',
    },
    body: new URLSearchParams({
      phone_number: phone,
      amount: amountUGX.toString(),
      reference: reference,
      description: 'Order payment',
      country: 'UG'
    })
  });

  const data = await response.json();
  return data;
}
```

### Python (Using `httpx` or `requests`)

```python
import uuid
import httpx

API_KEY = "your_public_key"
API_SECRET = "your_secret_key"
BASE_URL = "https://paydb.makycloud.com/api/v1"

async def collect_payment(phone: str, amount: int):
    reference = str(uuid.uuid4())
    async with httpx.AsyncClient() as client:
        response = await client.post(
            f"{BASE_URL}/collections/collect-money",
            auth=(API_KEY, API_SECRET),
            data={
                "phone_number": phone,
                "amount": amount,
                "reference": reference,
                "description": "Subscription Renewal",
                "country": "UG"
            }
        )
        return response.json()
```

### PHP (Using cURL)

```php
<?php
$apiKey = getenv('MAKYPAY_CLIENT_API_KEY');
$apiSecret = getenv('MAKYPAY_CLIENT_API_SECRET');
$reference = vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex(random_bytes(16)), 4));

$ch = curl_init('https://paydb.makycloud.com/api/v1/collections/collect-money');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_USERPWD, "$apiKey:$apiSecret");
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'phone_number' => '+256770000000',
    'amount' => 5000,
    'reference' => $reference,
    'description' => 'PHP Integration Payment'
]));

$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
```

---

## 7. Starter Prompt for AI Agents

Copy and paste the following prompt when instructing an AI agent to integrate MakyPay into an application:

```markdown
You are an expert software engineer integrating the MakyPay payment gateway into our application.
Refer to the official live MakyPay integration skill guide at `https://paydb.makycloud.com/llms.txt` or `https://paydb.makycloud.com/skill.md`.

Follow these mandatory integration rules:
1. Authenticate using HTTP Basic Authentication (`Authorization: Basic base64(API_KEY:API_SECRET)`).
2. Generate a fresh UUID v4 for the `reference` parameter on every payment request.
3. Mobile money collections require `phone_number` and `amount`. Card payments require `method="card"`.
4. Do NOT mark orders or transactions as paid immediately. Mobile money requests return status `pending`. Wait for a `collection.completed` webhook or poll `GET /api/v1/collections/collect-money/{reference}`.
5. Always validate bank accounts via `POST /api/v1/bank-transfer/validate` before creating bank transfers.
6. Always verify utility meters via `POST /api/v1/bill-payment/verify` before executing bill payments.
```
