---
title: Data Plans
description: Purchase mobile data bundles for all major networks
---

Buy daily, weekly, and monthly data bundles for MTN, Airtel, Glo, and 9mobile.

## Supported Networks

| Network        | Code      |
| -------------- | --------- |
| MTN Nigeria    | `MTN`     |
| Airtel Nigeria | `AIRTEL`  |
| Globacom       | `GLO`     |
| 9mobile        | `9MOBILE` |

## Bundle Types

Each plan carries a free-form `bundle_type` tag describing the plan family
(for example `SME`, `NIGHT`, `SOCIAL`, `SG GIFTING`). It can be `null` when
a plan is not categorised. Use the `duration` field for validity. Filter
the products endpoint by `bundle_type` to narrow results.

## Purchase Flow

Data plan purchases are straightforward - no verification required.

1. **List products** - Get available data plans
2. **Make purchase** - Send the purchase request

## Step 1: List Products

Filter by network and/or bundle type:

```bash
curl -X GET \
  -H "Authorization: Bearer sk_live_your_secret_key" \
  "https://my.rizpay.app/api/partners/v1/products/dataplans?network=MTN&bundle_type=monthly"
```

Response:

```json
{
  "status": { "code": 200, "message": "Success" },
  "data": [
    {
      "id": "prd_2270",
      "type": "data_plan",
      "attributes": {
        "display_name": "MTN 75MB / 1 Day (SG GIFTING)",
        "network": "MTN",
        "bundle_size": "75MB",
        "duration": "1 Day",
        "bundle_type": "SG GIFTING",
        "price": {
          "amount": "77.60",
          "currency": "NGN",
          "basis": "fixed"
        }
      }
    },
    {
      "id": "prd_2271",
      "type": "data_plan",
      "attributes": {
        "display_name": "MTN 2GB / 30 Days",
        "network": "MTN",
        "bundle_size": "2GB",
        "duration": "30 Days",
        "bundle_type": null,
        "price": {
          "amount": "1000.00",
          "currency": "NGN",
          "basis": "fixed"
        }
      }
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total_pages": 3,
    "total_count": 45
  }
}
```

Product ids are numeric with a `prd_` prefix (e.g. `prd_2270`). Use the
`id` from your own response in the purchase request. `bundle_type` may be
`null` when the plan is not categorised.

### The `price` block

Data plans are catalog-priced - RizPay returns a single `fixed` amount per
plan. The `amount` is your cost, not the retail price: it is what RizPay
bills you, and you set what your customer pays by adding your own markup. A
figure in the plan name is a label, not the price, so don't parse the name
yourself - when we can confidently read one, we return it as
`reference_price`. See [Pricing your products](/docs/core-concepts/pricing)
for worked examples.

| Field             | Type   | Notes                                                  |
| ----------------- | ------ | ------------------------------------------------------ |
| `amount`          | string | What RizPay will bill you per unit of this plan        |
| `reference_price` | string | Optional best-effort guide value; omitted when unknown |
| `currency`        | string | Always `NGN`                                           |
| `basis`           | string | `fixed`                                                |

## Step 2: Make Purchase

```bash
curl -X POST \
  -H "Authorization: Bearer sk_live_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": "prd_2271",
    "phone_number": "08012345678",
    "network": "MTN",
    "external_reference": "1736234400C3D4E5"
  }' \
  https://my.rizpay.app/api/partners/v1/purchases
```

**Note:** For data plans, the amount is fixed by the plan. You don't need
to specify it. Include the `network` matching the plan you selected.

Response:

```json
{
  "status": { "code": 201, "message": "Purchase created successfully" },
  "data": {
    "id": "txn_abc123",
    "type": "transaction",
    "attributes": {
      "amount": "1000.0",
      "currency": "NGN",
      "status": "pending",
      "category": "purchase",
      "description": "Purchase of MTN 2GB - 30 Days",
      "reference": "a26e6eb0cd196076ea2b",
      "external_reference": "1736234400C3D4E5",
      "product_type": "data_plan",
      "phone_number": "08012345678",
      "meter_number": null,
      "price": {
        "product_amount": "1000.00",
        "fee_amount": "0.00",
        "total_debit": "1000.00",
        "currency": "NGN",
        "basis": "fixed"
      },
      "created_at": "2026-05-18T10:30:00+01:00",
      "updated_at": "2026-05-18T10:30:00+01:00"
    }
  }
}
```

### The `price` breakdown

Same breakdown as airtime. For data plans the `basis` is `fixed` because
the catalog price is the bill, with no partner-supplied amount.

## Check Transaction Status

```bash
curl -X GET \
  -H "Authorization: Bearer sk_live_your_secret_key" \
  "https://my.rizpay.app/api/partners/v1/purchases/txn_abc123"
```

Successful response:

```json
{
  "status": { "code": 200, "message": "Purchase details retrieved" },
  "data": {
    "id": "txn_abc123",
    "type": "transaction",
    "attributes": {
      "amount": "1000.0",
      "currency": "NGN",
      "status": "successful",
      "category": "purchase",
      "description": "Purchase of MTN 2GB - 30 Days",
      "reference": "a26e6eb0cd196076ea2b",
      "external_reference": "1736234400C3D4E5",
      "product_type": "data_plan",
      "phone_number": "08012345678",
      "meter_number": null,
      "price": {
        "product_amount": "1000.00",
        "fee_amount": "0.00",
        "total_debit": "1000.00",
        "currency": "NGN",
        "basis": "fixed"
      },
      "created_at": "2026-05-18T10:30:00+01:00",
      "updated_at": "2026-05-18T10:30:02+01:00"
    }
  }
}
```

The transaction is done when `status` reaches `successful`, `failed`, or
`reversed`. There is no separate completion timestamp: use `updated_at`.

## Complete Example

```javascript
// Generate external reference: 10-digit timestamp + 6 alphanumeric
function generateReference() {
  const timestamp = Math.floor(Date.now() / 1000);
  const chars =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  let suffix = "";
  for (let i = 0; i < 6; i++) {
    suffix += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return `${timestamp}${suffix}`;
}

async function purchaseDataPlan(network, bundleType, bundleSize, phoneNumber) {
  const API_KEY = "sk_live_your_secret_key";
  const BASE_URL = "https://my.rizpay.app/api/partners/v1";

  // Step 1: Find matching data plans
  const params = new URLSearchParams({
    network: network,
    bundle_type: bundleType,
  });

  const productsRes = await fetch(`${BASE_URL}/products/dataplans?${params}`, {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });
  const products = await productsRes.json();

  // Find the plan matching the requested bundle size
  const product = products.data.find(
    (p) => p.attributes.bundle_size === bundleSize
  );
  if (!product) {
    throw new Error(`No ${bundleSize} ${bundleType} plan found for ${network}`);
  }

  // Step 2: Make purchase
  const purchaseRes = await fetch(`${BASE_URL}/purchases`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      product_id: product.id,
      phone_number: phoneNumber,
      network: product.attributes.network,
      external_reference: generateReference(),
    }),
  });

  return await purchaseRes.json();
}

// Usage
purchaseDataPlan("MTN", "monthly", "2GB", "08012345678")
  .then((result) => console.log(result))
  .catch((error) => console.error(error));
```

## Listing All Plans for a User

Build a plan selector by fetching all plans:

```javascript
async function getDataPlans(network) {
  const API_KEY = "sk_live_your_secret_key";
  const BASE_URL = "https://my.rizpay.app/api/partners/v1";

  const response = await fetch(
    `${BASE_URL}/products/dataplans?network=${network}&per_page=100`,
    { headers: { Authorization: `Bearer ${API_KEY}` } }
  );
  const data = await response.json();

  // Group by bundle type. `bundle_type` may be null for uncategorised plans.
  const grouped = {};

  data.data.forEach((plan) => {
    const attrs = plan.attributes;
    const key = attrs.bundle_type || "other";
    (grouped[key] ||= []).push({
      id: plan.id,
      name: `${attrs.bundle_size} - ₦${attrs.price.amount}`,
      size: attrs.bundle_size,
      price: attrs.price.amount,
      duration: attrs.duration,
    });
  });

  return grouped;
}
```

## Popular Plans

### MTN

| Plan | Price  | Validity |
| ---- | ------ | -------- |
| 1GB  | ~500   | 30 days  |
| 2GB  | ~1,000 | 30 days  |
| 5GB  | ~2,000 | 30 days  |
| 10GB | ~3,500 | 30 days  |

### Airtel

| Plan | Price  | Validity |
| ---- | ------ | -------- |
| 1GB  | ~500   | 30 days  |
| 2GB  | ~1,000 | 30 days  |
| 6GB  | ~2,000 | 30 days  |

_Prices may vary. Always check the products endpoint for current pricing._

## Transaction States

| Status       | Description                        |
| ------------ | ---------------------------------- |
| `pending`    | Processing with provider           |
| `successful` | Data plan activated                |
| `failed`     | Purchase failed (balance refunded) |

## Required Scope

Requires the `purchase_data` scope on your API key.

## Next Steps

- [Airtime](/docs/products/airtime) - Purchase airtime
- [Electricity](/docs/products/electricity) - Pay electricity bills
- [Webhooks](/docs/webhooks/overview) - Get notified when purchase completes