# lubaak/pay for coding agents

> Served at https://pay.lubaak.com/agents.md. Copy into AGENTS.md, CLAUDE.md,
> or a Cursor rule so your agent can integrate without reading the whole docs site.

lubaak/pay verifies Ethiopian bank and wallet payments at the source. Send a
receipt URL or a transaction reference. We fetch the bank/wallet receipt
(from Ethiopia), parse it, and return one normalized JSON envelope across
25+ institutions (CBE, Telebirr, Dashen, Awash, eBirr partners, and more).

Use it when your backend cannot reach Ethiopian banks reliably, or when you
need the bank's record - not a user-typed screenshot.

## Base URL and auth

Base URL: `https://pay.lubaak.com`

Pass your key as `Authorization: Bearer <token>`. Tokens are minted in the
dashboard at https://pay.lubaak.com/dashboard/tokens and start with a Sanctum
plaintext shown once - store it in your secret manager immediately.

```bash
curl -X POST https://pay.lubaak.com/api/v1/verify \
  -H "Authorization: Bearer $LUBAAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"bank":"telebirr","reference":"TB7G9K2P"}'
```

Never hardcode the key, and never send it from a browser. It is a server-side
credential. The public landing page may call the API without a key (IP-limited);
do not build products on anonymous access.

## POST /api/v1/verify

Also available as `GET` with the same query parameters.

Body / query takes **url** or **reference** (plus bank when required):

| Field | Type | Notes |
|---|---|---|
| `url` | string | Full receipt URL. Preferred when the customer shares an SMS/app link. Bank is auto-detected from the host when possible. |
| `reference` | string | Transaction / receipt id. Usually requires `bank`. |
| `bank` | string | Institution code (see providers below). Required for most references; optional for many URLs. |
| `suffix` | string | BOA only: last 5 digits of the account. |
| `phone` | string | CBE Birr only: payer phone. |
| `settlement_account` | string | Optional. Adds `settlement_match` - confirms funds landed on your account. |
| `expected_amount` | number/string | Optional. Adds `amount_match`. |

### Success shape

```json
{
  "valid": true,
  "status": "verified",
  "bank": "telebirr",
  "logo_url": "https://pay.lubaak.com/images/banks/telebirr.svg",
  "cached": false,
  "data": {
    "sender_name": "...",
    "sender_account": "...",
    "receiver_name": "...",
    "receiver_account": "...",
    "sent_amount": "100 ETB",
    "service_charge": "0 ETB",
    "tax_vat": "0 ETB",
    "total_paid": "100 ETB",
    "transfer_date": "...",
    "transaction_id": "..."
  },
  "confirmation": {
    "confirmed_count": 1,
    "first_confirmed_at": "...",
    "last_confirmed_at": "..."
  }
}
```

`data` fields are normalized strings across providers. Amounts usually look like
`"100 ETB"` or `"100.00 ETB"` - parse the number before arithmetic.

`cached: true` means a prior successful verification was reused. Repeat lookups
of the same payment are free for the caller (no extra credit charge).

### Common provider codes

| `bank` | Notes |
|---|---|
| `cbe` | CBE mobile / receipt |
| `cbebirr` | CBE Birr wallet (needs `phone` with reference) |
| `telebirr` | Telebirr |
| `boa` | Bank of Abyssinia (needs `suffix` with reference) |
| `mpesa` | M-Pesa Ethiopia |
| `dashen` | Dashen |
| `awash` | Awash |
| `zemen` | Zemen |
| `wegagen` | Wegagen bank-native |
| `nib` / `siinqee` / `abay` / `amhara` / `berhan` / `hibret` / `oromia` / `ahadu` / `zamzam` | Bank-native channels |
| `kaafiebirr` / `ahaduebirr` / `coopebirr` / `nibebirr` / `wegagenebirr` / `siinqeeebirr` / `ebirr` | eBirr wallet tenants (`receipt.ebirr.com/...`) |

Full list: https://pay.lubaak.com/docs#banks

### Errors

| HTTP | Meaning |
|---|---|
| 200 + `valid:false` | Upstream reachable; receipt not found / invalid |
| 402 | Insufficient credits (authenticated) |
| 422 | Bad input / could not detect bank |
| 429 | Rate or plan limit |
| 502 | Parse / upstream failure |

Anonymous IP limit: 10 verifications / hour. Authenticated limits follow the plan.

## Health / status

- Public status UI: https://pay.lubaak.com/status
- Per institution: https://pay.lubaak.com/status/{bank}

## Rules that are easy to get wrong

1. Prefer `url` when the customer has a receipt link - bank detection is more reliable.
2. Do not treat a screenshot as verified data. Verify against the bank URL or reference.
3. eBirr wallet receipts (`receipt.ebirr.com/{tenant}/...`) use `*ebirr` bank codes, not the bank-native code (`wegagen` ≠ `wegagenebirr`).
4. Cache hits are free. Failed lookups do not create a durable receipt record.
5. Treat receipt URLs like credentials: do not log them into public error reports.

## Full docs

- Human docs + playground: https://pay.lubaak.com/docs
- Agent index: https://pay.lubaak.com/llms.txt
- Try without a key: https://pay.lubaak.com/verify
