---
title: "Pay a mobile wallet in Rwanda, Uganda, Zambia or Congo"
description: "Pick the right operator row, save a mobile wallet payee with a phone number in the accepted form, and send local currency."
---
Use this recipe to pick the right operator row, save a mobile wallet payee with a phone number in an accepted format, and send local currency to Rwanda, Uganda, Zambia or the Republic of the Congo.

**Who it is for.** Jean-Paul, a Toronto engineer using your app, sends money to his sister's mobile wallet in Kigali. Another user pays a supplier's wallet in Lusaka.

**Status.** Available on the operator rows `MTN MoMo Rwanda`, `MTN MoMo Uganda`, `MTN MoMo Zambia` and `MTN MoMo Congo` (Republic of the Congo). Other operators in these countries are not yet available.

## Money example

1. Jean-Paul sends 150.00 USD. Say the fee on your plan is 1.00 USD.
2. Say the rate is 1,420.00 RWF per USD. The transfer response prices 213,000.00 RWF for his sister (`local_amount`).
3. Zambia works the same way. At a rate of 26.50 ZMW per USD, the transfer response prices 100.00 USD at 2,650.00 ZMW.

## Before you start

- The sender has a name and a country (`first_name`, `last_name` and `address.country` on [the customer](/api-reference/customers/get-v1-customers-customer-id)). This route does not pay without both. You can also send them as `additional_information.remitter_full_name` and `remitter_country`.
- The USD account is `active` and funded.

## Find out what is required

### The currency

[`GET /v1/transfer/supported-countries?iso_code=RW`](/api-reference/transfer/get-v1-transfer-supported-countries) returns `RWF`. `ZM` returns `ZMW`, and `UG` returns `UGX`. For `CG`, the list has no currency (`currency_code` is `null`). Use `XAF`, which the operator row for CG carries.

### The operator row

<CodeGroup>
```bash title="cURL"
curl --request GET \
     --url 'https://api.gravv.xyz/v1/external-accounts/institutions?country_iso_code=RW&institution_type=mobile_money' \
     --header 'Api-Key: <API_KEY>'
```
```javascript title="Node"
const response = await fetch("https://api.gravv.xyz/v1/external-accounts/institutions?country_iso_code=RW&institution_type=mobile_money", {
  method: "GET",
  headers: {
    "Api-Key": process.env.GRAVV_API_KEY,
  },
});
console.log(response.status, await response.json());
```
```python title="Python"
import os

import requests

response = requests.get(
    "https://api.gravv.xyz/v1/external-accounts/institutions?country_iso_code=RW&institution_type=mobile_money",
    headers={
        "Api-Key": os.environ["GRAVV_API_KEY"],
    },
)
print(response.status_code, response.json())
```
</CodeGroup>

```json title="Response"
{
  "data": {
    "items": [
      {
        "account_number_type": "phone_number",
        "country_iso_code": "RW",
        "currency": "RWF",
        "id": "e3077661-0359-4740-b6bb-bad5f4e965fd",
        "max_amount": 0,
        "min_amount": 0,
        "name": "MTN MoMo Rwanda"
      },
      {
        "account_number_type": "phone_number",
        "country_iso_code": "RW",
        "currency": "RWF",
        "id": "f6a7b8c9-0d1e-4f25-8a7b-8c9d0e1f2a33",
        "max_amount": 10000,
        "min_amount": 1,
        "name": "MTN Mobile Money"
      }
    ],
    "items_per_page": 10,
    "page": 1,
    "total_items": 2,
    "total_pages": 1
  },
  "error": null
}
```

Pick the row whose name is `MTN MoMo` followed by the country:

| Country | Operator row | `institution_id` |
| :-- | :-- | :-- |
| Rwanda | `MTN MoMo Rwanda` | `e3077661-0359-4740-b6bb-bad5f4e965fd` |
| Zambia | `MTN MoMo Zambia` | `52a0b270-79a1-44ba-a21f-dfa4fac926a0` |
| Uganda | `MTN MoMo Uganda` | `939461ba-a4f7-40e3-a3be-9e6cf076b0f3` |
| Republic of the Congo | `MTN MoMo Congo` | `181402b4-4709-4d4e-b077-810927e99c9f` |

Older rows with other names can also appear for Rwanda and Zambia. This route does not pay payees saved on those rows. Ids can differ between sandbox and live, so confirm them from the list.

### The phone number

Gravv ignores spaces, `+` and a leading `00`.

| Country | Dial code | Digits after it | Accepted examples |
| :-- | :-- | :-- | :-- |
| Rwanda | 250 | 9 | `+250788123456`, `0788123456`, `788123456` |
| Zambia | 260 | 9 | `+260961234567`, `0961234567`, `961234567` |
| Uganda | 256 | 9 | `+256772123456`, `0772123456`, `772123456` |
| Republic of the Congo | 242 | 9, keeping its leading 0 | `+242067700123`, `067700123` |

Gravv refuses a number in any other format at payout, not when you save the payee.

## Steps

### 1. Save the payee

When you save the payee, Gravv checks the wallet's name with the operator and replaces `account_name` with it.

<CodeGroup>
```bash title="cURL"
curl --request POST \
     --url https://api.gravv.xyz/v1/external-accounts \
     --header 'Api-Key: <API_KEY>' \
     --header 'Content-Type: application/json' \
     --header 'Idempotency-Key: a396d467-ed6a-425c-9a80-c1ef779e4495' \
     --data '
{
  "customer_id": "e0c40bf4-c1a6-4714-bde1-316a1c15e956",
  "payee_type": "mobile_money",
  "currency": "RWF",
  "account_name": "Claudine Uwase",
  "phone_number": "+250788123456",
  "institution_id": "e3077661-0359-4740-b6bb-bad5f4e965fd"
}
'
```
```javascript title="Node"
const response = await fetch("https://api.gravv.xyz/v1/external-accounts", {
  method: "POST",
  headers: {
    "Api-Key": process.env.GRAVV_API_KEY,
    "Content-Type": "application/json",
    "Idempotency-Key": "a396d467-ed6a-425c-9a80-c1ef779e4495",
  },
  body: JSON.stringify({
    "customer_id": "e0c40bf4-c1a6-4714-bde1-316a1c15e956",
    "payee_type": "mobile_money",
    "currency": "RWF",
    "account_name": "Claudine Uwase",
    "phone_number": "+250788123456",
    "institution_id": "e3077661-0359-4740-b6bb-bad5f4e965fd"
  }),
});
console.log(response.status, await response.json());
```
```python title="Python"
import os

import requests

response = requests.post(
    "https://api.gravv.xyz/v1/external-accounts",
    headers={
        "Api-Key": os.environ["GRAVV_API_KEY"],
        "Content-Type": "application/json",
        "Idempotency-Key": "a396d467-ed6a-425c-9a80-c1ef779e4495",
    },
    json={
        "customer_id": "e0c40bf4-c1a6-4714-bde1-316a1c15e956",
        "payee_type": "mobile_money",
        "currency": "RWF",
        "account_name": "Claudine Uwase",
        "phone_number": "+250788123456",
        "institution_id": "e3077661-0359-4740-b6bb-bad5f4e965fd",
    },
)
print(response.status_code, response.json())
```
</CodeGroup>

```json title="Response (HTTP 200)"
{
  "data": {
    "id": "ad2fee6e-161f-4b04-ac5f-39ed4e9182bc",
    "institution_id": "e3077661-0359-4740-b6bb-bad5f4e965fd",
    "payee_type": "mobile_money",
    "institution_type": "mobile_money",
    "institution_name": "MTN MoMo Rwanda",
    "account_name": "CLAUDINE UWASE",
    "customer_id": "e0c40bf4-c1a6-4714-bde1-316a1c15e956",
    "currency": "RWF",
    "institution_country_iso_code": "RW",
    "status": "active",
    "phone_number": "+250788123456",
    "date_created": "2026-10-13T11:00:04.871Z"
  },
  "error": null
}
```

### 2. Send

<CodeGroup>
```bash title="cURL"
curl --request POST \
     --url https://api.gravv.xyz/v1/transfer \
     --header 'Api-Key: <API_KEY>' \
     --header 'Content-Type: application/json' \
     --header 'Idempotency-Key: 04bd7913-20a3-4369-84a4-8232f1cdae2a' \
     --data '
{
  "customer_id": "e0c40bf4-c1a6-4714-bde1-316a1c15e956",
  "source": {
    "source_type": "internal_account",
    "id": "5151220a-b97c-442a-8cf5-b48ec96c8779"
  },
  "destination": {
    "destination_type": "external_account",
    "id": "ad2fee6e-161f-4b04-ac5f-39ed4e9182bc"
  },
  "amount": "150.00",
  "description": "School fees",
  "client_reference": "jp-rw-2026-10-003",
  "additional_information": {
    "remitter_full_name": "Jean-Paul Habimana",
    "remitter_country": "CA"
  }
}
'
```
```javascript title="Node"
const response = await fetch("https://api.gravv.xyz/v1/transfer", {
  method: "POST",
  headers: {
    "Api-Key": process.env.GRAVV_API_KEY,
    "Content-Type": "application/json",
    "Idempotency-Key": "04bd7913-20a3-4369-84a4-8232f1cdae2a",
  },
  body: JSON.stringify({
    "customer_id": "e0c40bf4-c1a6-4714-bde1-316a1c15e956",
    "source": {
      "source_type": "internal_account",
      "id": "5151220a-b97c-442a-8cf5-b48ec96c8779"
    },
    "destination": {
      "destination_type": "external_account",
      "id": "ad2fee6e-161f-4b04-ac5f-39ed4e9182bc"
    },
    "amount": "150.00",
    "description": "School fees",
    "client_reference": "jp-rw-2026-10-003",
    "additional_information": {
      "remitter_full_name": "Jean-Paul Habimana",
      "remitter_country": "CA"
    }
  }),
});
console.log(response.status, await response.json());
```
```python title="Python"
import os

import requests

response = requests.post(
    "https://api.gravv.xyz/v1/transfer",
    headers={
        "Api-Key": os.environ["GRAVV_API_KEY"],
        "Content-Type": "application/json",
        "Idempotency-Key": "04bd7913-20a3-4369-84a4-8232f1cdae2a",
    },
    json={
        "customer_id": "e0c40bf4-c1a6-4714-bde1-316a1c15e956",
        "source": {
            "source_type": "internal_account",
            "id": "5151220a-b97c-442a-8cf5-b48ec96c8779",
        },
        "destination": {
            "destination_type": "external_account",
            "id": "ad2fee6e-161f-4b04-ac5f-39ed4e9182bc",
        },
        "amount": "150.00",
        "description": "School fees",
        "client_reference": "jp-rw-2026-10-003",
        "additional_information": {
            "remitter_full_name": "Jean-Paul Habimana",
            "remitter_country": "CA",
        },
    },
)
print(response.status_code, response.json())
```
</CodeGroup>

```json title="Response"
{
  "data": {
    "amount": "150",
    "amount_currency": "USD",
    "reference": "c62d1693-2a10-4897-8b1d-279d3d64a646",
    "date_created": "2026-10-13T11:02:40.300Z",
    "transfer_status": "pending",
    "transaction_id": "22a31043-d85f-44b8-abfd-94bd2924a529",
    "local_amount": "213000",
    "local_currency": "RWF",
    "fee": "1",
    "fee_currency": "USD",
    "requires_approval": false
  },
  "error": null
}
```

### 3. Follow it

Use the webhooks, or poll [`GET /v1/transactions/22a31043-d85f-44b8-abfd-94bd2924a529`](/api-reference/transactions/get-v1-transactions-transaction-id). Gravv asks the operator for the status, so the completion arrives as a later webhook.

## What can go wrong

| Response | Why | Fix |
| :-- | :-- | :-- |
| 400 `account verification failed: bank could not resolve account holder: invalid input` when saving | The number is not an active wallet | Check the number |
| 400 `account verification temporarily unavailable; please retry: invalid input` | The operator's name check is down | Retry with a new key |
| 400 `transfers to RW/RWF are not supported at this time` | No route can pay this country and currency now | Contact support |
| 400 `this payee is not yet set up for transfers — please contact support to complete its setup` | The payee is on another row, or has no `institution_id` | Save the payee on the right operator row |
| 400 `destination currency is required for international transfers` | The payee has no currency | Use the country's currency: RWF, ZMW, UGX or XAF |
| `transfer.status.failed` after acceptance, and a refund row | The phone number is not in an accepted format, the sender's name or country is missing, or the operator refused the amount | Save a new payee with the right number, add the sender details, or change the amount |
| `transfer.status.failed`, but the transaction is still `pending` | The operator's response was unclear, so a person checks it | Do not send it again. Contact support with the `reference` |

## Webhooks you will receive

1. `external_account.created`.
2. `transfer.status.pending`, several times.
3. `transfer.status.completed` or `transfer.status.failed`.

## Testing in sandbox

Sandbox does not simulate the wallet name check. It calls the operator's own test system, so the results depend on that system.

- A Uganda payee on `+256772123456` was saved, and a 5.00 USD payout completed within 3 minutes.
- Rwanda numbers were refused at save time.
- Zambia returned `account verification temporarily unavailable` on repeated tries.

## Reference

- [List institutions](/api-reference/external-accounts/get-v1-external-accounts-institutions)
- [Add an external account](/api-reference/external-accounts/post-v1-external-accounts)
- [Create a transfer](/api-reference/transfer/post-v1-transfer)
