Accept mobile money payments
Mobile money is Ghana's dominant payment method, accounting for over 70% of digital transactions. This guide shows you how to accept payments from MTN, Telecel, and AirtelTigo wallets through a three-phase flow: create an order, confirm customer intent with an OTP, then wait for payment authorization.
An authenticated AI agent can inspect enabled payment methods, create a mobile-money order after confirmation, and look up or render the order while payment progresses.
MCP tools: get_payment_method_settings, create_order, get_order or render_order_card
Confirmed MCP actions require explicit form confirmation before Inttegro changes state.
How it works
Mobile money payments can require more than one customer action. Create an order with execute_payment: true, inspect order.payment.next_action, and present the requested confirmation or authorization experience. After each action, use the returned order state to decide whether to wait, request confirmation, or consider the payment paid.
Supported networks
Inttegro integrates with all three major networks in Ghana: MTN Mobile Money (24M+ wallets), Telecel Cash (8M+ wallets), and AirtelTigo Money (6M+ wallets). Inttegro automatically routes transactions based on phone number prefix—no network-specific integration needed.
Step 1: create the order
Creating an order bundles the customer, payment method, and line items into one request. Setting execute_payment: true starts payment execution; the response tells you whether customer confirmation is required.
Create mobile money order
- cURL
- TypeScript
- Go
- Python
- PHP
- Ruby
- Java
- C#
curl https://api.inttegro.com/orders/create \
-H "Authorization: Bearer $INTTEGRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"request_meta": {
"idempotency_key": "order_momo_2025_001"
},
"execute_payment": true,
"customer_data": {
"name": "Akosua Mensah",
"email_address": "[email protected]",
"phone_number": "+233244123456"
},
"payment_method_data": {
"type": "mobile_money",
"mobile_money": {
"network": "mtn",
"account_number": "0244123456"
}
},
"line_items": [
{
"type": "product",
"product": {
"type": "digital",
"name": "Premium Subscription - 1 Month",
"quantity": 1,
"price": {
"currency": "ghs",
"value": 5000
}
}
}
]
}'
import * as Inttegro from '@inttegro/inttegro-sdk'
const inttegro = new Inttegro.InttegroClient({
apiKey: process.env.INTTEGRO_API_KEY!,
})
const result = await inttegro.orders.create({
requestMeta: {
idempotencyKey: "order_momo_2025_001",
},
executePayment: true,
customerData: {
name: "Akosua Mensah",
phoneNumber: "+233244123456",
},
paymentMethodData: {
type: Inttegro.PaymentMethodTypes.MobileMoney,
mobileMoney: {
network: Inttegro.MobileMoneyNetworks.MTN,
accountNumber: "0244123456",
},
},
lineItems: [
{
type: Inttegro.LineItemTypes.Product,
product: {
type: Inttegro.ProductTypes.Digital,
name: "Premium Subscription - 1 Month",
quantity: 1,
price: {
currency: "ghs",
value: 5000,
},
},
},
],
})
package main
import (
"context"
"log"
"os"
inttegro "github.com/zebodotdev/inttegro-sdk-go/v4"
"github.com/zebodotdev/inttegro-sdk-go/v4/money"
"github.com/zebodotdev/inttegro-sdk-go/v4/paymentmethods"
)
func main() {
ctx := context.Background()
client := inttegro.NewClient(os.Getenv("INTTEGRO_API_KEY"))
params := inttegro.OrderCreateParams{
RequestMeta: &inttegro.RequestMeta{
IdempotencyKey: "order_momo_2025_001",
},
ExecutePayment: inttegro.Bool(true),
CustomerData: &inttegro.CustomerData{
Name: "Akosua Mensah",
PhoneNumber: "+233244123456",
},
PaymentMethodData: &inttegro.PaymentMethodData{
Type: inttegro.PaymentMethodTypeMobileMoney,
MobileMoney: &inttegro.MobileMoneyParams{
Network: paymentmethods.MobileMoneyNetworkMTN,
AccountNumber: "0244123456",
},
},
LineItems: []inttegro.OrderLineItemParams{
{
Type: inttegro.LineItemTypeProduct,
Product: &inttegro.ProductLineItemParams{
Type: inttegro.ProductTypeDigital,
Name: "Premium Subscription - 1 Month",
Quantity: 1,
Price: inttegro.PriceParams{
AmountParams: money.AmountParams{
Currency: money.GHS,
Value: 5000,
},
},
},
},
},
}
result, err := client.Orders.Create(ctx, params)
if err != nil {
log.Fatal(err)
}
_ = result
}
import os
import inttegro
client = inttegro.InttegroClient(api_key=os.environ["INTTEGRO_API_KEY"])
result = client.orders.create(inttegro.orders.CreateRequest(
request_meta=inttegro.orders.RequestMeta(
idempotency_key="order_momo_2025_001",
),
execute_payment=True,
customer_data=inttegro.orders.Customer(
name="Akosua Mensah",
phone_number="+233244123456",
),
payment_method_data=inttegro.orders.PaymentMethod(
type=inttegro.PaymentMethodType.MOBILE_MONEY,
mobile_money=inttegro.orders.MobileMoney(
network=inttegro.MobileMoneyNetwork.MTN,
account_number="0244123456",
),
),
line_items=[
inttegro.orders.ProductLineItem(
type=inttegro.LineItemType.PRODUCT,
product=inttegro.orders.Product(
type=inttegro.ProductType.DIGITAL,
name="Premium Subscription - 1 Month",
quantity=1,
price=inttegro.orders.PriceParams(
currency=inttegro.Currency.GHS,
value=5000,
),
),
),
],
))
<?php
use Inttegro\Client;
$client = new Client($_ENV['INTTEGRO_API_KEY']);
$result = $client->orders->create([
'request_meta' => [
'idempotency_key' => 'order_momo_2025_001',
],
'execute_payment' => true,
'customer_data' => [
'name' => 'Akosua Mensah',
'phone_number' => '+233244123456',
],
'payment_method_data' => [
'type' => \Inttegro\PaymentMethodType::MobileMoney,
'mobile_money' => [
'network' => \Inttegro\MobileMoneyNetwork::MTN,
'account_number' => '0244123456',
],
],
'line_items' => [
[
'type' => \Inttegro\LineItemType::Product,
'product' => [
'type' => \Inttegro\ProductType::Digital,
'name' => 'Premium Subscription - 1 Month',
'quantity' => 1,
'price' => [
'currency' => 'ghs',
'value' => 5000,
],
],
],
],
]);
require "inttegro"
client = Inttegro::Client.new(api_key: ENV.fetch("INTTEGRO_API_KEY"))
result = client.orders.create(
request_meta: {
idempotency_key: "order_momo_2025_001",
},
execute_payment: true,
customer_data: {
name: "Akosua Mensah",
phone_number: "+233244123456",
},
payment_method_data: {
type: Inttegro::PaymentMethodType::MOBILE_MONEY,
mobile_money: {
network: Inttegro::MobileMoneyNetwork::MTN,
account_number: "0244123456",
},
},
line_items: [
{
type: Inttegro::LineItemType::PRODUCT,
product: {
type: Inttegro::ProductType::DIGITAL,
name: "Premium Subscription - 1 Month",
quantity: 1,
price: {
currency: "ghs",
value: 5000,
},
},
},
]
)
import com.inttegro.Client;
import com.inttegro.orders.OrderCreateParams;
import com.inttegro.RequestMeta;
import com.inttegro.customers.CustomerData;
import com.inttegro.paymentmethods.PaymentMethodData;
import com.inttegro.paymentmethods.PaymentMethodType;
import com.inttegro.paymentmethods.MobileMoneyParams;
import com.inttegro.paymentmethods.MobileMoneyNetwork;
import com.inttegro.orders.OrderLineItemParams;
import com.inttegro.orders.ProductLineItemParams;
import com.inttegro.products.ProductType;
import com.inttegro.prices.PriceParams;
import com.inttegro.money.Currency;
public class Example {
public static void main(String[] args) throws Exception {
var client = new Client(System.getenv("INTTEGRO_API_KEY"));
var params = OrderCreateParams.builder()
.requestMeta(RequestMeta.builder()
.idempotencyKey("order_momo_2025_001")
.build())
.executePayment(true)
.customerData(CustomerData.builder()
.name("Akosua Mensah")
.phoneNumber("+233244123456")
.build())
.paymentMethodData(PaymentMethodData.builder()
.type(PaymentMethodType.MOBILE_MONEY)
.mobileMoney(MobileMoneyParams.builder()
.network(MobileMoneyNetwork.MTN)
.accountNumber("0244123456")
.build())
.build())
.lineItem(OrderLineItemParams.product(ProductLineItemParams.builder()
.type(ProductType.DIGITAL)
.name("Premium Subscription - 1 Month")
.quantity(1L)
.price(PriceParams.of(Currency.GHS, 5000))
.build()))
.build();
var result = client.orders().create(params);
}
}
using Inttegro;
using var inttegro = new InttegroClient(
Environment.GetEnvironmentVariable("INTTEGRO_API_KEY")!
);
var result = await inttegro.Orders.CreateAsync(new {
request_meta = new {
idempotency_key = "order_momo_2025_001",
},
execute_payment = true,
customer_data = new {
name = "Akosua Mensah",
phone_number = "+233244123456",
},
payment_method_data = new {
type = Inttegro.PaymentMethodType.MobileMoney,
mobile_money = new {
network = Inttegro.MobileMoneyNetwork.MTN,
account_number = "0244123456",
},
},
line_items = new[] {
new {
type = Inttegro.LineItemType.Product,
product = new {
type = Inttegro.ProductType.Digital,
name = "Premium Subscription - 1 Month",
quantity = 1,
price = new {
currency = "ghs",
value = 5000,
},
},
},
},
});
Key parameters
execute_payment- Set totrueto initiate payment immediately.payment_method_data.mobile_money.network- Network:"airtel","mtn","telecel", or"vodafone".payment_method_data.mobile_money.account_number- Wallet phone number (local or international format).- Amounts - In minor units (pesewas). GHS 50.00 =
5000.
The response includes the order, payment, and confirmation-request identifiers needed for the next action. Read the token size, delivery channel, and expiry from order.payment.next_action.confirm_payment instead of assuming fixed values.
Step 2: confirm customer intent with OTP
When the next action is confirm_payment, collect the token from the customer and submit it before the response's expires_at time. After confirmation, inspect the returned order again; some payments require a separate authorization action before they become paid.
Confirmation is bound to one order, payment, and confirmation request. Use
order.payment.id as payment_id and
order.payment.next_action.confirm_payment.request.id as confirmation_id,
then submit those values with order_id and token. See Confirm a
payment for complete SDK examples.
Inttegro validates the token and returns the latest order state. Continue only according to order.payment.next_action; don't assume confirmation alone completed the charge.
Common errors:
confirmation_bad_token- Ask the customer for the latest token and retry with the same four identifiers.confirmation_expired- Request a new confirmation before retrying.confirmation_max_reached- Request a new confirmation because the active request has no attempts remaining.
Step 3: verify payment status
After the customer authorizes the payment with their mobile money provider, look up the order to verify completion. This typically happens within 5-15 seconds after authorization:
Check payment status
- cURL
- TypeScript
- Go
- Python
- PHP
- Ruby
- Java
- C#
curl https://api.inttegro.com/orders/lookup \
-H "Authorization: Bearer $INTTEGRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"order_id": "or_abc123xyz"
}'
import * as Inttegro from '@inttegro/inttegro-sdk'
const inttegro = new Inttegro.InttegroClient({
apiKey: process.env.INTTEGRO_API_KEY!,
})
const result = await inttegro.orders.lookup({
orderId: "or_abc123xyz",
})
package main
import (
"context"
"log"
"os"
inttegro "github.com/zebodotdev/inttegro-sdk-go/v4"
)
func main() {
ctx := context.Background()
client := inttegro.NewClient(os.Getenv("INTTEGRO_API_KEY"))
result, err := client.Orders.Lookup(ctx, "or_abc123xyz")
if err != nil {
log.Fatal(err)
}
_ = result
}
import os
import inttegro
client = inttegro.InttegroClient(api_key=os.environ["INTTEGRO_API_KEY"])
result = client.orders.lookup("or_abc123xyz")
<?php
use Inttegro\Client;
$client = new Client($_ENV['INTTEGRO_API_KEY']);
$result = $client->orders->lookup("or_abc123xyz");
require "inttegro"
client = Inttegro::Client.new(api_key: ENV.fetch("INTTEGRO_API_KEY"))
result = client.orders.lookup(order_id: "or_abc123xyz")
import com.inttegro.Client;
public class Example {
public static void main(String[] args) throws Exception {
var client = new Client(System.getenv("INTTEGRO_API_KEY"));
var result = client.orders().lookup("or_abc123xyz");
}
}
using Inttegro;
using var inttegro = new InttegroClient(
Environment.GetEnvironmentVariable("INTTEGRO_API_KEY")!
);
var result = await inttegro.Orders.LookupAsync("or_abc123xyz");
Statuses: requires_action (waiting for OTP), paid (success), failed (insufficient balance, cancelled), expired (5-minute window closed).
Important details
Transaction limits: MTN (GHS 5K/transaction, 10K daily), Telecel (3K/transaction, 5K daily), AirtelTigo (2K/transaction, 3K daily). Exceeding limits returns amount_too_large error.
Order limits: Each order can contain up to 64 line items. Order totals are capped at 100,000 for ghs and 50,000 for all other supported currencies, measured in the currency's smallest unit. Contact support if you need these limits increased.
Settlement: Real-time to your balance, but 7-day aging period before payout eligibility (Bank of Ghana dispute window).
Pricing: 1.5% + GHS 0.50 per transaction, deducted before funds reach your balance.
Network detection: Inttegro validates network matches phone prefix (MTN: 024/054/055/059, Telecel: 020/050, AirtelTigo: 027/057/026/056).
Next steps
You're now accepting mobile money payments! Here's what to explore next:
- Charge repeat customers - Save payment methods for one-click checkout
- Handle payment failures - Retry failed transactions gracefully
- Set up payouts - Withdraw funds to your bank account
- Understand payment method settings - Configure verification and confirmation requirements
For detailed parameter documentation, see the Orders API reference.