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
Node (SDK)
Python
PHP
Go
Ruby
Java
C#
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.

Create payment
List payments
Get NGN balance
Create invoice
List disputes

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).

TypeScript
Python
Go
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

POST/v1/payment_intents

Create a payment intent. Returns a next_action for the payer.

GET/v1/payment_intents

List payment intents.

GET/v1/payment_intents/{id}

Retrieve a payment intent.

POST/v1/payment_intents/{id}/refund

Refund (full or partial).

Payouts

POST/v1/payouts

Disburse to a bank account or crypto wallet. 422 if available balance is insufficient.

GET/v1/payouts

List payouts.

GET/v1/payouts/{id}

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

GET/v1/balances/{asset}

Available, pending, and reserved balance for an asset (e.g. /v1/balances/NGN).

Invoices

POST/v1/invoices

Create an invoice with line items.

GET/v1/invoices

List invoices.

GET/v1/invoices/{id}

Retrieve an invoice.

POST/v1/invoices/{id}/pay

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.

POST/v1/prices

Create a price (recurring or usage).

GET/v1/prices

List prices.

POST/v1/subscriptions

Start a subscription on a price.

GET/v1/subscriptions

List subscriptions.

POST/v1/subscriptions/{id}/usage

Report metered usage (PAYG).

POST/v1/subscriptions/{id}/cancel

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):

POST/v1/customers/{id}/prepaid/topup

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:

Node
Python
PHP
Go
Ruby
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

GET/v1/disputes

List disputes against your payments.

GET/v1/disputes/{id}

Retrieve a dispute.

POST/v1/disputes/{id}/evidence

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.