Payment Integration Guide

This guide explains how to use our API to initiate payments. Ensure you have completed the Payment Requirements & Setup first.

Authentication

All Payment API requests must be authenticated using your specific App's API keys. Include your Access Key in the request header:

Header:
access_key: YOUR_ACCESS_API_KEY

Replace YOUR_ACCESS_API_KEY with the actual Access Key generated for your application in the dashboard.

API Base URL

All API endpoints mentioned in this documentation should be appended to the following base URL:

https://api.weflexfy.com

Initiate a Payment

To start a new payment process, make a POST request to the following endpoint (appended to the base URL):

POST /api/v1/payment/initiate

Request Body

The request body must be a JSON object containing the details of the payment and the transfers involved. Here are the key fields:

  • amount (number, required): The total amount being billed (sum of all transfers).
  • currency (string, required): The currency code. Supported values: "RWF", "USD".
  • billName (string, optional): The name of the customer making the payment.
  • billEmail (string, optional): The email address of the customer.
  • billPhone (string, optional): The phone number of the customer (international format).
  • billCountry (string, optional): The 2-letter country code of the customer (e.g., "RW").
  • transfers (array, required): An array of transfer objects, each specifying a recipient and amount/percentage. The sum of percentages across all transfers must equal 100.
    • percentage (number, required): The percentage of the total amount for this specific transfer.
    • recipientNumber (string, required): The recipient's phone number (international format).
    • payload (object, optional): Any JSON object containing custom data you want associated with this specific transfer leg. This payload will be returned to you in the response and webhook notifications, useful for tracking or identification purposes.

Note on Transfers: For Mobile Money (MOMO) payments, the transfers specified in the `transfers` array are processed in real-time immediately after the customer successfully completes the payment.

Example Request Body

{
  "amount": 100,
  "currency": "RWF",
  "billName": "Customer Name",
  "billEmail": "customer@example.com",
  "billPhone": "+250780000000",
  "billCountry": "RW",
  "transfers": [
    {
      "percentage": 70,
      "recipientNumber": "+250780000000",
      "payload": { "orderId": "ORD-12345", "internalRef": "REF-ABC" }
    },
    {
      "percentage": 30,
      "recipientNumber": "+250780000000",
      "payload": { "orderId": "ORD-12345", "internalRef": "REF-DEF" }
    }
  ]
}

This example shows a total bill amount of 100 RWF, split into two transfers based on percentages (70% and 30%) to potentially different or the same recipients.

Code Examples

const initiatePayment = async () => {
  const apiKey = 'YOUR_ACCESS_API_KEY'; // Replace with your actual API key
  const baseUrl = 'https://api.weflexfy.com';
  const endpoint = '/api/v1/payment/initiate';

  const payload = {
    amount: 100,
    currency: "RWF",
    billName: "Customer Name",
    billEmail: "customer@example.com",
    billPhone: "+250780000000",
    billCountry: "RW",
    transfers: [
      {
        percentage: 70,
        recipientNumber: "+250780000000",
        payload: { "orderId": "ORD-12345", "internalRef": "REF-ABC" }
      },
      {
        percentage: 30,
        recipientNumber: "+250780000000",
        payload: { "orderId": "ORD-12345", "internalRef": "REF-DEF" }
      }
    ]
  };

  try {
    const response = await fetch(baseUrl + endpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'access_key': apiKey
      },
      body: JSON.stringify(payload)
    });

    const data = await response.json();

    if (!response.ok) {
      console.error('API Error:', data);
      throw new Error(data.message || `HTTP error! status: ${response.status}`);
    } else {
      console.log('Payment Initiated:', data);
      // Example: if (data.paymentUrl) window.location.href = data.paymentUrl;
    }

  } catch (error) {
    console.error('Request Failed:', error);
  }
};

initiatePayment();

Remember to replace 'YOUR_ACCESS_API_KEY' with your actual Access Key. These examples include basic error handling.

Successful Response (201 Created)

If the payment initiation request is successful, the server will respond with an HTTP status code of 201 Created. The response body will be a JSON object containing details about the initiated payment and the next steps.

Response Body Fields

  • message (string): A confirmation message (e.g., "Payment initiated successfully").
  • status (string): Indicates the outcome (e.g., "success").
  • data (object): Contains the detailed information about the payment request.
    • requestToken (string): A unique identifier for this payment request.
    • amount (string): The total amount requested for payment (formatted as a string).
    • currency (string): The currency used (e.g., "RWF").
    • iframeUrl (string): The URL to redirect the customer to (or load in an iframe) to complete the payment process. This is the crucial next step.
    • transfers (array): Details about each individual transfer created as part of this payment request.
      • amount (number): The calculated amount for this specific transfer (based on the percentage provided in the request).
      • recipientNumber (string): The recipient's phone number.
      • transferRef (string): A unique reference ID for this specific transfer leg.
      • status (string): The initial status of the transfer (e.g., "DRAFT"). This will update via webhooks as the payment progresses.
      • payload (object | null): The custom payload object you provided in the request for this transfer leg, or `null` if none was provided. Useful for correlating transfers back to your internal system records.

Example Successful Response Body

{
  "message": "Payment initiated successfully",
  "status": "success",
  "data": {
    "requestToken": "1137f53c-4128-4165-bb0e-bcf3f00ca149",
    "amount": "100.00",
    "currency": "RWF",
    "iframeUrl": "https://weflexfy.com/payment/1137f53c-4128-4165-bb0e-bcf3f00ca149",
    "transfers": [
      {
        "amount": 67,
        "recipientNumber": "0780000000",
        "transferRef": "CRPWEC9619576068",
        "status": "DRAFT",
        "payload": { "orderId": "ORD-12345", "internalRef": "REF-ABC" }
      },
      {
        "amount": 28,
        "recipientNumber": "0780000000",
        "transferRef": "CRPWEC5629210566",
        "status": "DRAFT",
        "payload": { "orderId": "ORD-12345", "internalRef": "REF-DEF" }
      }
    ]
  }
}

This example response assumes the example request (including the custom `payload` objects) was sent.

After receiving this response, you should typically redirect the user to the provided iframeUrl to authorize and complete the payment.

Webhook Notifications

Our system uses webhooks to send you real-time updates about the status of payments and individual transfers. When an event occurs (e.g., payment success, transfer completion, failure), we will send a POST request to the webhook URL you configured for your application.

The body of this POST request contains a single JWT (JSON Web Token) named token and a requestType field to differentiate between event types.

{"token": "YOUR_RECEIVED_JWT_TOKEN","requestType": "payment" // or "transfer"}

Verifying Webhooks & Decoding Data

It is critical that you verify the signature of the received JWT (the token field) using the Secret Key associated with your application. This ensures the webhook notification is genuinely from our system and hasn't been tampered with.

Most JWT libraries provide a function to verify and decode a token simultaneously. You will need your App's Secret Key for this verification step. If the signature is valid, the library will return the decoded payload containing the event data.

Conceptual Verification (Pseudocode):

// 1. Get the token from the request body
received_token = request.body.token

// 2. Get your App's Secret Key (from secure storage)
secret_key = YOUR_APP_SECRET_KEY

// 3. Try to verify and decode using your JWT library
try {
  decoded_payload = jwt.verify(received_token, secret_key)
  
  // 4. Verification successful! Use the data in decoded_payload
  print("Webhook verified. Payload:", decoded_payload)
  
  // 5. Process the event based on requestType and payload data
  if request.body.requestType == "payment":
     // Process payment update using decoded_payload
  else if request.body.requestType == "transfer":
     // Process transfer update using decoded_payload
  
} catch (error) {
  // 4. Verification failed! Discard the request.
  print("Webhook verification failed:", error)
  // Respond with an error status (e.g., 401 Unauthorized)
}

Payment Status Webhook Payload

When requestType is "payment", the decoded JWT payload will contain the following fields related to the overall payment status:

  • paymentRef (string): The unique reference for the entire payment transaction.
  • requestToken (string): The initial token generated when the payment was initiated.
  • status (string): The current status of the payment (e.g., "SUCCESS", "FAILED", "PENDING").
  • amount (number): The total amount of the payment.
  • billName (string | null): Customer name (if provided).
  • billEmail (string | null): Customer email (if provided).
  • billPhone (string | null): Customer phone (if provided).
  • billCountry (string | null): Customer country code (if provided).

Transfer Status Webhook Payload

When requestType is "transfer", the decoded JWT payload will contain the following fields related to a specific transfer leg within a payment:

  • transferRef (string): The unique reference ID for this specific transfer leg.
  • paymentRef (string): The reference for the parent payment transaction.
  • requestToken (string): The initial token from the payment initiation.
  • payload (object | null): Your custom payload object provided in the original request for this transfer, if any.
  • status (string): The current status of this specific transfer (e.g., "SUCCESS", "FAILED").
  • amount (number): The amount of this specific transfer.
  • recipientNumber (string): The phone number of the recipient for this transfer.

By verifying the token and processing these webhook payloads, you can keep your system synchronized with the status of payments and transfers.