A2A
A peer agent discovers AbaPay via its Agent Card, then sends structured tool calls over A2A JSON-RPC — no browser, no human account-creation step, for either side.
Skills (11) — full reference
describe_capabilitiesRead-onlyList what AbaPay can pay (airtime, data, electricity, cable, etc.), any services currently paused, and example requests. Call this first if unsure what is supported.
No parameters.
check_balanceRead-onlyCheck a linked wallet's stablecoin balances and remaining agent spending allowance. Works with no arguments once authorized via OAuth.
| Name | Type | Required | Description |
|---|---|---|---|
api_key | string | Optional | AbaPay MCP API key (starts with aba_mcp_). Not needed over OAuth. |
chain | "CELO" | Optional | Which chain to check.Backend also accepts BASE for the multi-chain consumer app; this site's rails are Celo-only. |
list_plansRead-onlyList the REAL, currently purchasable plans for DATA, CABLE, or EDUCATION — exact codes and current prices. Always call before pay_bill for these three services.
| Name | Type | Required | Description |
|---|---|---|---|
service | "DATA" | "CABLE" | "EDUCATION" | Required | Which service to list plans for. |
provider | string | Required | e.g. mtn, airtel, glo, 9mobile (data); dstv, gotv, startimes (cable); waec, waec-registration, jamb (education). |
list_international_optionsRead-onlyBrowse the live international top-up catalogue (140+ countries) one level at a time: country → product type → operator → priced plan.
| Name | Type | Required | Description |
|---|---|---|---|
country | string | Optional | Country name or ISO code, e.g. "Ghana" or "GH". Omit to list all countries. |
product_type_id | string | Optional | From this country's results. Omit to list product types. |
operator_id | string | Optional | From this country + product_type_id's results. Omit to list operators. |
transaction_historyRead-onlyList recent real transactions for the linked wallet — service, provider, amount, status, tx hash. No PIN required.
| Name | Type | Required | Description |
|---|---|---|---|
api_key | string | Optional | Not needed over OAuth. |
limit | number | Optional | How many to return. Defaults to 10, max 25. |
offset | number | Optional | How many of the most recent to skip. 0 (default) starts at the newest. |
get_payment_statusRead-onlyLook up one payment by tx hash or request id: delivered, still confirming, failed or refunded, with refund state. Only the linked wallet's payments. No PIN required.
| Name | Type | Required | Description |
|---|---|---|---|
api_key | string | Optional | Not needed over OAuth. |
reference | string | Required | The transaction hash (0x…) or request id. |
pay_billMoves moneyPay a real bill — Nigerian (airtime, data, electricity, cable, WAEC/JAMB) or international airtime/data — from the linked wallet, settled on-chain. Executes immediately; no delay parameter exists.
| Name | Type | Required | Description |
|---|---|---|---|
api_key | string | Optional | Not needed over OAuth. |
pin | string | Required | The key's PIN (6 digits for keys created now; older keys may have 4-6). Required on every payment, including over OAuth. |
idempotency_key | string | Optional | A unique id for this payment (8-128 chars). A retry with the same key returns the first result instead of paying again. |
service | "AIRTIME" | "DATA" | "ELECTRICITY" | "CABLE" | "EDUCATION" | "INTERNATIONAL" | Required | Which kind of bill. |
provider | string | Optional | e.g. mtn, ikeja-electric, dstv, waec. Not used for INTERNATIONAL. |
account_number | string | Required | Phone/meter/smartcard/JAMB ID/destination number, depending on service. |
amount_ngn | number | Optional | Amount in Naira. Not needed for INTERNATIONAL. |
chain | "CELO" | Optional | Defaults to the chain approved on the key.Backend also accepts BASE for the consumer app; Celo-only here. |
token | "USD₮" | "USDC" | "USA₮" | Optional | Which stablecoin to pay with. Defaults to the token approved on the key. |
variation_code | string | Optional | Required for DATA, EDUCATION, INTERNATIONAL, and CABLE package changes. |
meter_type | "prepaid" | "postpaid" | Optional | Required for ELECTRICITY. |
customer_email | string | Optional | Required for INTERNATIONAL (receipt destination). |
customer_name | string | Optional | Optional, used for the receipt if known. |
country | string | Optional | Required for INTERNATIONAL. |
product_type_id | string | Optional | Required for INTERNATIONAL. |
operator_id | string | Optional | Required for INTERNATIONAL. |
schedule_billWriteSet up a recurring or future one-off bill payment. Charges nothing when this runs — money only moves later, when the schedule fires and the allowance still covers it. EDUCATION and INTERNATIONAL can't be scheduled.
| Name | Type | Required | Description |
|---|---|---|---|
api_key | string | Optional | Not needed over OAuth. |
pin | string | Required | Required to create a schedule. |
idempotency_key | string | Optional | A unique id for this payment (8-128 chars). A retry with the same key returns the first result instead of paying again. |
service | "AIRTIME" | "DATA" | "ELECTRICITY" | "CABLE" | Required | Which kind of bill. |
provider | string | Optional | e.g. mtn, ikeja-electric, dstv. |
account_number | string | Required | Phone/meter/smartcard number. |
amount_ngn | number | Required | Amount to charge each run. |
variation_code | string | Optional | Required for DATA and CABLE package changes. |
meter_type | "prepaid" | "postpaid" | Optional | Required for ELECTRICITY. |
frequency | "daily" | "weekly" | "monthly" | "once" | Required | How often this runs. |
day_of_week | number | Optional | Required when frequency is "weekly" — 0 (Sun) to 6 (Sat). |
day_of_month | number | Optional | Required when frequency is "monthly" — 1-28. |
schedule_in_minutes | number | Optional | Required when frequency is "once". |
chain | "CELO" | Optional | Defaults to the key's approved chain.Celo-only here; backend also accepts BASE for the consumer app. |
token | "USD₮" | "USDC" | "USA₮" | Optional | Defaults to the key's approved token. |
customer_email | string | Optional | Notified when this runs — MCP has no persistent channel to message back. |
list_schedulesRead-onlyList active recurring/one-off bill schedules for the linked wallet. No PIN required. Returns each schedule's id for cancel_schedule.
| Name | Type | Required | Description |
|---|---|---|---|
api_key | string | Optional | Not needed over OAuth. |
cancel_scheduleWriteCancel active schedules. Pass id for exactly one (no PIN). provider (all of that provider's) or all: true (every schedule) require the PIN. With none of these the call is refused.
| Name | Type | Required | Description |
|---|---|---|---|
api_key | string | Optional | Not needed over OAuth. |
id | string | Optional | Exact schedule id from list_schedules. Cancels only that one. |
provider | string | Optional | Cancel every active schedule for this provider, e.g. "mtn". Requires pin. Ignored if id is set. |
all | boolean | Optional | true cancels every active schedule on the wallet. Requires pin. |
pin | string | Optional | Required with provider or all; not needed for a single id. |
pay_bill_batchMoves moneyPay airtime or data to 2-20 recipients in one call, one PIN for the whole batch. All-or-nothing on capacity: if any (chain, token) group is short, nothing moves. Executes immediately.
| Name | Type | Required | Description |
|---|---|---|---|
api_key | string | Optional | Not needed over OAuth. |
pin | string | Required | Authorizes the whole batch. |
idempotency_key | string | Optional | A unique id for this payment (8-128 chars). A retry with the same key returns the first result instead of paying again. |
recipients | array | Required | 2-20 objects, each: service (AIRTIME|DATA), provider, account_number, amount_ngn, variation_code (DATA only), chain/token overrides. |
chain | "CELO" | Optional | Default chain for recipients that don't set their own. |
token | "USD₮" | "USDC" | "USA₮" | Optional | Default token for recipients that don't set their own. |
customer_email | string | Optional | Optional, applies to the whole batch. |
Can an agent set and use a PIN without visiting a website? Yes.
The PIN is a field in a JSON body, not something entered into a web form. Linking and every payment after it are both plain API calls:
POST /api/agent/link — a call authenticated with a Sign-In with Ethereum (EIP-4361) signature, using a single-use nonce from GET /api/auth/nonce. It picks the PIN in that same request and mints an Agent Hub api_key back. No session, no browser.pay_bill / pay_bill_batch / schedule_bill call after that sends the same PIN back as another JSON field — still just an HTTP request.headers: {
"x-wallet-address": "0xYourAgentWallet...",
"x-wallet-signature": "<signature over the SIWE message>",
"x-wallet-siwe": "<the SIWE message, base64>"
}
body: {
"wallet_address": "0xYourAgentWallet...",
"channel": "MCP",
"pin": "123456",
"approved_chain": "CELO"
}
-> { "success": true, "api_key": "aba_mcp_..." }Full runnable version: examples/agent-quickstart.mjs. Or skip the wire format entirely: AbaPayAgent.link() in the SDK does this in one line. CORS is open on this endpoint too — try it straight from a browser.
The PIN itself is still real security, not a formality: it's the one thing separate from the signature that has to be right on every payment call, unlike x402, which needs neither a PIN nor a link step at all. Two different trust models, both entirely API-driven — neither ever requires opening a browser.