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

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

> **Warning:** The `perly-pay` package is on its way to npm. Until it is there, follow the [Quick start](https://pay.perly.io/docs/quick-start.md): 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

| Framework | Found by | Files |
| --- | --- | --- |
| Next.js (App Router) | `next` | `lib/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` |
| Express | `express` | `lib/perly-pay.js`, `routes/perly-pay.js` |
| Hono | `hono` | `lib/perly-pay.ts`, `routes/perly-pay.ts` |
| Laravel | `artisan`, `laravel/framework` | `app/Http/Controllers/PerlyPayController.php`, `routes/perly-pay.php`, `config/perly-pay.php`, `resources/views/perly-pay/button.blade.php` |
| Node.js | any other `package.json` | `lib/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`.

> **Note:** 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](https://pay.perly.io/docs/webhooks.md).

## Pay once, in test mode

1. **Start your app** — Express and Node read `.env` with `node --env-file=.env`, or with dotenv.
2. **Open /perly-pay** — Press **Pay with crypto**. You land on the checkout.
3. **Simulate payment** — The invoice turns paid, then fulfilled. See [Test mode](https://pay.perly.io/docs/test-mode.md).
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

| Flag | What it does |
| --- | --- |
| `--yes`, `-y` | No 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. |
| `--install` | Installs the SDK too. Otherwise the command is printed. |
| `--force` | Replaces files and values that are already there. |
| `--plugin`, `--mcp` | Prints how to add the Claude Code plugin and the `perly-pay-mcp` server. |
| `--dry-run` | Says what would happen, writes nothing. |
| `--json` | Prints 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](https://pay.perly.io/docs/sdks.md) has the rest of the API.
