***
title: Create an invoice
subtitle: >-
Generate one-off invoices for custom charges, or understand how subscription
invoices are created automatically.
-----------------------------------
# One-off invoices
Create a standalone invoice for a customer that is not tied to a subscription. Use one-off invoices for custom charges, consulting fees, setup fees, or any non-recurring billing.
1. Go to **Billing > Invoices** in the sidebar
2. Click **Create Invoice**
3. Select a customer
4. Set the currency and issued date
5. Add line items with descriptions, quantities, and amounts
6. Click **Create**
The invoice is created in **Draft** state. Finalize it to begin collection.
```bash
curl -X POST https://api.paymentkit.com/api/{account_id}/invoices \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cus_abc123",
"currency": "USD",
"issued_at": "2026-02-01T00:00:00Z",
"description": "Setup fee - Enterprise onboarding",
"items": [
{
"description": "Enterprise onboarding",
"quantity": 1,
"amount": 500.00
},
{
"description": "Custom integration development",
"quantity": 4,
"unit_amount": 150.00
}
]
}'
```
```python
invoice = client.invoices.create(
account_id="acc_abc123",
customer_id="cus_abc123",
currency="USD",
issued_at="2026-02-01T00:00:00Z",
description="Setup fee - Enterprise onboarding",
items=[
{
"description": "Enterprise onboarding",
"quantity": 1,
"amount": 500.00
},
{
"description": "Custom integration development",
"quantity": 4,
"unit_amount": 150.00
}
]
)
```
## Line item fields
| Field | Description |
| ------------- | ------------------------------------------------------------------------- |
| `name` | Display name for the line item |
| `description` | Description displayed on the invoice |
| `quantity` | Number of units (default: 1) |
| `unit_amount` | Price per unit |
| `amount` | Total amount for this line item (alternative to `unit_amount * quantity`) |
| `price_id` | Link to an existing price in your product catalog |
| `metadata` | Free-form metadata for the item |
Use `price_id` to reference a catalog price, or provide `amount`/`unit_amount` for ad-hoc charges.
# Subscription invoices
Subscription invoices are generated automatically by the billing lifecycle. You do not need to create them manually.
PaymentKit generates invoices at these points:
| Event | Billing reason |
| ------------------------------------------------------------ | --------------------- |
| Subscription created | `subscription_create` |
| Billing period renews | `subscription_cycle` |
| Subscription items changed (with `always_invoice` proration) | `subscription_update` |
Each invoice contains line items built from the subscription's active items at the time of generation.
# Invoice lifecycle
Every invoice follows this state flow:
| State | Description |
| ------------------ | ------------------------------------------------------------------- |
| **Draft** | Invoice is being prepared. Items and amounts can still be modified. |
| **Open** | Finalized and ready for payment. Amounts are locked. |
| **Paid** | Payment collected in full. |
| **Partially paid** | Some payment received, balance remaining. |
| **Past due** | Payment deadline has passed. Dunning retries are active. |
| **Void** | Invoice cancelled. No payment expected. |
| **Uncollectible** | All collection attempts exhausted. |
## Transitions
| From | To | Trigger |
| -------------- | -------------- | -------------------------------- |
| Draft | Open | Invoice finalized |
| Draft | Void | Invoice voided before finalizing |
| Open | Paid | Payment succeeds in full |
| Open | Partially paid | Partial payment received |
| Open | Past due | Payment deadline passes |
| Open | Void | Invoice voided |
| Open | Uncollectible | Dunning exhausted |
| Partially paid | Paid | Remaining balance paid |
| Partially paid | Past due | Payment deadline passes |
| Partially paid | Void | Invoice voided |
| Past due | Paid | Payment recovered |
| Past due | Partially paid | Partial payment received |
| Past due | Uncollectible | Dunning exhausted |
| Uncollectible | Void | Invoice voided |
# Finalize an invoice
Finalizing moves a draft invoice to **Open** state, locks all amounts, and optionally triggers PDF generation and email delivery.
```bash
curl -X POST https://api.paymentkit.com/api/{account_id}/invoices/{invoice_id}/finalize \
-H "Authorization: Bearer sk_live_..."
```
```python
invoice = client.invoices.finalize(
account_id="acc_abc123",
invoice_id="in_abc123"
)
```
# Collect payment
Attempt to collect payment on an open invoice:
```bash
curl -X POST https://api.paymentkit.com/api/{account_id}/invoices/{invoice_id}/collect \
-H "Authorization: Bearer sk_live_..."
```
The response includes the payment outcome:
```json
{
"invoice_id": "in_abc123",
"invoice_status": "paid",
"subscription_id": null,
"payment_status": "paid",
"error_message": null
}
```
If the invoice is still in **Draft** state, the collect endpoint finalizes it before attempting payment.
For subscription invoices, payment collection is handled automatically by the lifecycle engine. Use the collect endpoint for manual invoices or to retry a failed payment.
# Webhook events
| Event | Trigger |
| ------------------------------ | ---------------------------- |
| `invoice.created` | Invoice created |
| `invoice.finalized` | Draft finalized to Open |
| `invoice.paid` | Payment collected in full |
| `invoice.payment_succeeded` | A payment attempt succeeded |
| `invoice.payment_failed` | A payment attempt failed |
| `invoice.overdue` | Invoice became past due |
| `invoice.voided` | Invoice voided |
| `invoice.marked_uncollectible` | Invoice marked uncollectible |