Skip to content

Start

Quick start with npx

One command sets Perly Pay up in your project: a checkout route, a webhook route that checks signatures, a Pay button and your test key.

View as Markdown

npx perly-pay init reads your project, writes the code for its framework, and leaves you one press from a test payment. It sets up test mode only; you go live in the dashboard.

The perly-pay package is on its way to npm. Until it is there, follow the Quick start: the same code, by hand.

Run it

bash
npx perly-pay init

It finds the framework and the package manager, opens Dashboard → Developers and asks for a test key (sk_test_…). A live key is refused.

What it writes

FrameworkFound byFiles
Next.js (App Router)nextlib/perly-pay.ts, app/api/perly-pay/checkout/route.ts, app/api/perly-pay/webhook/route.ts, components/PayButton.tsx, app/perly-pay/page.tsx
Expressexpresslib/perly-pay.js, routes/perly-pay.js
Honohonolib/perly-pay.ts, routes/perly-pay.ts
Laravelartisan, laravel/frameworkapp/Http/Controllers/PerlyPayController.php, routes/perly-pay.php, config/perly-pay.php, resources/views/perly-pay/button.blade.php
Node.jsany other package.jsonlib/perly-pay.js, perly-pay.js (node:http)

TypeScript or JavaScript, ES modules or CommonJS, as your project is, and under src/ when your code lives there. npm, pnpm, yarn, bun and Composer.

  • Checkout. The button posts to /perly-pay/checkout (/api/perly-pay/checkout in Next.js). It opens an invoice and sends the buyer to pay it.
  • Webhook. /perly-pay/webhook checks Perly-Signature on the raw body. On invoice.fulfilled it calls grantAccess(): the one TODO you fill in.
  • Plans. One-off sales and credit packs, in PLANS at the top of the core module. The plan, its credits and your user id travel in the invoice's metadata and come back in the webhook.
  • Keys. PERLY_PAY_SECRET_KEY and PERLY_PAY_WEBHOOK_SECRET in .env.local (Next.js) or .env, and that file in .gitignore.
init never replaces a file or a value that is already there. --force does.

Connect the webhook

Perly Pay has to reach the webhook URL. Add it in Dashboard → Developers → Webhooks for invoice.fulfilled and paste its whsec_… secret into PERLY_PAY_WEBHOOK_SECRET. Or let init do both:

bash
npx perly-pay init --webhook-url https://your-app.example/perly-pay/webhook

On your laptop, a tunnel gives a public URL: cloudflared tunnel --url http://localhost:3000. More in Webhooks.

Pay once, in test mode

  1. 1

    Start your app

    Express and Node read .env with node --env-file=.env, or with dotenv.

  2. 2

    Open /perly-pay

    Press Pay with crypto. You land on the checkout.

  3. 3

    Simulate payment

    The invoice turns paid, then fulfilled. See Test mode.

  4. 4

    Watch grantAccess run

    Your webhook gets invoice.fulfilled. Now write what it grants.

With an AI assistant

--yes asks nothing, so Claude Code, Cursor or Codex can run it for you. Give it the key and what you sell:

bash
npx perly-pay init --yes --key sk_test_… --product "Logo review" --amount 4900

--json prints the result for the assistant to read.

Options

FlagWhat it does
--yes, -yNo questions. For AI assistants and scripts.
--framework <name>next, express, hono, laravel or node, when the guess is wrong.
--key <sk_test_…>Your test key. Default: PERLY_PAY_SECRET_KEY, or it asks.
--webhook-url <url>Registers the URL for invoice.fulfilled and saves its secret.
--product <name>, --amount <cents>, --currency <code>What you sell, in USD or EUR. --amount 4900 is $49.00.
--installInstalls the SDK too. Otherwise the command is printed.
--forceReplaces files and values that are already there.
--plugin, --mcpPrints how to add the Claude Code plugin and the perly-pay-mcp server.
--dry-runSays what would happen, writes nothing.
--jsonPrints the result as JSON.
--api <origin>, --dir <path>Another Perly Pay (a local one), another folder.

Go live

  • Connect your live wallet keys in Dashboard → Wallets.
  • Make a live key (sk_live_…) and a live webhook endpoint.
  • Set them where your app runs. The code stays as it is. SDKs has the rest of the API.