Documentation

A non-custodial gateway. You hold the keys; we derive deposit addresses, watch the chain, and notify your store.

1. Create an account

Sign up at /auth, create a store, and add at least one chain config.

2. Add an xpub or receive address

We support BIP32 extended public keys for UTXO chains (BTC, TXC, DOGE, ISK, ZCU) and a single receive address for account-based chains (ETH, Base, Tron, Solana). Your private keys never leave your wallet.

New to xpubs? Step-by-step wallet setup guide for every supported chain →

3. Get your API key

Each store has its own secret API key (sk_live_…). It's shown once — store it securely.

4. Create invoices

POST /api/public/v1/invoices
Authorization: Bearer sk_live_...
Content-Type: application/json

{
  "chain": "btc",
  "amount": 49.00,
  "currency": "USD",
  "order_id": "ORDER_1234",
  "redirect_url": "https://store.example.com/thanks"
}

Response includes the unique deposit address and the hosted payment page URL.

5. Receive webhooks

We POST to your configured webhook URL on every status change. Each request is signed:

X-TXCPay-Signature: t=1729000000,v1=hex-hmac-sha256

# verify in node:
const sig = req.headers["x-txcpay-signature"];
const [, t] = sig.match(/t=(\d+)/);
const [, v1] = sig.match(/v1=([a-f0-9]+)/);
const expected = crypto
  .createHmac("sha256", WEBHOOK_SECRET)
  .update(`${t}.${rawBody}`)
  .digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))) reject();

Drop-in JS button

One <script> tag and a button — crypto checkout opens in a modal, no redirect, works on any site.

<script src="https://pay.honest.money/sdk/payhme.js" defer></script>

<button
  data-payhme
  data-api-key="sk_live_..."
  data-chain="btc"
  data-amount="49.00"
  data-currency="USD"
  data-order-id="ORDER_1234"
>Pay $49 with Bitcoin</button>

Or call it programmatically:

PayHME.checkout({
  apiKey: "sk_live_...",
  chain: "base", amount: 49, currency: "USD",
  orderId: "ORDER_1234",
}).then(result => {
  // result.status: "paid" | "closed" | "expired"
  if (result.status === "paid") console.log("Got it:", result.tx);
});
Live demo

Click below — this is the actual SDK, opening a real (test-mode) checkout in a modal. No payment will be processed; close the modal at any time.

Tip: open your browser console to see the payhme:result event payload when the modal closes.

WooCommerce

See the WooCommerce integration guide to install our plugin in under five minutes.