Introduction
The Harepay API lets your product accept cards, bank transfer, and crypto, settle to a bank account or crypto wallet, and run invoicing and subscriptions — through one REST API that returns JSON.
Base URL
https://api.harepay.click
All amounts are integers in the smallest unit — kobo or cents for fiat, base units for crypto (USDC has 6 decimals). There are no floating-point amounts anywhere in the API.
Authentication
Authenticate every request with a secret API key as a Bearer token. Keys come in test and live modes (sk_test_… / sk_live_…). Create them after signing up, in the dashboard. Session tokens from /v1/login work too (for first-party apps). Always call the API from your server — never expose a secret key in a browser or mobile client.
Authorization: Bearer sk_test_xxxxxxxxxxxxxxxx
Idempotency
Money-moving POST requests accept an Idempotency-Key header. Retrying with the same key returns the original result instead of creating a second charge — safe against network failures.
Idempotency-Key: a-unique-id-per-operation
Quickstart
Create a ₦10,000 bank-transfer payment:
curl -X POST https://api.harepay.click/v1/payment_intents \
-H "Authorization: Bearer sk_test_xxx" \
-H "Idempotency-Key: order-1001" \
-H "Content-Type: application/json" \
-d '{
"amount": { "amount": 1000000, "currency": "NGN" },
"method": "bank_transfer",
"rail": "rubies"
}'The payment becomes succeeded once it settles — listen for the payment_intent.succeeded webhook. To accept crypto and settle in naira, send a crypto amount, set "settle_as": { "currency": "NGN" }, and use the partna rail.
Try it live
Paste an API key (use the demo key sk_test_demo against a local server) and send real requests right here.
Tip: start the API and use the demo key sk_test_demo. Run Create payment, then check List payments and Get NGN balance.
SDKs
A typed TypeScript SDK ships in the repo at web/lib/harepay-sdk.ts — dependency-free, works in Node 18+ and browsers. For any other language, generate a client from the OpenAPI spec (e.g. openapi-generator-cli generate -i https://api.harepay.click/openapi.json -g python).
import { Harepay } from "./harepay-sdk";
const lodum = new Harepay({
apiKey: process.env.HAREPAY_SECRET_KEY!,
baseUrl: "https://api.harepay.click",
});
// Accept crypto, settle in naira
const intent = await lodum.payments.create({
amount: { amount: 100_000000, currency: "USDC", network: "TRON" },
settle_as: { amount: 0, currency: "NGN" },
method: "crypto",
rail: "partna",
});
const { available } = await lodum.balances.get("NGN");
// Verify an inbound webhook (works in Node 18+ and browsers)
const ok = await Harepay.verifyWebhook(
WEBHOOK_SECRET, timestamp, rawBody, signatureHeader,
);AI & agents
Harepay is built for AI-assisted integration and for agents that act on your behalf.
llms.txt
A concise, machine-readable map of the API in the llms.txt format — point any AI coding tool (Cursor, Claude, etc.) at it and it will understand auth, conventions and every endpoint.
https://api.harepay.click/llms.txt
MCP server
A Model Context Protocol server ships in the repo at mcp/ (zero dependencies, Node 18+). It lets an assistant inspect your account and — with explicit confirmation — move money. Read-only tools (get_balance, list_payments, system_status, …) are safe to use freely; write tools (create_payment_intent, create_payout, create_invoice) require confirm: true, send an idempotency key, and respect maker-checker payout approval thresholds.
Add it to your MCP client config:
{
"mcpServers": {
"harepay": {
"command": "node",
"args": ["/path/to/LodumPayment/mcp/index.mjs"],
"env": {
"HAREPAY_API_BASE": "https://api.harepay.click",
"HAREPAY_SECRET_KEY": "sk_test_..."
}
}
}
}Errors
Errors use standard HTTP status codes and a consistent JSON envelope.
{ "error": { "type": "insufficient_funds", "message": "..." } }Payments
Create a payment intent. Returns a next_action for the payer.
List payment intents.
Retrieve a payment intent.
Refund (full or partial).
Payouts
Disburse to a bank account or crypto wallet. 422 if available balance is insufficient.
List payouts.
Retrieve a payout.
curl -X POST https://api.harepay.click/v1/payouts \
-H "Authorization: Bearer sk_test_xxx" -H "Content-Type: application/json" \
-d '{
"amount": { "amount": 485000, "currency": "NGN" },
"rail": "rubies",
"destination": { "kind": "bank", "account_no": "0123456789", "bank_code": "0001" }
}'Balances
Available, pending, and reserved balance for an asset (e.g. /v1/balances/NGN).
Invoices
Create an invoice with line items.
List invoices.
Retrieve an invoice.
Collect an invoice — creates a linked payment intent; the invoice is marked paid when it settles.
Subscriptions & usage
Create a price (recurring or usage), start a subscription on it, and report metered usage for pay-as-you-go. A scheduler generates invoices each period; POST /v1/billing/run triggers it on demand.
Create a price (recurring or usage).
List prices.
Start a subscription on a price.
List subscriptions.
Report metered usage (PAYG).
Cancel a subscription.
Allowances & overage
A usage price can include a per-period allowance via included_units: usage up to it is free, and unit_amount is the overage rate beyond it (0 = bill every unit). As you report usage, the moment cumulative usage crosses the allowance the API auto-generates an overage invoice for the exceeded units — it tracks what’s been billed so it never double-charges, and resets each period. The usage response includes an overage_invoice when one is raised.
POST /v1/prices
{ "model": "usage", "currency": "NGN",
"unit_amount": 100, // ₦1.00 per overage unit
"included_units": 1000, // first 1,000 units free each period
"auto_charge": true, // debit prepaid balance on overage (else invoice)
"interval": { "unit": "month", "count": 1 } }Prepaid balances & auto-charge
When a usage price sets auto_charge: true, an overage is debited from the customer’s prepaid balance instead of just invoiced (the resulting invoice is marked paid). If the balance can’t cover it, an open invoice is raised as a fallback. Top up a customer’s balance (in production this is funded by a real payment):
Credit a customer’s prepaid balance ({ "amount": { "amount": 100000, "currency": "NGN" } }).
The customer’s current balance is returned on GET /v1/customers/{id} as prepaid_ngn.
Webhooks
Register an endpoint (dashboard → Webhooks, or POST /v1/webhook_endpoints) and we deliver events as they happen — for example payment_intent.succeeded. Each delivery is signed so you can verify it came from us.
POST https://your-app.com/hooks
X-Lodum-Event: payment_intent.succeeded
X-Lodum-Timestamp: 1750000000
X-Lodum-Signature: sha256=<hex>
{ "id": "pi_000001", "status": "succeeded", ... }Verify the signature against the raw request body — the signed string is timestamp.rawBody, HMAC-SHA256, hex-encoded:
import crypto from "crypto";
function verify(secret, timestamp, rawBody, signature) {
const mac = crypto.createHmac("sha256", secret);
mac.update(timestamp + "." + rawBody);
const expected = "sha256=" + mac.digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
// verify(SECRET, headers["x-lodum-timestamp"], rawBody, headers["x-lodum-signature"]);Disputes
List disputes against your payments.
Retrieve a dispute.
Submit evidence while a dispute is open.
Full machine-readable reference: OpenAPI 3.0 spec — generate a client SDK in your language with any OpenAPI generator.