Source: https://datafa.st/docs/api/website/payments/create
Markdown source: https://datafa.st/docs/api/website/payments/create.md
Description: Record a payment, refund, renewal, or free trial from a custom payment flow — for providers without a native DataFast integration or for [payment links](/changelog/payment-api-lemonsqueezy-payment-links). Always include `datafast_visitor_id` when possible so revenue is [attributed](/docs/revenue-attribution-guide) to marketing channels.

# Create a payment

`POST https://datafa.st/api/v1/payments`

Record a payment, refund, renewal, or free trial from a custom payment flow — for providers without a native DataFast integration or for [payment links](/changelog/payment-api-lemonsqueezy-payment-links). Always include `datafast_visitor_id` when possible so revenue is [attributed](/docs/revenue-attribution-guide) to marketing channels.

Successful responses use a plain JSON body (no `status` wrapper). Duplicate `transaction_id` values are handled idempotently.

> **Related:** [Revenue attribution](/docs/revenue-attribution-guide) · [Custom payment API](/changelog/payment-api-lemonsqueezy-payment-links)

## Request

#### Query parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `websiteId` | string | Required with dft_ | Required with a `dft_` account token on Website API routes. Omit with a `df_` website key. Example: `?websiteId=665f0b3c4d2e1a0012345678`. |

#### Body parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `amount` | number | Yes | Amount in major currency units. Example: `29.99`. Use `0` for free trials (or set `is_free_trial: true`). |
| `currency` | string | Yes | ISO currency code matching your charge. Example: `"USD"`. |
| `transaction_id` | string | Yes | Unique ID from your billing system — used for idempotency. Example: `"txn_abc123"`. Re-posting the same ID returns a duplicate message, not a second payment. |
| `datafast_visitor_id` | string | No | Visitor UUID from the `datafast_visitor_id` cookie or tracking script. Example: `"a3ab2331-989f-4cfa-91c6-2461c9e3c6bd"`. Alias: `visitorId` on some endpoints. Strongly recommended for [revenue attribution](/docs/revenue-attribution-guide). |
| `email / customer_email` | string | No | Customer email. Helps match free trials to later payments. Accepts `email` or `customer_email`. |
| `name / customer_name` | string | No | Human-readable name for the resource or event. The exact meaning depends on the endpoint. |
| `customer_id` | string | No | Stable customer ID from your billing system. Example: `"cus_abc123"`. |
| `renewal` | boolean | No | Whether the payment is a recurring renewal. This affects lifecycle and renewal revenue reporting. |
| `refunded` | boolean | No | Whether this payload represents a refund instead of a payment. |
| `is_free_trial` | boolean | No | Whether this payload represents a free trial. Also inferred when `amount` is `0`. `true` for free trials. Also inferred when `amount` is `0`. |
| `timestamp` | string | No | ISO 8601 event time. Defaults to request time. Example: `"2026-05-21T12:00:00Z"`. |

#### Example request body

```json
{
  "amount": 29.99,
  "currency": "USD",
  "transaction_id": "txn_abc123",
  "datafast_visitor_id": "a3ab2331-989f-4cfa-91c6-2461c9e3c6bd",
  "email": "customer@example.com"
}
```

Always include `datafast_visitor_id` when possible so revenue is [attributed](/docs/revenue-attribution-guide) to traffic sources.

## Response

Returns a plain JSON object. This endpoint intentionally does not wrap successful create responses in `status: "success"`.

#### Response fields

| Field | Type | Description |
| --- | --- | --- |
| `message` | string | Human-readable confirmation or status message for the operation. Result message. This endpoint does not wrap create responses in `status`. |
| `transaction_id` | string | Unique transaction ID from your payment provider. Used for idempotency and deletion. Transaction ID that was recorded, skipped, refunded, or attributed. |

## Authentication

- **`df_` website API key:** The website is inferred from the key. You do not need a `websiteId` query parameter.
- **`dft_` account token:** Requires `payments:write` permission and `?websiteId=` on every request. The token must be allowed to access that website.

Read [authentication and scopes](/docs/api/authentication) for token creation, permission lists, and scoped tokens.

### Errors

**400** — Missing `amount`, `currency`, or `transaction_id`, invalid amount, or invalid field combination.

**404** — Website not found.

See [API errors](/docs/api#errors) for the standard error envelope, auth failures, validation errors, permission errors, and rate limits.

## Code examples

### Example request

```bash
curl -X POST "https://datafa.st/api/v1/payments" \
  -H "Authorization: Bearer df_xxx" \
  -H "Content-Type: application/json" \
  -d '{"amount":29.99,"currency":"USD","transaction_id":"payment_456","datafast_visitor_id":"visitor-id-from-cookie"}'
```

### Success response

```json
{
  "message": "Payment recorded and attributed successfully",
  "transaction_id": "payment_456"
}
```
