> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.paymentkit.com/guides/billing/invoices/pending-invoice-items/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.paymentkit.com/_mcp/server. # Pending invoice items Pending invoice items (also called floating items) let you add one-off charges to a subscription. By default, these charges are collected on the next renewal invoice. You can also [bill them immediately](#bill-pending-items-on-demand) without waiting for renewal. This is useful for usage-based charges, setup fees, or any ad-hoc billing. # How it works When you create an invoice item with a `subscription_id`, the item is stored as a "floating" item: 1. The item is created with `invoice_id = null` (not yet attached to an invoice) 2. The item is linked to the subscription via `subscription_id` 3. At the next renewal, PaymentKit automatically sweeps all floating items into the renewal invoice 4. The customer is charged for the subscription's recurring items plus all pending one-off charges # Create a pending invoice item Add a one-off charge to a subscription using the invoice items endpoint. ## With a catalog price Use a catalog price when you want consistent product naming and reporting: #### API ```bash curl -X POST https://app.paymentkit.com/api/{account_id}/invoice-items \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "customer_id": "cus_abc123", "subscription_id": "sub_xyz789", "price_id": "price_sms_usage", "quantity": 150, "description": "SMS charges - July 2026 (150 messages)" }' ``` #### Python SDK ```python item = client.invoice_items.create( account_id="acc_xxx", customer_id="cus_abc123", subscription_id="sub_xyz789", price_id="price_sms_usage", quantity=150, description="SMS charges - July 2026 (150 messages)" ) ``` ## With a custom amount Create an amount-only item when you don't need a catalog price. The currency is automatically derived from the subscription: #### API ```bash curl -X POST https://app.paymentkit.com/api/{account_id}/invoice-items \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "customer_id": "cus_abc123", "subscription_id": "sub_xyz789", "amount": 75.00, "description": "Custom setup fee" }' ``` #### Python SDK ```python item = client.invoice_items.create( account_id="acc_xxx", customer_id="cus_abc123", subscription_id="sub_xyz789", amount=75.00, description="Custom setup fee" ) ``` > **Info** > > **Currency handling:** When creating an amount-only item (no `price_id`), the currency is automatically set to match the subscription's currency. When using a `price_id`, the price's currency must match the subscription's currency. # View pending charges ## Preview the upcoming invoice Use the subscription preview endpoint to see all pending charges that will be collected at renewal: ```bash curl -X GET https://app.paymentkit.com/api/{account_id}/subscriptions/{subscription_id}/preview \ -H "Authorization: Bearer sk_live_..." ``` Each pending (floating) item is returned as its own line item in the `upcoming_invoice.items` array, listed alongside the subscription's recurring items — so you can see exactly what will be charged, not just the aggregate total. Every pending item includes its `description`, `quantity`, and `amount`, is denominated in the subscription's currency, and carries a `proration` flag indicating whether it was generated by a mid-cycle change. Itemizing pending charges in the preview does not change any totals: `upcoming_invoice.subtotal`, `total`, and related amounts already account for these items exactly once. ```json { "upcoming_invoice": { "items": [ { "description": "Pro plan", "quantity": 1, "amount": 4900, "currency": "usd", "proration": false }, { "description": "SMS charges - July 2026 (150 messages)", "quantity": 150, "amount": 1500, "currency": "usd", "proration": false } ] } } ``` ## List pending items for a subscription Use the invoice items list endpoint with `status=floating` to get all pending (unbilled) charges for a subscription. Floating items are those not yet swept onto an invoice: #### API ```bash curl -X GET "https://app.paymentkit.com/api/{account_id}/invoice-items?subscription_id=sub_xyz789&status=floating" \ -H "Authorization: Bearer sk_live_..." ``` #### Python SDK ```python result = client.invoice_items.list( account_id="acc_xxx", subscription_id="sub_xyz789", status="floating", ) ``` The response is paginated — matching items are returned in the `items` array alongside `total` and `has_more`. You can also filter by `customer_id`, or pass `status=attached` to list items already swept onto an invoice. Omit `status` to return both. > **Tip** > > **Global search** now indexes invoice items. Paste an item's `ii_` id into the dashboard search bar (or scope a search with the `ii` prefix) to jump straight to a pending item. # Validation rules | Rule | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------- | | **Subscription state** | Must be `active` or `trialing`. Cannot add pending items to cancelled, paused, or past\_due subscriptions. | | **Customer match** | The `customer_id` must match the subscription's customer. | | **Currency match** | If `price_id` is provided, the price's currency must match the subscription's currency. | | **Positive amount** | Amount-only items (no `price_id`) must have a positive `amount` or `unit_amount`. | # Renewal behavior When a subscription renews: 1. PaymentKit creates a draft renewal invoice 2. All floating items for the subscription are attached to this invoice 3. The invoice is finalized and payment is collected 4. The floating items now have `invoice_id` set to the renewal invoice If the renewal invoice is voided (e.g., due to mid-cycle changes), floating items return to their unbilled state (`invoice_id = null`) and will be swept into the replacement invoice. # Bill pending items on demand Bill accumulated charges immediately without waiting for the next renewal. The bill-pending-items endpoint sweeps all floating items for a customer into standalone invoices, finalizes them, and attempts collection. ```mermaid flowchart LR A[Floating items] --> B[Create invoice per currency] B --> C[Finalize] C --> D{Payment} D -->|Success| E[Invoice paid] D -->|Failure| F[Invoice open for dunning] ``` ## Create an off-cycle invoice #### API ```bash curl -X POST https://app.paymentkit.com/api/{account_id}/invoices/bill-pending-items \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: bill-cus123-july-usage" \ -d '{ "customer_id": "cus_abc123" }' ``` #### Python SDK ```python result = client.invoices.bill_pending_items( account_id="acc_xxx", customer_id="cus_abc123" ) for invoice in result.invoices: print(f"{invoice.currency}: {invoice.total_amount_atom} atoms, {invoice.items_swept} items") ``` **Response:** ```json { "invoices": [ { "id": "inv_abc123", "currency": "usd", "status": "paid", "total_amount_atom": 1500, "items_swept": 3 } ] } ``` The response contains one invoice per currency. If the customer has no pending items, the `invoices` array is empty. ## Filter which items to bill By default, all floating items for the customer are swept. Use filters to narrow the scope. ### Bill specific items Pass `item_ids` to sweep only specific floating items: ```bash curl -X POST https://app.paymentkit.com/api/{account_id}/invoices/bill-pending-items \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "customer_id": "cus_abc123", "item_ids": ["ii_item1", "ii_item2"] }' ``` When `item_ids` is provided, other filters (`subscription_id`, `currency`) are ignored. ### Bill items from a specific subscription ```bash curl -X POST https://app.paymentkit.com/api/{account_id}/invoices/bill-pending-items \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "customer_id": "cus_abc123", "subscription_id": "sub_xyz789" }' ``` ### Bill items in a specific currency ```bash curl -X POST https://app.paymentkit.com/api/{account_id}/invoices/bill-pending-items \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "customer_id": "cus_abc123", "currency": "EUR" }' ``` ## Request fields | Field | Type | Required | Description | | ------------------- | ------- | -------- | -------------------------------------------------------------------------- | | `customer_id` | string | Yes | Customer whose pending items to bill | | `item_ids` | array | No | Specific item IDs to sweep. Overrides other filters. | | `subscription_id` | string | No | Narrow to a single subscription | | `currency` | string | No | Narrow to a single currency. If omitted, creates one invoice per currency. | | `tax_amount_atom` | integer | No | Tax amount in smallest currency unit (default: 0) | | `discount_id` | string | No | Discount to apply to the invoice | | `collection_method` | string | No | `charge_automatically` or `send_invoice`. Defaults to customer's setting. | | `description` | string | No | Invoice memo | ## Response fields | Field | Type | Description | | ------------------------------ | ------- | ----------------------------------- | | `invoices` | array | Invoices created (one per currency) | | `invoices[].id` | string | Invoice external ID | | `invoices[].currency` | string | Invoice currency code | | `invoices[].status` | string | `paid`, `open`, etc. | | `invoices[].total_amount_atom` | integer | Total in smallest currency unit | | `invoices[].items_swept` | integer | Number of floating items attached | ## Behavior | Scenario | Behavior | | ------------------------ | ---------------------------------------------------------------------------------------------- | | **Multi-currency** | Creates one invoice per currency. A customer with USD and EUR pending items gets two invoices. | | **Payment success** | Invoice status is `paid`. | | **Payment failure** | Invoice remains `open` and enters the dunning flow. | | **No pending items** | Returns empty `invoices` array (200 OK). | | **Paused subscriptions** | Items from paused subscriptions are excluded. | | **Race with renewal** | Row-level locking prevents double-billing. If a renewal is in progress, returns 409 Conflict. | > **Warning** > > **Idempotency:** Without an `Idempotency-Key` header, duplicate requests create duplicate invoices. Always include an idempotency key for production use. # Use cases | Use case | Implementation | | -------------------------------- | --------------------------------------------------------------------------------------------------------- | | **Usage-based billing** | Track usage throughout the billing period, then create a pending item with the total usage before renewal | | **One-time setup fees** | Add a setup fee when the subscription is created or upgraded | | **Ad-hoc professional services** | Bill consulting or implementation hours as they occur | | **Overage charges** | Add charges when customers exceed plan limits | | **On-demand usage billing** | Accumulate charges mid-cycle (e.g., SMS), then call `/invoices/bill-pending-items` to collect immediately | > **Warning** > > **Pending items do not affect subscription state.** Pending charges are passive — they don't trigger pause, cancel, or dunning logic. They are simply swept into the renewal invoice when it's created. > Add one-off charges to a subscription and collect them at renewal or on demand.