Invoice line items
An invoice line item is a single billable row on an invoice. Each line has a quantity, a unit amount, an optional product reference, and an optional description. The sum of all lines is the invoice's gross_amount_cents — the amount before any promotion-code discounts apply.
Line items are how invoices itemize charges. A simple invoice has one line ("Pro Plan, 1 × $29 = $29"). A complex B2B invoice might have a dozen lines mixing products, services, and one-off charges.
Fields
curl --request POST \
--url https://api.framepayments.com/v1/invoices/<invoice_id>/line_items \
--header "Authorization: Bearer $FRAME_SECRET_KEY" \
--header 'Content-Type: application/json' \
--data '{
"product": "<product_id>",
"quantity": 2
}'
The API accepts a narrow set of fields on create — the line inherits pricing and description from the referenced product:
product— FK to a product. The line inherits the product'sdefault_priceasunit_amount_centsand the product's name as its description.quantity— how many of this line. Defaults to 1.metadata— k/v pairs for your internal tracking.
A line item's total is quantity × unit_amount_cents. The invoice's gross_amount_cents is the sum of all its lines' totals.
Pricing comes from the product
The line item record has unit_amount_cents, unit_amount_currency, and description columns, but the create API doesn't accept overrides for these — the line inherits them from the referenced product. To bill a non-standard amount, model the charge as a Product with the right default_price and reference it; for repeated one-off variants (consulting hours, setup fees), create a Product per variant rather than trying to override pricing inline.
This is more constrained than a free-form invoice builder. If your B2B billing needs free-text line items with arbitrary pricing per invoice, the workaround is to maintain a generic "Custom" product and update its default_price per-customer — though that mutates the catalog and isn't a great pattern. Talk to Frame support if free-form line items are a real requirement for your platform.
Editing line items
Line items can be added, updated, or deleted as long as the parent invoice is in draft status:
POST /v1/invoices/<invoice_id>/line_items— add a new line.PATCH /v1/invoices/<invoice_id>/line_items/<id>— update an existing line.DELETE /v1/invoices/<invoice_id>/line_items/<id>— remove a line.
Once the invoice is issued (outstanding / due), line items are frozen. Edits after issue don't take effect on the existing invoice — they'd require voiding and re-creating, or rolling into the next invoice for subscription contexts.
Lifecycle and webhooks
Line items don't carry their own state machine — they exist alongside the parent invoice. Frame fires invoice.line_item.created when a line is added. Updates and deletes happen quietly under the parent invoice's webhook surface (the invoice itself emits invoice.updated when its composition changes).
Relationships
- Invoice —
line_item.invoice_id. Mandatory. Each line belongs to exactly one invoice. - Product —
line_item.product_id. The line copiesunit_amount_cents,unit_amount_currency, anddescriptionfrom the product at creation time, so future product price changes don't mutate historical invoices.
A line item delegates its merchant and dev_mode through its parent invoice; these aren't independently settable.
Gotchas
Symptom: you tried to pass unit_amount_cents on a line item create and the API ignored it. Why: the line items endpoint permits only product, quantity, and metadata on create/update — pricing comes from the referenced product. Fix: if you need a different price, model the variant as a separate Product. See the "Pricing comes from the product" section above.
Symptom: you tried to delete a line item on an issued invoice and got an error. Why: invoices freeze line items on issue. Fix: if you need to undo a charge, void the invoice and create a fresh one with the corrected lines. For subscription invoices, the correction lands on the next cycle's invoice automatically once the underlying subscription is updated.
Symptom: line item description doesn't match what you wanted on the invoice. Why: the description is inherited from the product's name at line-creation time; there's no per-line override on the API. Fix: update the product's name (which only affects future lines, not existing ones) or use a separate Product for the variant you want to surface differently.
Reference
For the full API surface, see POST/v1/invoices/{invoice_id}/line_items and the rest of the InvoiceLineItems resource.