Skip to main content
This page is for developers building a Mini App for MiniPay, the stablecoin wallet from Opera. It covers only what is specific to Celo. The build, test and submit lifecycle is documented by the MiniPay team at docs.minipay.xyz; the index at the end of this page lists every page there so you — or your coding agent — can see what is available without leaving this site. MiniPay runs only on Celo (mainnet) and Celo Sepolia (testnet). It has more than 10M activations, a built-in Mini App discovery page, and ships inside the Opera Mini Android browser and as a standalone app for Android and iOS. Balances are shown in the user’s local currency, the wallet is 2 MB, and phone numbers can stand in for addresses.

Prerequisites

  • A web app (any framework) reachable over HTTPS; for local development use ngrok http 3000 to expose localhost
  • viem or wagmi — both support Celo’s fee-currency transactions natively
  • Testnet funds: CELO from the Celo Sepolia faucet, swapped to a stablecoin in the Mento app
  • To scaffold: npx @celo/celo-composer@latest create -t minipay (the MiniPay template), or follow the MiniPay quick start

What is Celo-specific

Stablecoins are the only assets

MiniPay holds USDm, USDC and USDT — no CELO balance is shown to the user. Price and settle in one of these.
USDC and USDT use 6 decimals; USDm uses 18. parseUnits(amount, 18) on a USDC transfer sends 10¹² times the intended amount. Pass the token’s decimals explicitly.
Testnet addresses are on Fee currency contracts.

Gas is paid in the user’s stablecoin

MiniPay uses fee abstraction: the user never holds CELO, and the wallet pays gas in the stablecoin the user holds the most of. You may set feeCurrency on eth_sendTransaction, but MiniPay can override it. Do not build flows that assume a CELO balance, and do not show a “buy CELO for gas” step. To show a fee estimate in the user’s currency, estimate gas and gas price in that token. The JSON-RPC methods accept the fee currency directly:
In the UI, label this “network fee”, not “gas” — see the MiniPay design standards.

Detect MiniPay and skip the connect button

Inside MiniPay the wallet is already connected through the injected provider, and window.ethereum.isMiniPay is true. Hide your connect-wallet UI and connect the injected connector on load:
Check for window.ethereum before initialising any web3 library; the provider is injected by the host. Wallet-connection details and error handling: Wallet connection.

Resolve MiniPay phone numbers to addresses

MiniPay maps phone numbers to addresses through SocialConnect and ODIS. To look a number up you act as an issuer: an account that has verified the user owns the number (for example by SMS), has a data encryption key (DEK) registered on the Accounts contract, and holds ODIS quota.
Contract addresses are from the on-chain registry (FederatedAttestations, OdisPayments) and listed on Core contracts. The MiniPay reference for this is Phone number lookup. Deeplinks open a MiniPay screen from your Mini App or from outside (WhatsApp, a web page). The host is link.minipay.xyz; users without the app get an install prompt. Reference: Deeplinks.

Test inside MiniPay

You cannot test in an Android emulator; use a phone.
  1. In the MiniPay app open Settings → About and tap the Version number until developer mode is confirmed.
  2. Back in Settings → Developer Settings, enable Developer Mode and, for Celo Sepolia, Use Testnet.
  3. Tap Load Test Page, enter your app’s HTTPS URL (the ngrok URL for local development), and tap Go.
Step-by-step with screenshots: Test your Mini App inside MiniPay.

The MiniPay developer docs

Everything below lives at docs.minipay.xyz and is maintained by the MiniPay team. Getting started Guides Technical reference

Funding and programs