Start
Quick start
Your first payment in five minutes — first without code, then with two calls and a webhook.
Everything here works in test mode: test networks, test coins, nothing real moves. Switch to live when it feels right.
Without code: a payment link
- 1
Sign up
Start free with your email. No password — we send a code.
- 2
Connect a wallet
Dashboard → Wallets. Add the public key from your Ledger or Trezor. See Wallets.
- 3
Make a product
Dashboard → Products. A name and a price is enough.
- 4
Make a link
Dashboard → Links → New. Copy the
/l/…address. - 5
Pay it
Open the link, pick a coin, and press Simulate payment. The invoice turns Paid and a receipt is sent.
With code: two calls
Get a test key in Dashboard → Developers. It starts with sk_test_. Keep it on your server.
import { PerlyPay } from "perly-pay";
const pay = new PerlyPay(process.env.PERLY_PAY_KEY); // sk_test_…
// 1. Make an invoice (amounts in cents)
const invoice = await pay.invoices.create({
amount: 2400,
currency: "USD",
description: "Beans, 1 kg",
customer: { email: "ada@example.com" },
metadata: { orderId: "1042" },
});
// 2. Send the buyer to pay it
redirect(invoice.url); // https://pay.perly.io/i/<uuid>The buyer picks bitcoin or a stablecoin, scans, pays. The money goes to an address made from your key.
Know when it's paid: a webhook
Add an endpoint in Dashboard → Developers → Webhooks and copy its whsec_… secret. Then check every delivery's signature before you trust it.
app.post("/webhooks/perly", express.raw({ type: "application/json" }), (req, res) => {
const event = pay.webhooks.verify(
req.body, // the raw bytes, not parsed JSON
req.header("Perly-Signature"),
process.env.PERLY_PAY_WEBHOOK_SECRET,
); // throws if the signature is wrong or old
if (event.type === "invoice.fulfilled") {
ship(event.data.object.metadata.orderId);
}
res.sendStatus(200);
});invoice.fulfilled, not on invoice.paid: fulfilled comes once, after screening. See Webhooks.Go live
- Connect your live wallet keys (mainnet).
- Make a live key (
sk_live_…) and a live webhook endpoint. - Test mode stays as it is, beside live. The two never mix.