> For the complete index of the 402pay docs, see [llms.txt](https://402pay.co/docs/llms.txt).

# Quickstart

Accept your first payment in five steps, from a new account to a fulfilled order.

## Before you start

| You need | Why |
| --- | --- |
| A 402pay account | It owns your wallet, your keys and every payment. |
| A server | Secret keys only ever live on a server, never in a browser or app. |
| A public HTTPS endpoint | For the webhook that tells you when a payment succeeds. |

> Never put a secret key in browser or mobile code. Anyone who opens the developer tools could read it and act as your business. Create payments on your server and send the customer only the checkout `url`.

## Create an account

Sign up with your email and a passkey or a password, enter the code we email you, then add your business and create its wallet. It takes a few minutes. [Create an account](https://dash.402pay.co/auth/signup).

## Create a secret key

In the dashboard, open Developers, then API keys, and create a secret key. Its secret starts with `402s_live_` and is shown once, so put it in your server's environment.

Shell:

```bash
export PAY402_SECRET_KEY="402s_live_..."
```

> There is no test mode: every payment you create is real and moves real money, so start with small amounts.

## Create a payment

Create it from your server when the customer is ready to pay. The response carries a hosted checkout `url`.

cURL:

```bash
curl -X POST "https://api.402pay.co/api/v1/payments" \
  -H "Authorization: Bearer $PAY402_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "49.00",
    "currency": "USD",
    "reference": "order_1042",
    "description": "Pro plan, monthly",
    "success_url": "https://example.com/thanks"
  }'
```

Node.js:

```js
const response = await fetch("https://api.402pay.co/api/v1/payments", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PAY402_SECRET_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    amount: "49.00",
    currency: "USD",
    reference: "order_1042",
    description: "Pro plan, monthly",
    success_url: "https://example.com/thanks"
  }),
});
const { data } = await response.json();
```

Python:

```python
import os

import requests

response = requests.post(
    "https://api.402pay.co/api/v1/payments",
    headers={
        "Authorization": f"Bearer {os.environ['PAY402_SECRET_KEY']}",
    },
    json={
        "amount": "49.00",
        "currency": "USD",
        "reference": "order_1042",
        "description": "Pro plan, monthly",
        "success_url": "https://example.com/thanks"
    },
)
data = response.json()["data"]
```

## Send the customer to checkout

Redirect to the payment's `url`. Checkout handles the coin and network, cards, short transfers and the receipt, then sends the customer to your `success_url`.

## Fulfill the order on a webhook

Add a webhook endpoint for `payment.succeeded`, in the dashboard under Developers, then Webhooks, or through the API. Its `url` must be a public `https://` address, so `localhost` and private networks are refused. Save the signing secret in the response: it's shown once.

cURL:

```bash
curl -X POST "https://api.402pay.co/api/v1/webhooks" \
  -H "Authorization: Bearer $PAY402_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/402pay",
    "event_types": ["payment.succeeded"],
    "description": "Fulfill orders"
  }'
```

Node.js:

```js
const response = await fetch("https://api.402pay.co/api/v1/webhooks", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PAY402_SECRET_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://example.com/webhooks/402pay",
    event_types: ["payment.succeeded"],
    description: "Fulfill orders"
  }),
});
const { data } = await response.json();
```

Python:

```python
import os

import requests

response = requests.post(
    "https://api.402pay.co/api/v1/webhooks",
    headers={
        "Authorization": f"Bearer {os.environ['PAY402_SECRET_KEY']}",
    },
    json={
        "url": "https://example.com/webhooks/402pay",
        "event_types": ["payment.succeeded"],
        "description": "Fulfill orders"
    },
)
data = response.json()["data"]
```

When it arrives, [verify the signature](https://402pay.co/docs/guides/webhooks.md#verify) and fulfill the order its `reference` points to.

webhooks.js, Node.js:

```js
// Fulfill once, when the payment succeeds.
app.post("/webhooks/402pay", express.raw({ type: "application/json" }), async (req, res) => {
  if (!verifyWebhook(process.env.PAY402_WEBHOOK_SECRET, req.headers, req.body)) {
    return res.sendStatus(400);
  }
  res.sendStatus(200);

  const event = JSON.parse(req.body);
  // A test delivery names a made-up payment, and its data holds only that id.
  if (event.test) return;
  if (event.type === "payment.succeeded") {
    await orders.markPaid(event.data.reference, event.data.id);
  }
});
```

> Each delivery is a signed HTTPS request to your endpoint. Read every attempt under Developers, then Webhooks, or with `GET /webhook-deliveries`.

## Next steps

- [Going live](https://402pay.co/docs/going-live.md): Everything to check before you take real payments, and after.
- [Hosted checkout](https://402pay.co/docs/guides/hosted-checkout.md): Everything between choosing how to pay and the receipt, on one hosted page.
- [Underpayments and overpayments](https://402pay.co/docs/guides/underpayments.md): What happens when a customer sends too little, too much, too late or on the wrong network.
- [Webhooks](https://402pay.co/docs/guides/webhooks.md): Signed events for every change, retried until your server answers.
