Fynlo API Documentation
Welcome to Fynlo's developer hub. Our API lets you process payments and mock complex scenarios in sandbox using V4 headers.
Authentication
Use OAuth 2.0 Client Credentials to obtain a Bearer Token.
POST /api/v1/oauth/tokencurl -X POST "https://api.fynlo.makylegacy.com/api/v1/oauth/token" \
-d '{ "client_id": "...", "client_secret": "...", "grant_type": "client_credentials" }'Step 1: Initiate Direct Charge
Initiate a white-label direct charge.
POST /api/v1/charges/cardInitiate a white-label direct charge.
Step 2: Handle Validation (OTP)
If the response status is pending and suggests OTP, use the validate endpoint.
POST /api/v1/charges/validate{
"otp": "123456",
"flw_ref": "FLW-...",
"type": "card"
}Collections - Inflow
Accept payments seamlessly across multiple channels. Our Orchestrator & General flows support all methods.
Card Payments
Accept Debit/Credit cards. (This is the default type: card in our Orchestrator).
Integration Methods
- Orchestrator Flow (Recommended): Single-step charge.
- General Flow (Advanced): Create Customer → Payment Method → Charge.
Mobile Money
Collection via Mobile Money (MOMO). Supports Push Notifications and Redirect flows.
POST /api/v1/charges/orchestrate{
"amount": 1500,
"currency": "GHS",
"email": "user@example.com",
"name": "Jane Doe",
"reference": "MOMO-123",
"payment_method": {
"type": "mobile_money",
"mobile_money": {
"network": "MTN",
"country_code": "233",
"phone_number": "054xxxxxxx"
}
}
}Note: Response will contain meta.authorization.mode: "redirect" or "callback".
Pay With Bank Transfer
Generate a virtual bank account for your customer to transfer funds to.
Create Dynamic Account (One-time)
POST /api/v1/virtual-accounts{
"email": "user@example.com",
"name": "John Doe",
"amount": 5000,
"currency": "NGN",
"reference": "VA-12345",
"is_permanent": false,
"expires_in": 3600
}USSD
Charge customers via USSD string (Offline).
POST /api/v1/charges/orchestrate{
"amount": 1000,
"currency": "NGN",
"email": "user@example.com",
"payment_method": {
"type": "ussd",
"ussd": {
"account_bank": "057" // e.g., Zenith Bank
}
}
}Note: You must get the list of banks first (see Flutterwave generic docs).
OPay
Direct charge via OPay wallet.
POST /api/v1/charges/orchestrate{
"amount": 500,
"currency": "NGN",
"email": "user@example.com",
"payment_method": {
"type": "opay",
"opay": {
"phone_number": "08012345678"
}
}
}General Payment Flow (Advanced)
For maximum control, use the 5-step flow:
- Create Customer:
POST /customersReturns
customer_id(e.g.,cus_...) - Create Payment Method:
POST /payment-methodsReturns
payment_method_id(e.g.,pmd_...) - Initiate Charge:
POST /chargesUse IDs from Step 1 & 2. Returns
authinstructions. - Authorize (Validation):
POST /charges/validateSubmit OTP/PIN if required.
- Verify:
GET /payments/verify/:id
Orchestrator Flow (Simple)
For quick, one-off charges, use our Orchestrator endpoint. It automatically encrypts your raw card data, creates the customer, and initiates the charge in a single request.
Step 1: Initiate Charge
POST /api/v1/charges/orchestrate{
"amount": 5000,
"currency": "NGN",
"reference": "TX-123456789",
"email": "user@example.com",
"name": "John Doe",
"card_number": "5399...",
"cvv": "123",
"expiry_month": "12",
"expiry_year": "25"
}Note: Send raw card details. We handle V4 encryption securely.
Step 2: Handle Authorization (PIN/OTP)
If the response suggests next_action: requires_pin or requires_otp, use the Authorize endpoint. This handles V4 encryption for you.
For PIN (First Step)
PUT /api/v1/charges/:id/authorize{
"mode": "pin",
"pin": "1234"
}For OTP (Second Step)
PUT /api/v1/charges/:id/authorize{
"mode": "otp",
"otp": "123456"
}Step 3: Verify Status
Always verify the final status before giving value.
GET /api/v1/payments/verify/:transaction_idUSSD Payments
Generate USSD strings for offline payments. USSD payments provide a reliable, internet-free option for customers to complete transactions using their mobile devices.
Feature Availability: USSD payments are currently only available for NGN (Nigerian Naira) collections.
How it Works
To initiate a USSD payment, a USSD code is generated for the customer. The customer dials this code to authorize the transaction with their PIN.
Step 1: Create a Customer
First, create a customer profile to link the transaction to.
POST /api/v1/customers{
"email": "johndoe@example.com",
"name": {
"first": "John",
"last": "Doe"
},
"phone": {
"country_code": "234",
"number": "08012345678"
}
}Step 2: Get Account Bank Code
Retrieve a list of supported banks to show to the customer.
GET /api/v1/banks?country=NGStep 3: Create USSD Payment Method
Create the payment method specifying the user's bank code.
POST /api/v1/payment-methods{
"type": "ussd",
"ussd": {
"account_bank": "044"
}
}Note: "044" is the code for Access Bank (example).
Step 4: Create the Charge
Initiate the charge using the IDs from previous steps.
POST /api/v1/charges{
"reference": "TX-USSD-001",
"currency": "NGN",
"amount": 250,
"customer_id": "cus_...",
"payment_method_id": "pmd_...",
"redirect_url": "https://yoursite.com/callback",
"meta": {
"order_id": "12345"
}
}Step 5: User Action
The response will contain a payment_instruction with a USSD code (e.g., *1414#). Display this note to the user so they can dial it and verify.
"Please dial *1414# to complete this transaction"
Payouts - Outflows
Introduction
Learn how to transfer funds globally across multiple channels. We provide a suite of services that enable you to send money seamlessly to bank accounts, mobile numbers, and wallets.
We support two main flows:
- Transfer Orchestrator: Best for one-time transfers. Quicker to initiate as all info is collected at once.
- General Transfer Flow: Best for recurring transfers. Customizable flow offering more control (Create Recipient → Transfer).
Transfer Orchestrator
Unlike the general transfer flow, the direct transfer flow lets you set up both recipient and sender in a single request.
This flow has two key steps:
- Initiate the transfer (Instant, Deferred, or Scheduled).
- Verify the transfer status.
Step 1: Initiate Transfer (Instant)
POST /api/v1/transfers/orchestrate{
"action": "instant",
"type": "bank",
"reference": "TRF-INSTANT-001",
"payment_instruction": {
"source_currency": "NGN",
"amount": {
"value": 50000,
"applies_to": "destination_currency"
},
"destination_currency": "NGN",
"recipient": {
"bank": {
"account_number": "0122333334",
"code": "044"
}
}
}
}Optional: Scheduled Transfer
POST /api/v1/transfers/orchestrate{
"action": "scheduled",
"type": "bank",
"reference": "TRF-FUTURE-001",
"disburse_option": {
"date_time": "2025-12-25 09:00:00",
"timezone": "UTC"
},
"payment_instruction": {
"source_currency": "NGN",
"amount": { "value": 5000, "applies_to": "destination_currency" },
"destination_currency": "NGN",
"recipient": {
"bank": {
"account_number": "0122333334",
"code": "044"
}
}
}
}Step 2: Verify Status
GET /api/v1/transfers/:idGeneral Transfer Flow
Create reusable beneficiaries and then transfer.
Step 1: Create Recipient
POST /api/v1/transfers/recipients{
"type": "bank_ngn",
"bank": {
"account_number": "0690000031",
"code": "044"
}
}Step 2: Initiate Transfer
POST /api/v1/transfers{
"action": "instant",
"reference": "TRF-MULTI-001",
"payment_instruction": {
"source_currency": "NGN",
"amount": { "value": 5000, "applies_to": "source_currency" },
"recipient_id": "rcb_12345"
}
}Bank Account Transfers
Transfer funds directly to a bank account. This example uses the Orchestrator Flow to send funds Internationally (USD to AUD).
POST /api/v1/transfers/orchestrate{
"action": "instant",
"type": "bank",
"reference": "TRF-AUD-001",
"payment_instruction": {
"amount": {
"value": 1000,
"applies_to": "destination_currency"
},
"source_currency": "USD",
"destination_currency": "AUD",
"recipient": {
"bank": {
"routing_number": "062123",
"swift_code": "BANK123",
"name": "Commonwealth Bank of Australia",
"account_number": "123456789"
},
"name": {
"first": "Bob",
"last": "Builder"
},
"email": "user@example.com",
"address": {
"line1": "7A, Awesome Apartments",
"city": "Cool City",
"country": "AU"
}
}
}
}Note: Use source_currency and destination_currency for cross-currency transfers.
Mobile Money Transfers
Transfer funds directly to a mobile money wallet. This example uses the Orchestrator Flow to send GH Cedis to an MTN wallet.
POST /api/v1/transfers/orchestrate{
"action": "instant",
"type": "mobile_money",
"reference": "TRF-MOMO-GHS-001",
"narration": "GHS MOMO TRANSFER EXAMPLE",
"payment_instruction": {
"source_currency": "NGN",
"destination_currency": "GHS",
"amount": {
"value": 1000,
"applies_to": "destination_currency"
},
"recipient": {
"name": {
"first": "John",
"last": "Doe"
},
"mobile_money": {
"network": "MTN",
"msisdn": "2339012345678"
}
}
}
}msisdn must include the country code (e.g., 233... for Ghana).Wallet-to-Wallet Transfers
Transfer funds directly to another Flutterwave Merchant (Identifier/MID).
POST /api/v1/transfers/orchestrate{
"action": "instant",
"type": "wallet",
"reference": "TRF-W2W-001",
"narration": "WALLET TRANSFER EXAMPLE",
"payment_instruction": {
"source_currency": "NGN",
"destination_currency": "NGN",
"amount": {
"value": 100,
"applies_to": "destination_currency"
},
"recipient": {
"wallet": {
"provider": "flutterwave",
"identifier": "00118468" // Merchant ID
}
}
}
}Note: Use your own MID as the identifier for Intra-wallet transfers (moving funds between your own currency balances).
Settlements
Track the funds settled to your bank account or wallet.
GET /api/v1/operations/settlementsQuery params: page, from, to
Refunds
Initiate full or partial refunds for transactions.
Initiate Refund
POST /api/v1/operations/refunds{
"amount": 2000,
"reason": "duplicate",
"charge_id": "chg_Jwb2Y7ZbJQ"
}Chargebacks
Manage disputes. Accept liability or decline with proof.
Accept/Decline Dispute
PUT /api/v1/operations/chargebacks/:id{
"status": "declined", // or "accepted"
"comment": "Value provided. See proof.",
"uploaded_proof": "https://example.com/receipt.pdf"
}Use Cases
Fynlo is built to scale with you. Whether you are a freelancer just starting out or a growing enterprise, our tools are designed to fit your unique needs.
Sole Entrepreneurs
Freelancers, Consultants, and Creators.
- Quick Collections: Accept payments via Payment Links or simple invoices (No coding required).
- Mobile Wallet Payouts: Get paid instantly to your MoMo wallet or Personal Bank Account.
- Low Fees: Pay as you go with no monthly maintenance fees.
Small Businesses
Retail Stores, Boutiques, and Service Providers.
- Unified Payments: Accept Card, Mobile Money, and Bank Transfers at checkout.
- Chargeback Protection: Our fraud detection helps protect your revenue.
- Easy Reconciliation: View all your sales in one simple Dashboard.
Medium Businesses
Growing E-commerce and Tech Startups.
- Automated Operations: Use our
/operationsAPI to automate refunds and settlements. - Bulk Payouts: Pay suppliers and staff instantly using our Transfer Orchestrator.
- Global Reach: Accept international payments (USD, GBP, EUR) and settle in local currency.
- Developer First: Robust Webhooks and Sandbox environment for testing specific scenarios.
Deployment Information
Production Domains
- Frontend:
https://fynlo.makylegacy.com - API:
https://api.fynlo.makylegacy.com(Recommended)
When deploying, ensure your NEXT_PUBLIC_API_URL is set to the API domain.
Testing & Scenarios
In Sandbox, use the X-Scenario-Key header to simulate specific outcomes. Format: scenario:<value>&issuer:<value>
Card Scenarios
scenario:auth_pin- Mock PIN auth.scenario:auth_3ds- Mock 3DS flow.scenario:auth_avs- Mock No-Auth/AVS.
Issuer Responses (Simulate Failures)
Example: Simulate 3DS Success
-H "X-Scenario-Key: scenario:auth_3ds&issuer:approved"
Errors
Standard V4 codes (10400, 10401, etc.) are returned.