---
title: "Payments API"
description: "Record payments from any provider with POST /api/payment and optional visitor attribution fields."
source: "https://xpmetric.com/docs/revenue/payments-api"
---
Use the Payments API when you process orders outside Stripe/Polar — WordPress plugins, Paddle webhooks, manual backends — and still want revenue in XPmetric with optional visitor attribution.

## Get your API secret

1. Open **Settings → Integrations** for the site.
2. Generate an **API secret** (`xpm_sk_…`) — shown once; store it securely.
3. **Never** use your public site token (`data-site` in `p.js`) for this endpoint.

## Record a payment

<PaymentsApiCurl />

### Request body

| Field | Required | Description |
|-------|----------|-------------|
| `amount_cents` | Yes | Integer cents (negative for refunds) |
| `currency` | Yes | ISO code, e.g. `usd` |
| `external_id` | Yes | Your unique charge/order id |
| `type` | No | `new`, `renewal`, `one_time`, `refund` (default `one_time`) |
| `visitor_id` | No | `window.xpmetric.v` at purchase time |
| `session_id` | No | `window.xpmetric.s` at purchase time |
| `occurred_at` | No | ISO 8601 timestamp (default now) |

### Auth & limits

- Header: `Authorization: Bearer xpm_sk_…`
- Rate limit: **120 requests/minute** per site
- Idempotent on `(source, external_id)` — safe to retry

## Attribution

When `visitor_id` is set, XPmetric looks up first-touch channel, referrer, UTM, and landing path from ClickHouse and stores them on the `PaymentEvent` row.

## XP

New non-refund payments award **+100 XP** to the site (same as Stripe/Polar sync).

## Related

- [Stripe Checkout](/docs/revenue/stripe-checkout) — zero-code path for Stripe
- [Custom goals](/docs/custom-goals) — track the conversion event before payment

