Update an invoice
AI agents: read /llms.txt; add .md to any page URL. This page as Markdown: /reference/invoices/v2-invoice-update.md. Index of every page and the rules for every call: /llms.txt. Guides and concepts in one file: /llms-full.txt. OpenAPI: /openapi.json.
PUT/
Changes an invoice's header (number, issue date, addresses) and, in the same save, its lines, its tax and the order of its lines. Everything in one call is saved together or not at all.
item_actionsadds, changes and removes lines: each entry is like a row of Add, change and remove invoice lines at once (deletes run first, then creates, then updates). Tax lines can't be added or changed here; adeleteof the tax line removes it (except on Auto Invoice invoices).tax_selectionsets, changes or removes the one tax line, as in Change the tax on an invoice.resort_items: truespaces out the line positions again, keeping their order.
Returns the invoice; its items are included when you sent item_actions, tax_selection or resort_items.
Address changes and tax: updating only the header addresses does not automatically recalculate tax on a manual invoice. To update tax for a new address on a manual invoice, include tax_selection in your request. When the order has Auto Invoice turned on, YoPrint automatically maintains a single invoice (auto_invoice_managed: true): whenever you add, edit, or remove lines or shipping fees on the order, YoPrint automatically updates the matching lines, shipping fees, and tax on this invoice. On an Auto Invoice invoice, changing the destination address automatically recalculates the managed Auto Tax line (custom tax lines you set manually are left unchanged).
Business rules
- The invoice's customer is always reset to the order's customer.
- On an Auto Invoice invoice, a new Bill To or Ship To must be a current address of your team or the customer ("The selected billing address must be a current address."), and
resort_itemsis refused. - On an invoice from Shopify, the address ids can't change: 422
shopify_invoice_snapshot_update_boundary. - On an order deleted in Shopify nothing can change: 422
shopify_order_deleted_externally. - Tax lines can't be added or changed in
item_actions: "Tax Item is not allow in bulk operations." Adeleteof the tax line there removes it on an invoice without Auto Invoice (refused on one with it). Usetax_selectionfor tax changes. - Every rule of the line calls applies to
item_actionsrows. - In
tax_selection, bothexpected_taxanddesired_taxmust be present; null is allowed for either. Missing: 422 "The tax_selection.expected_tax field must be present." (ordesired_tax). expected_taxmust match the current tax line exactly (id andlock_version), or be null when there is none. Otherwise 422invoice_tax_conflict: "Invoice tax changed in another window. Reload and retry."- A different
typefrom the current one replaces the line (new id); the same type updates it; null deletes it. - A tax line you set is yours: YoPrint no longer manages it, even on an Auto Invoice invoice.
- Auto Tax needs a US plan with Auto Tax turned on: otherwise 422
cart_item_validation_errorwitherror.context.reasonauto_tax_unavailable. - Synced (external) invoices are read-only here: 422
external_invoice_tax_snapshot_read_only.
Side effects
- Line and tax changes recalculate the invoice and the order's invoiced totals, and automatically redistribute (reallocate) the order's payments across its invoices.
- When the team syncs to QuickBooks Online automatically and the order is published, the order is synced again about 3 minutes later.
- Auto Tax (on create, change, or an address change on an Auto Invoice invoice) calls the tax provider while you wait.
- Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open. No webhook or email is sent.
Path parameters
Your team slug, shown as Team ID next to your API key in Profile.
- Example
your-team
- Example
The invoice's
id(a hash id), as its answers show it. Its unique key (ordinv_...) also works, but API answers don't include it.- Example
cBRpSf5nw6upt5
- Example
Request body
application/json, required.
billing_address_idstring | nullBill To address hash id. Null clears it.
issue_datestring (date-time)The issue date (ISO 8601).
item_actionsarray of objectsLine changes, applied in the same save. Tax lines can't be created or updated here (use
tax_selection).Fields of each item (4)
- One of:
"update","create","delete"
- One of:
Your label for this row, echoed in errors.
cart_item_idstringThe invoice line. Required for
updateanddelete.payloadobjectRequired for
createandupdate: the line body, as in Add a line to an invoice or Update an invoice line.
resort_itemsbooleantruere-spaces line positions, keeping the current order. Not allowed on Auto Invoice invoices.scoped_idstringThe invoice number, as a string. Not checked for duplicates.
shipping_address_idstring | nullShip To address hash id. Null clears it.
tax_selectionobjectSet, change or remove the invoice's one tax line. Send both keys; either may be null.
Child fields (2)
The tax you want, or null to remove the tax line.
Child fields (2)
propertiesobjectThe fields of that kind, as for an invoice line of that
product.type:auto_taxtakesengineus,from,toandrate;user_taxtakes the presetid;override_taxtakesmodeandtotal.typestringauto_tax(US Auto Tax),user_tax(one of your tax presets) oroverride_tax(set by hand).- One of:
"auto_tax","user_tax","override_tax"
- One of:
The tax line you think is there now: its
idandlock_versionfrom the invoice's items, or null when it has none. If it doesn't match, nothing changes (422invoice_tax_conflict).Child fields (2)
idstringThe current tax line.
lock_versionintegerThat line's
lock_version.- Minimum 0
Response
200Successful response.
An invoice. Amounts are decimal pairs at the stored scale (4 decimal places for invoice totals), except
paid_amountandcalc_deposit_total(thousandths). Thecalc_*totals are deprecated copies of the decimal-pair ones.Child fields (43)
auto_invoice_managedbooleanYoPrint keeps this invoice in step with the order (Auto Invoice).
bill_to_statusstringHow Bill To compares with the order's.
- One of:
"okay","empty","diff_from_order","diff_from_customer"
- One of:
billing_addressobject | nullAn address.
Child fields (10)
address1string | nulladdress2string | nullcitystring | nullcountrystring | nullcountry_codestring | nullidstringThe address.
labelstring | nullpostcodestring | nullstatestring | nullstate_codestring | null
billing_address_idstring | nullBill To.
calc_deposit_totalinteger | number | string | nullThe order's deposit amount. Thousandths, an older encoding:
12500is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (1234.5is 1.2345), or as a string ("1234.5") when you sendX-Yoprint-Decimal-Format: exact-v1. See Money and quantities.cart_item_subtotaldecimal pairBilled sales order lines and shipping fees (price × quantity);
shipment_subtotalis the shipping part of it.total=cart_item_subtotal−discount_subtotal+tax_subtotal(+credit_card_surcharge). At the stored scale (4 decimal places). A decimal pair: the amount isvalue÷ 10^dp({ "value": 1250, "dp": 2 }is 12.50). Readdpevery time: it can differ between fields and records.- See Money and quantities.
created_atstring (date-time)credit_card_surchargedecimal pairA card surcharge added by a card payment; zero when there is none. Always sent. A decimal pair: the amount is
value÷ 10^dp({ "value": 1250, "dp": 2 }is 12.50). Readdpevery time: it can differ between fields and records.- See Money and quantities.
customerobject | nullThe customer (the full customer record).
deposit_duestring (date-time) | nullFrom the order. ISO 8601 with offset, or null.
deposit_requiredboolean | integer | nullFrom the order.
discount_subtotaldecimal pairDiscounts. A decimal pair: the amount is
value÷ 10^dp({ "value": 1250, "dp": 2 }is 12.50). Readdpevery time: it can differ between fields and records.- See Money and quantities.
external_typestring | nullfrom_legacybooleanfull_amount_duestring (date-time) | nullFrom the order. ISO 8601 with offset, or null.
idstringThe invoice.
is_externalbooleanis_paidbooleanPaid amount covers the total (also true for a zero total).
is_validbooleanFalse when the invoice needs fixing: no lines, lines without a tax line, or a customer that differs from the order's.
issue_datestring (date-time) | nullIssue date. ISO 8601 with offset, or null.
itemsarray of objectsThe lines. Sort by
position.Fields of each item (15)
_metaobjectRead-only:
id,type,invoice_id,lock_version,from_legacy,position_hash.auto_invoice_managedbooleanYoPrint manages this line (Auto Invoice).
external_idsarray of objectsLinks to external systems; empty for lines made in YoPrint.
external_typestring | nullfrom_legacybooleanidstringThe invoice line.
invoice_idstringThe invoice.
is_externalbooleanlock_versionintegerSend it back on Update an invoice line to detect a concurrent change.
positionintegerpricingobjectAbsent on tax and discount lines.
system(sales order lines):_meta.unit_priceis the price copied from the sales order line and_meta.subtotalis that price × this line's quantity.fee(shipping fees):product.totalis the fee. Prices come at the stored scale (6 decimal places);_meta.subtotalat the combined scale of price × quantity (compacted when large). Always readdp.Child fields (1)
typestring- One of:
"system","fee"
- One of:
productobjectChild fields (3)
_metaobjectRead-only details, always an object (with
editable_fields_on_update); fororder_item,parentdescribes the sales order line.propertiesobjectThe kind's fields; for
order_item,idis the sales order line. A discount's percentage or amount comes back astotal(you send it asrate).typestring- One of:
"order_item","shipment_fee","invoice_discount","user_tax","override_tax","auto_tax","invoice_surcharge"
- One of:
quantityobjectAbsent on tax and discount lines.
Child fields (2)
typestring- Always
"unit"
- Always
totaldecimal pairThe quantity. A decimal pair: the amount is
value÷ 10^dp({ "value": 1250, "dp": 2 }is 12.50). Readdpevery time: it can differ between fields and records.- See Money and quantities.
taxobjectAbsent on tax and discount lines. YoPrint adds it by default only to sales order lines (
taxable); other lines have it only when it was sent.Child fields (1)
typestring- One of:
"taxable","non_taxable"
- One of:
typestringSame as
product.type.
lock_versionintegerorderobjectThe sales order or quote in the v2 order shape: its header fields, with
statusandassigned_users, but noitems.order_idstringThe sales order or quote it bills.
order_object_typestring | nullsales_orderorquote.order_quotebooleanThe order is a quote.
order_scoped_idstring | nullThe order number.
paid_amountinteger | number | string | nullAllocated payments. Thousandths, an older encoding:
12500is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (1234.5is 1.2345), or as a string ("1234.5") when you sendX-Yoprint-Decimal-Format: exact-v1. See Money and quantities.pdf_urlarray of objectsPDF links.
Fields of each item (3)
labelstringobject_typestringurlstringA download link with its own long-lived access token: don't publish it.
scoped_idstring | nullThe invoice number.
ship_to_statusstring- One of:
"okay","empty","diff_from_order","diff_from_customer"
- One of:
shipment_subtotaldecimal pairShipping fees (already in
cart_item_subtotal). A decimal pair: the amount isvalue÷ 10^dp({ "value": 1250, "dp": 2 }is 12.50). Readdpevery time: it can differ between fields and records.- See Money and quantities.
shipment_tax_subtotaldecimal pairThe tax on shipping (included in
tax_subtotal). A decimal pair: the amount isvalue÷ 10^dp({ "value": 1250, "dp": 2 }is 12.50). Readdpevery time: it can differ between fields and records.- See Money and quantities.
shipping_addressobject | nullAn address.
- Same fields as
data.billing_address.
- Same fields as
shipping_address_idstring | nullShip To.
tax_subtotaldecimal pairTax. A decimal pair: the amount is
value÷ 10^dp({ "value": 1250, "dp": 2 }is 12.50). Readdpevery time: it can differ between fields and records.- See Money and quantities.
totaldecimal pairThe invoice total. A decimal pair: the amount is
value÷ 10^dp({ "value": 1250, "dp": 2 }is 12.50). Readdpevery time: it can differ between fields and records.- See Money and quantities.
versionintegerDeprecated: use
shipment_subtotal, the same amount. Thousandths, an older encoding:12500is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (1234.5is 1.2345), or as a string ("1234.5") when you sendX-Yoprint-Decimal-Format: exact-v1. See Money and quantities.Deprecated: use
discount_subtotal, the same amount. Thousandths, an older encoding:12500is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (1234.5is 1.2345), or as a string ("1234.5") when you sendX-Yoprint-Decimal-Format: exact-v1. See Money and quantities.Deprecated: use
cart_item_subtotal, the same amount. Thousandths, an older encoding:12500is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (1234.5is 1.2345), or as a string ("1234.5") when you sendX-Yoprint-Decimal-Format: exact-v1. See Money and quantities.Deprecated: use
tax_subtotal, the same amount. Thousandths, an older encoding:12500is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (1234.5is 1.2345), or as a string ("1234.5") when you sendX-Yoprint-Decimal-Format: exact-v1. See Money and quantities.Deprecated: use
total, the same amount. Thousandths, an older encoding:12500is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (1234.5is 1.2345), or as a string ("1234.5") when you sendX-Yoprint-Decimal-Format: exact-v1. See Money and quantities.
Errors
401The API key is missing or wrong (
unauthenticated).403You are not allowed to do this.
api_access_not_in_plan: your team's plan doesn't include API access (Pro and above, with an active subscription or trial), so every request answers this until the team upgrades. When your role lacks the permission the operation needs, the body is only{"message": "Insufficient Permission"}. Other refusals use the error envelope, withunauthorizedoruser_is_not_authorized.- When
- Your role can't edit this order (
user_is_not_authorized). - Fix
- Ask the team owner to adjust your role or assign you to the order.
404Not found.
page_not_found: the team slug is unknown, you are not a member of the team, or an id in the path is not one of this team's.code: null, with a message that starts "No query results for": there is no record with that id.- When
- The invoice isn't your team's.
- Fix
- Check the id.
422The request was refused and changed nothing.
validation_failedlists what to fix inerror.fields; other codes name a business rule, explained inerror.message. A few checks answer with only{"message": "..."}. An operation that calls another service (a payment provider, a carrier, an accounting app) can answerconnect_timeout("Please retry again") when that service does not answer in time: the change may or may not have happened there, so read the record back before you retry.- When
- Validation fails (
validation_failed, with field messages inerror.fieldssuch as "The issue date must be a valid ISO8601 string." or "The scoped id must be a string."). - Fix
- Fix the fields in
error.fields. - When
- A line row or the tax selection is refused (see rules); nothing in the call is saved.
- Fix
- Read
error.codeanderror.message, fix that part and resend the whole call.
Notes
- Send the header
X-Yoprint-Decimal-Format: exact-v1. Without it, a save that would return an amount the old number format can't carry is refused with 422amount_out_of_range. - There is no locked or permanently paid state: you can change a paid invoice, and YoPrint automatically redistributes (reallocates) the order's recorded payments across its invoices.
Related
- GETGet an invoice
/v2/ api/ store/ {team_slug}/ v2/ invoice/ {unique_key} - POSTAdd, change and remove invoice lines at once
/v2/ api/ store/ {team_slug}/ v2/ invoice/ {unique_key}/ item/ bulk - PUTChange the tax on an invoice
/v2/ api/ store/ {team_slug}/ v2/ invoice/ {unique_key}/ tax-selection - POSTCreate an invoice for a sales order
/v2/ api/ store/ {team_slug}/ v2/ sales_order/ {unique_key}/ invoice
