POST https://mybundlepay.com/ng/api/v1/card/customers/enroll

KEY USAGE POLICY

Important: You must always begin your integration using your test_secret_key. This ensures you can simulate requests and validate your flows without creating real customers or transactions.

  • Use test_secret_key for all development, testing, and sandbox calls.
  • Only switch to secret_key (Live Key) after your integration has been fully tested and approved.
  • Requests with test_secret_key return simulated responses and do not persist customers in the live mode.
  • Requests with secret_key (Live) will create real customers and trigger production flows.

⚠️ Going live without first testing may cause failed enrollments or blocked access.

HEADERS

Authorization * string

Pass your {secret_key} as a Bearer token in the request header to authorize this call.

Content-Type * application/json

All requests must be sent in JSON format.

IP WHITELISTING

For extra security this endpoint checks that the calling IP is whitelisted for your business. The API checks these headers (in order):

  • CF-Connecting-IP (useful when behind Cloudflare)
  • X-Forwarded-For
  • fallback to the remote IP ($request->ip())

If your IP is not whitelisted or blocked, the API returns a 403 with a descriptive code (examples below).

How to send the IP from Postman / curl

CF-Connecting-IP: 203.0.113.5
X-Forwarded-For: 203.0.113.5
                                

You can set one or both headers in Postman → Headers tab. If using a reverse proxy, ensure the real client IP is forwarded.

BODY PARAMS

Customer’s first name.

Customer’s last name.

Valid email address of the customer.

2-letter ISO country code (e.g. US, NG, GH).

Government issued ID number (DRIVERS_LICENSE, NIN, VOTERS_CARD, PASSPORT).

Date of birth. Use 20-10-1988 (ISO) to avoid validation errors.

International dialing code (e.g. +1, +234, +261).

Customer’s phone number (without country code).

Example structure:


"identity": {
  "type": "PASSPORT",
  "image": "https://example.com/id.jpg",   // optional (URL)
  "number": "A12345678"
}
                                

Note: do not send 3-letter country codes (use 2-letter codes). Some MyBundlePay flows do not require identity.country — prefer using top-level country and address.country.


"address": {
  "street": "123 Main Street",
  "street2": null,
  "city": "New York",
  "state": "NY",
  "country": "US",
  "postal_code": "10001"
}
                                

country must be 2-letter ISO code and in many cases MyBundlePay only allows certain supported countries — if you get a 400 about address.country try removing the field or using a supported country.

Passport style photo of the customer (URL link).


<?php
$curl = curl_init();
curl_setopt_array($curl, array(
    CURLOPT_URL => "https://mybundlepay.com/ng/api/v1/card/customers/enroll",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => json_encode([
        "first_name" => "John",
        "last_name" => "Doe",
        "email" => "johndoe@example.com",
        "country" => "US",
        "identification_number" => "A12345678",
        "dob" => "01-01-1990",
        "phone_country_code" => "+1",
        "phone_number" => "5551234567",
        "identity" => [
            "type" => "PASSPORT",
            "image" => "https://example.com/passport.jpg",
            "number" => "A12345678"
        ],
        "address" => [
            "street" => "123 Main Street",
            "street2" => null,
            "city" => "New York",
            "state" => "NY",
            "country" => "US",
            "postal_code" => "10001"
        ],
        "photo" => "https://example.com/photo.jpg"
    ]),
    CURLOPT_HTTPHEADER => array(
        "Content-Type: application/json",
        "Authorization: Bearer {secret_key}",
        "CF-Connecting-IP: 203.0.113.5" // Optional - set to your whitelisted IP
    ),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
?>

const axios = require('axios');

const data = {
  first_name: "John",
  last_name: "Doe",
  email: "johndoe@example.com",
  country: "US",
  identification_number: "A12345678",
  dob: "01-01-1990",
  phone_country_code: "+1",
  phone_number: "5551234567",
  identity: { type: "PASSPORT", image: "https://example.com/id.jpg", number: "A12345678" },
  address: { street: "123 Main St", street2: null, city: "NY", state: "NY", country: "US", postal_code: "10001" },
  photo: "https://example.com/photo.jpg"
};

axios.post("https://mybundlepay.com/ng/api/v1/card/customers/enroll", data, {
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer {secret_key}",
    "X-Forwarded-For": "203.0.113.5" // Optional - set to your whitelisted IP
  }
}).then(res => {
  console.log(res.data);
}).catch(err => {
  console.error(err.response ? err.response.data : err.message);
});
Success Response

{
  "status": "success",
  "message": "Customer created successfully",
  "data": {
    "id": 1,
    "business_id": "f2fca2f5-b3f1-4759-8bb7-b9f0bb9c0060",
    "first_name": "John",
    "last_name": "Doe",
    "email": "johndoe@example.com",
    "country": "US",
    "phone_country_code": "+1",
    "phone_number": "5551234567",
    "identification_number": "A12345678",
    "dob": "01-01-1990",
    "identity_type": "PASSPORT",
    "identity_number": "A12345678",
    "identity_image": "https://example.com/id.jpg",
    "address_street": "123 Main Street",
    "address_city": "New York",
    "address_state": "NY",
    "address_country": "US",
    "address_postal_code": "10001",
    "photo": "https://example.com/photo.jpg",
    "MyBundlePay_customer_id": "f743070f-d37f-4e7e-bddc-4865fe069927",
    "MyBundlePay_status": "COMPLETED",
    "MyBundlePay_tier": 2,
    "raw_response": { /* MyBundlePay response object */ },
    "created_at": "2025-09-28T15:34:17Z",
    "updated_at": "2025-09-28T15:34:17Z"
  }
}
Common Error Responses

Missing token401


{
  "status": "failed",
  "code": "TOKEN_REQUIRED",
  "message": "Authorization token is required."
}

Invalid token / business not found401 / 404


{
  "status": "failed",
  "code": "BUSINESS_NOT_FOUND",
  "message": "Business not found for this secret key."
}

IP not whitelisted403


{
  "status": "failed",
  "code": "IP_NOT_WHITELISTED",
  "message": "Your IP is not authorized for API access.",
  "ip": "203.0.113.5"
}

IP blocked403


{
  "status": "failed",
  "code": "IP_BLOCKED",
  "message": "Your IP has been blocked from API access.",
  "ip": "203.0.113.5"
}

IP status not allowed403


{
  "status": "failed",
  "code": "IP_STATUS_NOT_ALLOWED",
  "message": "Your IP status does not permit API access.",
  "ip": "203.0.113.5"
}

Invalid secret key400


{
  "status": "failed",
  "message": "Invalid secret key",
  "data": null
}

Invalid token format401


{
  "status": "failed",
  "message": "Invalid token format"
}

Validation errors400


{
  "status": "failed",
  "message": {
    "email": ["The email field is required."],
    "dob": ["The dob must be in YYYY-MM-DD format."]
  }
}

Customer already exists (idempotent)200


{
  "status": "success",
  "code": "ALREADY_EXISTS",
  "message": "Customer already enrolled for this business",
  "data": { /* existing customer object */ }
}

MyBundlePay returned an error400


{
  "status": "failed",
  "message": "Exception contacting MyBundlePay",
  "data": {
    "status": false,
    "message": "Field validation failed",
    "error": "HTTP request returned status code 400: { ... }"
  }
}

Note: codes like IP_NOT_WHITELISTED, IP_BLOCKED are exact and should be used by integrators to handle flows programmatically.