Send money onchain, in naira or dollars
Kobo moves NGNm and dollar stablecoins on Celo. The network fee comes out of the token you send, so one balance is enough and you never hold CELO.
MiniPay is the wallet. Kobo adds what a wallet does not: send naira itself, not only dollars, share a payment link that carries an onchain receipt anyone can verify, run a savings circle, and let an app or agent pay and check on its own.
- Fee in the token you send. Naira and dollars pay their own gas, so no CELO ever leaves your wallet.
- Real people, proven with Self. A passport check that keeps only a same-person number, no name or ID.
- Payable by an agent. An MCP server and an x402-priced receipt check, on the same rails a person uses.
To
Connect and the send form fills itself in. Check the address matches the one they gave you before you sign.
Nothing in this wallet to send yet. Add cash in MiniPay, then come back.
Kobo never holds your money. You sign each transfer in your own wallet, so
the money stays yours until it reaches whoever you sent it to.
Inside MiniPay it connects on its own. Other Celo
wallets work too, but one that cannot pay fees in tokens, MetaMask
among them, will ask for a little CELO.
Open the MiniPay app, go to its site browser, and paste this link. Kobo connects on its own once it loads there. The same works in Valora or any Celo wallet with a browser.
On a laptop? Scan this to open Kobo on your phone.
- Get MiniPay. A free stablecoin wallet from Opera. Install it.
- Add a little money. MiniPay holds dollars: USD₮, USDC or USDm. Add cash in MiniPay.
- Open Kobo in your wallet and send. Paste their address, or open the payment link they sent you. The fee is paid in a token you already hold, so in MiniPay you never need CELO.
- Send
- ₦5,000
- They receive
- ₦5,000.00
- Network fee
- ₦2.88
- Leaves your balance
- ₦5,002.88
The fee is charged in naira, not CELO, and it is the same whether you send ₦100 or ₦100,000. Read from Celo when this page was built, not an estimate.
Your balance is shown as NGNm, which is naira. It is the Mento naira on Celo, and one NGNm is one naira. Kobo also sends cNGN, the SEC-regulated naira, whose fee comes out of NGNm or dollars you hold because cNGN cannot pay for its own gas, and USD₮, USDC and USDm, which pay their own.
The claim is that the fee comes out of naira and your CELO is never touched. These are real transfers. Open either one and check the Fee Currency field yourself.
- Sending naira, fee paid in naira
-
10 NGNm delivered, fee 1.7575 NGNm, CELO spent
0. Balance before and after the block was identical
to the wei: 8.413580680861054656.
0xa9a66398…ce8d9065 - Sending cNGN, fee still paid in naira
-
cNGN cannot pay for its own gas, so the fee came out of NGNm instead.
50 cNGN delivered in full, fee 2.7110 NGNm, CELO spent
0.
0xf030c1ac…67ed377a - Where the rule comes from
- Celo keeps a governance-controlled list of what may pay for gas, and Kobo reads it on every health check rather than assuming. NGNm is on it. cNGN is not. That is why the fee lands where it does, and if that ever changes the app will say so instead of failing at your wallet.
- They receive
- enter an amount
- Network fee
- enter an amount
- Leaves your balance
- enter an amount
Send naira, and they receive their own currency. The exchange happens in the same transaction that moves the money, and you still hold nothing but naira.
- They receive
- enter an amount
- Rate
- enter an amount
- Network fee
- enter an amount
- Leaves your balance
- enter an amount
Ajo, onchain. Everyone pays the same amount each round and takes a turn collecting. Members pay each other directly, so there is no pot sitting anywhere for anyone to run off with.
What happens if someone stops paying
Be clear about this before you put money in. The contract records who is in the circle and whose turn it is. It does not hold the money and it cannot make anyone pay, so it cannot recover a missed round for you. What it does give you is a public record: every contribution is a transaction, so who paid and who did not is visible to everyone, permanently, and cannot be argued about.
That is the same trust model as the ajo you already know, where the group is the enforcement. The difference is that the bookkeeping cannot be disputed and nobody is holding the pot. Join circles with people you would already lend money to.
Order is the order people joined, and it is fixed once the circle starts. Nobody can jump the queue, and no shuffle happens that you would have to trust.
Start a new circle
Make a link and QR code with your address and the amount already filled in. Whoever pays opens it and taps Send.
Someone says they paid you. Check before you hand anything over. A screenshot or an SMS alert can be faked, a transaction on Celo cannot, and only the real naira and dollar contracts count here, so a look-alike token named cNGN moves nothing.
- A check costs
- $0.01 in USD₮ or USDC
- Gas
- none, you only sign
A savings circle only works if one person cannot quietly hold four seats. Kobo checks that with a passport, through Self, and keeps only a number that says "same person" and nothing else. No name, no passport number, no date of birth. None of it is even asked for.
Open the Self app and scan this. If you have already registered your passport there, you will not need it again.
Open the Self appKobo is not only a page. There is a skill file and an MCP server at /mcp, so software can send naira, quote a rate or read a circle without a browser. Same rails, same contracts.
One call is paid. GET /v1/receipt/:hash tells an agent whether a payment really landed and paid who it should, for $0.01 over x402 in USD₮ or USDC. The agent signs, the Celo facilitator settles, and nobody needs gas. Prices are at /v1/paid.
The API, with real responses
Every response below was produced by calling this server when the page was built, not written by hand. Errors are always {"error": "..."} with a 4xx, phrased to be acted on rather than logged.
GET /healthz
{
"ok": true,
"service": "kobo",
"feeCurrency": "NGNm",
"accepted": true
}
GET /v1/cost?amount=5000
{
"example": "5000",
"arrives": "5000",
"feeCurrency": "NGNm",
"estimatedFee": "2.8788301445889",
"maximumFee": "10.991896915703",
"total": "5002.8788301445889",
"senderNeedsCelo": false,
"nairaAcceptedAsGas": true
}
GET /v1/quote?from=0xE23c44...&to=0xF70A02...&amount=1000
{
"token": "NGNm",
"to": "0xF70A02D74970FAFF6b0bE6D0dD558965E1B4d855",
"amount": "1000",
"arrives": "1000",
"feeCurrency": "NGNm",
"estimatedFee": "2.8788301445889",
"maximumFee": "10.991896915703",
"senderNeedsCelo": false,
"balance": "332.924924380576759279",
"sufficient": false
}
GET /v1/tokens
{
"tokens": [
{
"symbol": "NGNm",
"label": "Mento naira",
"kind": "naira",
"address": "0xE2702Bd97ee33c88c8f6f92DA3B733608aa76F71",
"decimals": 18,
"canPayOwnGas": true
},
{
"symbol": "cNGN",
"label": "Regulated naira",
"kind": "naira",
"address": "0xF6829D7393dAe24509eb1E52eE8e572e2E271a4f",
"decimals": 6,
"canPayOwnGas": false
},
{
"symbol": "USDT",
"label": "Tether dollars",
"kind": "dollar",
"address": "0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e",
"decimals": 6,
"canPayOwnGas": false
},
{
"symbol": "USDC",
"label": "Circle dollars",
"kind": "dollar",
"address": "0xcebA9300f2b948710d2653dD7B07f33A8B32118C",
"decimals": 6,
"canPayOwnGas": false
},
{
"symbol": "USDm",
"label": "Mento dollars",
"kind": "dollar",
"address": "0x765DE816845861e75A25fCA122bb6898B8B1282a",
"decimals": 18,
"canPayOwnGas": true
}
],
"feePaidIn": "whichever allowlisted token the sender already holds, naira first"
}
GET /v1/receipt/0xf030c1ac... (paid, $0.01 over x402)
{
"hash": "0xf030c1ace60441026509f128b4daa19091863ca25528526b2ae2be4667ed377a",
"found": true,
"status": "confirmed",
"block": 77168455,
"time": "2026-09-10T19:40:13.000Z",
"confirmations": 1550870,
"from": "0xe23c44dd4a51456786c6681cfe928aacfa00d619",
"transfers": [
{
"token": "cNGN",
"from": "0xE23c44Dd4a51456786c6681cFE928AAcfa00d619",
"to": "0xF70A02D74970FAFF6b0bE6D0dD558965E1B4d855",
"amount": "50"
}
],
"fee": {
"currency": "NGNm",
"amount": "2.711032419072168772"
},
"celoSpentOnFee": "0",
"sentWithKobo": true,
"paid": true,
"verdict": "Confirmed. 50 cNGN to 0xF70A...d855."
}
GET /v1/quote?amount=-5 (an error)
{
"error": "amount must be a number, like 5000 or 1500.50"
}
What the fields mean, so nothing has to be guessed:
- amount, arrives
- What you asked to send, and what lands with the recipient. They are equal on purpose: the fee is charged on top, never taken out of the transfer, so nobody receives less than the number you typed.
- estimatedFee, maximumFee
- What it should cost, and the ceiling you authorise. Under EIP-1559 you pay base plus tip and the rest is refunded, so the real cost lands near the estimate. Check affordability against the maximum, not the estimate, or a busy block turns a quote that said yes into a transfer that fails.
- feeCurrency
- Which token the fee comes out of, chosen from what the sender already holds. It is not always the token being sent, because cNGN cannot pay for its own gas. Never CELO.
- sufficient, gasSufficient
- Whether the balance covers the transfer, and separately whether anything on hand can cover the fee. They are separate because the two can come from different tokens. When either is false, note says what to do about it.
- feeOptions
- Every token Celo accepts as gas that this wallet holds, with the fee priced in each. Shown so a caller can see why one was picked rather than trusting the choice.
- payouts
- On /v1/currencies: the currencies a naira balance can be paid out in, not currencies you can hold here. Send naira, the recipient gets shillings.