Skip to content

Add, change and delete line items in one save

Open .md

POST/v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}/order_item/bulk

v2Operation ID v2_public_order_item_bulk

Runs several line operations on one sales order or quote as one save: all of them are written, or none. Sending the same batch again adds the lines again, so read the order back before you retry after a timeout.

The body is a JSON array of operations. Each has your own bid, an action and, depending on the action:

  • create: payload is the body of Add a line item;
  • update: cart_item_id (the line's id) and payload, the body of Update a line item (send only what changes);
  • delete: cart_item_id only.

Whatever the order in the array, deletes run first, then creates, then updates. Prices, job decoration pricing, shipments, invoices and totals are recalculated once, at the end.

The optional header X-Yoprint-Order-Item-Save-Intent says what the save is for. The web app sends save.

  • save: when nothing in the batch changes anything, nothing is written and has_changes is false;
  • recalculate: always recalculates, even when only a description or position changed;
  • left out (or any other value): the older behavior, where has_changes is always true.

Amounts and quantities are sent as { value, dp } pairs: value is the number without its decimal point and dp is how many of its digits come after the decimal point. 12.50 is { "value": 1250, "dp": 2 }; 24 is { "value": 24, "dp": 0 }. value is a whole number (a JSON integer or a string of digits); dp is 0 to 30.

{order_unique_key} is the sales order or quote id (for example V4keXwwxMQyXw7) or its unique_key (it starts with ord_). The order number people see, such as SO1001, is not accepted here.

The answer, in data, lists every line of the order after the save, by position, each as { object_type, action_performed, has_changes, lock_version, item, bid }. A line created by this request carries its operation's bid; other lines have bid: null. Ignore action_performed and has_changes on individual rows: action_performed is always CREATED and has_changes is always true. The has_changes next to data tells whether anything changed.

A new line is refused with HTTP 422 if the product or variant cannot be sold:

  • Simple product phased out: 422 product_phased_out (error.product_id names it)
  • Simple product deleted: 422 product_deleted (error.product_id names it)
  • Size or color phased out: 422 variant_phased_out (error.variant_id names it)
  • Size or color deleted: 422 variant_deleted (error.variant_id names it)

This holds for quotes, published orders (Live Edit), and the public API alike. Resume the product, or its size or color, in Products to sell it again. Existing lines keep working. A refused batch writes none of its lines and names the refused line in error.bid.

Permission

Needs permission to edit this sales order or quote:

  • The team owner
  • A role with update_all_order
  • A role with update_self_order, when the order was created by or is assigned to the API key's user
  • The person who created a draft, with create_order

Quotes use the same sales order permissions.

Business rules

  • The body is an array. Each operation needs bid and action (create, update or delete). create and update need payload; update and delete need cart_item_id.
  • Deletes run first, then creates, then updates, whatever their order in the array.
  • One refused operation refuses the whole batch: nothing is saved. Most refusals name the operation in error.bid; a product that is not found (no envelope), a product.type change, a storage range error (error.context.item_bid) and malformed operation fields (validation_failed, error.fields like 0.bid) do not.
  • Every create and update follows the same rules as the single Add and Update operations. In particular a new catalog line needs its catalog cost in pricing.catalog unless it is customer-supplied; without it the whole batch is refused with bulk_validation_payload_failed, naming the operation's bid and "Enter the catalog cost for this line." on pricing.catalog in error.fields.
  • cart_item_id must be a line of this order: otherwise "Order item not found".
  • Lines an integration brought in can't be created or deleted here.

Side effects

  • Recalculates the line's price, every job's decoration pricing (quantity breaks count all lines on a job), the order totals, profit, margin and deposit.
  • Updates stock tracking for the line (inventory status and stock workflow), and, on a published sales order, reserves or releases stock as quantities change.
  • Updates this line on the order's invoices (new price, excess quantity removed); when the order keeps its invoice up to date automatically, rebuilds that invoice. Rebalances payments across the invoices.
  • On a published sales order with QuickBooks Online connected, queues the order's QuickBooks sync.
  • Refreshes the order for people who have it open in the web app. No email is sent.
  • Recalculates everything once, after all operations.

Path parameters

  • team_slugstringrequired

    Your team slug, shown as Team ID next to your API key in Profile.

    • Example your-team
  • order_unique_keystringrequired

    The sales order's or quote's id (a hash id), or its unique_key (ord_…). The order number (scoped_id) does not work.

    • Example V4keXwwxMQyXw7

Headers

  • save (what the web app sends): a batch that changes nothing writes nothing and answers has_changes: false (next to data). recalculate: always recalculate. Left out: the older behavior, has_changes always true.

    • One of: "save", "recalculate"
    • Example save

Request body

application/json, required.

The body is an array of objects.

Each item is one of these 3 kinds, picked by action:

Add a linecreate

Adds a line. payload is the same body as Add a line item.

  • actionstringrequired
    • Always "create"
  • bidstringrequired

    Your own id for this operation, unique in the request. The new line comes back with this bid, and an error names it.

  • payloadobjectrequired

    Pick the branch by product.type.

    One of, picked by product.type:

    Catalog productdb_catalog

    Add a product from a supplier catalog (one size and color).

    • productobjectrequired

      What the line is. type picks the kind of line and can't change later.

      Child fields (2)
      • typestringrequired
        • Always "db_catalog"
      • propertiesobjectrequired
        Child fields (3)
        • customer_suppliedbooleanrequired

          true when the customer provides the item and you only decorate it. The product price is then 0; the line still carries the decoration price. Only then may a new catalog line leave out pricing.catalog. true, 1, "1" and "true" count as true.

        • idstringrequired

          The catalog item: one size and color of a supplier style. It is the supplier code, a dash and the supplier's number, for example smr-10001.

        • Extra text shown under the line, for example a note about the color.

    • pricingobjectrequired

      How the line is priced. YoPrint determines the product price in this order:

      1. Price override: if product.override is true, YoPrint uses product.total.
      2. Customer-supplied: if customer_supplied is true (product.properties.customer_supplied), the product price is 0.
      3. Marked-up cost: otherwise, YoPrint takes the supplier cost in catalog and applies the order's pricing group markup or a matching pricing rule.

      A new catalog line must carry catalog unless customer_supplied is true (without it, the line is refused with 422: "Enter the catalog cost for this line.").

      Child fields (4)
      • typestringrequired
        • Always "catalog_product_pricing"
      • catalogobject

        The supplier price the line starts from. When you send catalog, all four fields are required.

        Child fields (4)
        • datestring (date)required

          When the price was looked up, an ISO 8601 date such as 2026-11-03 (a date-time is accepted too).

        • providerstringrequired

          The supplier code, such as smr or ssa: the code the catalog item id starts with (smr for smr-10001), and the provider of that item in its product's attr_data. YoPrint stores it as sent and doesn't check it against your suppliers.

        • selectedstringrequired

          Which supplier price total represents:

          • piece: standard piece price
          • dozen: dozen price tier
          • case: case price tier
          • account: your account's negotiated price (your_price in catalog lookups)
          • sales: the supplier's sale price (sales_price in catalog lookups)
          • custom: a custom cost you entered manually
          • legacy: lines migrated from the old editor
          • One of: "piece", "dozen", "case", "account", "sales", "custom", "legacy"
        • totaldecimal pairrequired

          The supplier's cost for one unit.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
      • productobject

        Set your own product price for one unit with override: true and total. It replaces the marked-up catalog cost.

        Child fields (2)
        • overridebooleanrequired

          true to use total as given; false to let YoPrint work it out.

        • totaldecimal pair

          The amount for one unit, as a { value, dp } pair. Up to 6 decimal places are kept.

      • serviceobject

        The decoration price added to each unit. Leave it out, or send override: false, to use the job's decoration price per unit. Send override: true with total to set your own. Ignored when the line has no job (job.type standalone).

        Child fields (2)
        • overridebooleanrequired

          true to use total instead of the job's decoration price.

        • totaldecimal pair

          The decoration price for one unit. Required when override is true. Up to 6 decimal places.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
    • quantityobjectrequired

      How many units. type is always unit.

      Child fields (2)
      • typestringrequired
        • Always "unit"
      • totaldecimal pairrequired

        The quantity as a { value, dp } pair: 24 is { "value": 24, "dp": 0 }. Up to 8 decimal places.

    • jobobjectrequired

      Which job of this order the line belongs to. Decoration prices and quantity breaks count every line on a job, so put all sizes of a product on the same job.

      One of, picked by type:

      Linked to a joblinked

      The line belongs to one of this order's jobs and takes its decoration price.

      • typestringrequired
        • Always "linked"
      • idstringrequired

        The job's id, from the order's jobs. It must be a job of this same order.

      No jobstandalone

      The line has no job, so no decoration price.

      • typestringrequired
        • Always "standalone"
    • positionintegerrequired

      Where the line sits on the order: lines are shown by ascending position. The web app spaces lines 100000 apart, which leaves room to insert between them. A value outside the allowed range is replaced by the next free position at the end.

    • weightobject

      Optional, used for shipping. Leave it out to use the product's weight.

      One of, picked by type:

      Use the product's weightuse_system

      Take the weight from the product (in lb).

      • typestringrequired
        • Always "use_system"
      Set the weightmass

      Your own weight for one unit.

      • typestringrequired
        • Always "mass"
      • totaldecimal pairrequired

        The weight as a { value, dp } pair whose two parts are strings: 1.5 is { "value": "15", "dp": "1" }.

      • unitstringrequired
        • One of: "lb", "kg"
    Custom simple productuser_simple

    Add one of your own products that has no sizes or colors.

    • productobjectrequired

      What the line is. type picks the kind of line and can't change later.

      Child fields (2)
      • typestringrequired
        • Always "user_simple"
      • propertiesobjectrequired
        Child fields (3)
        • customer_suppliedbooleanrequired

          true when the customer provides the item and you only decorate it. The product price is then 0; the line still carries the decoration price.

        • idstringrequired

          The product's id from Products.

        • Extra text shown under the line, for example a note about the color.

    • pricingobjectrequired

      How the line is priced. YoPrint determines the product price in this order:

      1. Price override: if product.override is true, YoPrint uses product.total.
      2. Customer-supplied: if customer_supplied is true (product.properties.customer_supplied), the product price is 0.
      3. Product pricing: otherwise, YoPrint starts from product_cost.total (or the price from Products when omitted or 0) and applies any matching pricing rule.
      Child fields (4)
      • typestringrequired
        • Always "product_cost_service"
      • productobject

        Set your own product price for one unit with override: true and total.

        Child fields (2)
        • overridebooleanrequired

          true to use total as given; false to let YoPrint work it out.

        • totaldecimal pair

          The amount for one unit, as a { value, dp } pair. Up to 6 decimal places are kept.

      • Your cost for one unit. Optional: leave it out, or send a total of 0, to use the product's price from Products.

        Child fields (2)
        • overridebooleanrequired

          true when you set the cost yourself.

        • totaldecimal pairrequired

          The cost for one unit. 0 means "use the product's price".

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
      • serviceobject

        The decoration price added to each unit. Leave it out, or send override: false, to use the job's decoration price per unit. Send override: true with total to set your own. Ignored when the line has no job (job.type standalone).

        Child fields (2)
        • overridebooleanrequired

          true to use total instead of the job's decoration price.

        • totaldecimal pair

          The decoration price for one unit. Required when override is true. Up to 6 decimal places.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
    • quantityobjectrequired

      How many units. type is always unit.

      Child fields (2)
      • typestringrequired
        • Always "unit"
      • totaldecimal pairrequired

        The quantity as a { value, dp } pair: 24 is { "value": 24, "dp": 0 }. Up to 8 decimal places.

    • jobobjectrequired

      Which job of this order the line belongs to. Decoration prices and quantity breaks count every line on a job, so put all sizes of a product on the same job.

      One of, picked by type:

      Linked to a joblinked

      The line belongs to one of this order's jobs and takes its decoration price.

      • typestringrequired
        • Always "linked"
      • idstringrequired

        The job's id, from the order's jobs. It must be a job of this same order.

      No jobstandalone

      The line has no job, so no decoration price.

      • typestringrequired
        • Always "standalone"
    • positionintegerrequired

      Where the line sits on the order: lines are shown by ascending position. The web app spaces lines 100000 apart, which leaves room to insert between them. A value outside the allowed range is replaced by the next free position at the end.

    • weightobject

      Optional, used for shipping. Leave it out to use the product's weight.

      One of, picked by type:

      Use the product's weightuse_system

      Take the weight from the product (in lb).

      • typestringrequired
        • Always "use_system"
      Set the weightmass

      Your own weight for one unit.

      • typestringrequired
        • Always "mass"
      • totaldecimal pairrequired

        The weight as a { value, dp } pair whose two parts are strings: 1.5 is { "value": "15", "dp": "1" }.

      • unitstringrequired
        • One of: "lb", "kg"
    Custom variant productdb_variant

    Add one size and color of your own product.

    • productobjectrequired

      What the line is. type picks the kind of line and can't change later.

      Child fields (2)
      • typestringrequired
        • Always "db_variant"
      • propertiesobjectrequired
        Child fields (3)
        • customer_suppliedbooleanrequired

          true when the customer provides the item and you only decorate it. The product price is then 0; the line still carries the decoration price.

        • idstringrequired

          The id of one size and color (a variant) of your product, not the product's own id. Each size or color is its own line.

        • Extra text shown under the line, for example a note about the color.

    • pricingobjectrequired

      How the line is priced. YoPrint determines the product price in this order:

      1. Price override: if product.override is true, YoPrint uses product.total.
      2. Customer-supplied: if customer_supplied is true (product.properties.customer_supplied), the product price is 0.
      3. Product pricing: otherwise, YoPrint starts from product_cost.total (or the price from Products when omitted or 0) and applies any matching pricing rule.
      Child fields (4)
      • typestringrequired
        • Always "product_cost_service"
      • productobject

        Set your own product price for one unit with override: true and total.

        Child fields (2)
        • overridebooleanrequired

          true to use total as given; false to let YoPrint work it out.

        • totaldecimal pair

          The amount for one unit, as a { value, dp } pair. Up to 6 decimal places are kept.

      • Your cost for one unit. Optional: leave it out, or send a total of 0, to use the product's price from Products.

        Child fields (2)
        • overridebooleanrequired

          true when you set the cost yourself.

        • totaldecimal pairrequired

          The cost for one unit. 0 means "use the product's price".

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
      • serviceobject

        The decoration price added to each unit. Leave it out, or send override: false, to use the job's decoration price per unit. Send override: true with total to set your own. Ignored when the line has no job (job.type standalone).

        Child fields (2)
        • overridebooleanrequired

          true to use total instead of the job's decoration price.

        • totaldecimal pair

          The decoration price for one unit. Required when override is true. Up to 6 decimal places.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
    • quantityobjectrequired

      How many units. type is always unit.

      Child fields (2)
      • typestringrequired
        • Always "unit"
      • totaldecimal pairrequired

        The quantity as a { value, dp } pair: 24 is { "value": 24, "dp": 0 }. Up to 8 decimal places.

    • jobobjectrequired

      Which job of this order the line belongs to. Decoration prices and quantity breaks count every line on a job, so put all sizes of a product on the same job.

      One of, picked by type:

      Linked to a joblinked

      The line belongs to one of this order's jobs and takes its decoration price.

      • typestringrequired
        • Always "linked"
      • idstringrequired

        The job's id, from the order's jobs. It must be a job of this same order.

      No jobstandalone

      The line has no job, so no decoration price.

      • typestringrequired
        • Always "standalone"
    • positionintegerrequired

      Where the line sits on the order: lines are shown by ascending position. The web app spaces lines 100000 apart, which leaves room to insert between them. A value outside the allowed range is replaced by the next free position at the end.

    • weightobject

      Optional, used for shipping. Leave it out to use the product's weight.

      One of, picked by type:

      Use the product's weightuse_system

      Take the weight from the product (in lb).

      • typestringrequired
        • Always "use_system"
      Set the weightmass

      Your own weight for one unit.

      • typestringrequired
        • Always "mass"
      • totaldecimal pairrequired

        The weight as a { value, dp } pair whose two parts are strings: 1.5 is { "value": "15", "dp": "1" }.

      • unitstringrequired
        • One of: "lb", "kg"
    Custom line itemcustom

    Add a one-off line with a name and a price, not linked to a product.

    • productobjectrequired

      What the line is. type picks the kind of line and can't change later.

      Child fields (2)
      • typestringrequired
        • Always "custom"
      • propertiesobjectrequired
        Child fields (3)
        • customer_suppliedbooleanrequired

          true when the customer provides the item and you only decorate it. The product price is then 0; the line still carries the decoration price.

        • namestringrequired

          The line's name, as the customer sees it.

        • Extra text shown under the line, for example a note about the color.

    • pricingobjectrequired

      How the line is priced. Send the unit price in product.total with override: true.

      Child fields (4)
      • typestringrequired
        • Always "custom_product"
      • productobjectrequired

        The product price for one unit. With override: true (what the web app sends) the line uses total. With override false or left out, YoPrint starts from product_cost.total (or total when no cost is set) and applies any matching pricing rule.

        Child fields (2)
        • totaldecimal pairrequired

          The price for one unit. Up to 6 decimal places are kept.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
        • overrideboolean

          true to use total as the price.

      • Optional: your cost for one unit, used for profit and margin.

        Child fields (1)
        • totaldecimal pairrequired

          Your cost for one unit.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
      • serviceobject

        The decoration price added to each unit. Leave it out, or send override: false, to use the job's decoration price per unit. Send override: true with total to set your own. Ignored when the line has no job (job.type standalone).

        Child fields (2)
        • overridebooleanrequired

          true to use total instead of the job's decoration price.

        • totaldecimal pair

          The decoration price for one unit. Required when override is true. Up to 6 decimal places.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
    • quantityobjectrequired

      How many units. type is always unit.

      Child fields (2)
      • typestringrequired
        • Always "unit"
      • totaldecimal pairrequired

        The quantity as a { value, dp } pair: 24 is { "value": 24, "dp": 0 }. Up to 8 decimal places.

    • jobobjectrequired

      Which job of this order the line belongs to. Decoration prices and quantity breaks count every line on a job, so put all sizes of a product on the same job.

      One of, picked by type:

      Linked to a joblinked

      The line belongs to one of this order's jobs and takes its decoration price.

      • typestringrequired
        • Always "linked"
      • idstringrequired

        The job's id, from the order's jobs. It must be a job of this same order.

      No jobstandalone

      The line has no job, so no decoration price.

      • typestringrequired
        • Always "standalone"
    • positionintegerrequired

      Where the line sits on the order: lines are shown by ascending position. The web app spaces lines 100000 apart, which leaves room to insert between them. A value outside the allowed range is replaced by the next free position at the end.

    • weightobject

      Optional, used for shipping. Leave it out for 0 lb.

      Child fields (3)
      • typestringrequired
        • Always "mass"
      • totaldecimal pairrequired

        The weight as a { value, dp } pair whose two parts are strings: 1.5 is { "value": "15", "dp": "1" }.

      • unitstringrequired
        • One of: "lb", "kg"
    Fee line itemfee

    Add a fee, such as a rush or setup fee.

    • productobjectrequired

      What the line is. type picks the kind of line and can't change later.

      Child fields (2)
      • typestringrequired
        • Always "fee"
      • propertiesobjectrequired
        Child fields (2)
        • namestringrequired

          The fee's name, for example "Rush fee".

        • Extra text shown under the fee, for example what it covers.

    • pricingobjectrequired

      The fee amount for one unit. Fees never take a decoration price.

      Child fields (2)
      • typestringrequired
        • Always "fee"
      • productobjectrequired
        Child fields (1)
        • totaldecimal pairrequired

          The fee for one unit, 0 or more.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
    • quantityobjectrequired

      How many units. type is always unit.

      Child fields (2)
      • typestringrequired
        • Always "unit"
      • totaldecimal pairrequired

        The quantity as a { value, dp } pair: 24 is { "value": 24, "dp": 0 }. Up to 8 decimal places.

    • jobobjectrequired

      Which job of this order the line belongs to. Decoration prices and quantity breaks count every line on a job, so put all sizes of a product on the same job.

      One of, picked by type:

      Linked to a joblinked

      The line belongs to one of this order's jobs and takes its decoration price.

      • typestringrequired
        • Always "linked"
      • idstringrequired

        The job's id, from the order's jobs. It must be a job of this same order.

      No jobstandalone

      The line has no job, so no decoration price.

      • typestringrequired
        • Always "standalone"
    • positionintegerrequired

      Where the line sits on the order: lines are shown by ascending position. The web app spaces lines 100000 apart, which leaves room to insert between them. A value outside the allowed range is replaced by the next free position at the end.

    • weightobject

      Optional, used for shipping. Leave it out for no weight.

      Child fields (3)
      • typestringrequired
        • Always "mass"
      • totaldecimal pairrequired

        The weight as a { value, dp } pair whose two parts are strings: 1.5 is { "value": "15", "dp": "1" }.

      • unitstringrequired
        • One of: "lb", "kg"
Change a lineupdate

Changes a line. payload is the same body as Update a line item: send only what changes.

  • actionstringrequired
    • Always "update"
  • bidstringrequired

    Your own id for this operation, unique in the request. An error names it.

  • cart_item_idstringrequired

    The line's id (a hash id) from the order's line items. It must be a line of this order. (Its orditm_ unique key is also accepted, but no API answer shows it.)

  • payloadobjectrequired

    Send only what changes. Each object you send (product, pricing, quantity, job, weight) must carry its type, and product.type and pricing.type must stay the line's own. Fields you leave out keep their value.

    Any of, picked by product.type:

    Catalog productdb_catalog

    Change a product from a supplier catalog (one size and color).

    • productobject

      What the line is. type picks the kind of line and can't change later.

      Child fields (2)
      • typestringrequired
        • Always "db_catalog"
      • Child fields (1)
        • Extra text shown under the line, for example a note about the color.

    • jobobject

      Which job of this order the line belongs to. Decoration prices and quantity breaks count every line on a job, so put all sizes of a product on the same job.

      One of, picked by type:

      Linked to a joblinked

      The line belongs to one of this order's jobs and takes its decoration price.

      • typestringrequired
        • Always "linked"
      • idstringrequired

        The job's id, from the order's jobs. It must be a job of this same order.

      No jobstandalone

      The line has no job, so no decoration price.

      • typestringrequired
        • Always "standalone"
    • positioninteger

      Where the line sits on the order: lines are shown by ascending position. The web app spaces lines 100000 apart, which leaves room to insert between them. A value outside the allowed range is replaced by the next free position at the end.

    • pricingobject

      How the line is priced. YoPrint determines the product price in this order:

      1. Price override: if product.override is true, YoPrint uses product.total.
      2. Customer-supplied: if customer_supplied is true (product.properties.customer_supplied), the product price is 0.
      3. Marked-up cost: otherwise, YoPrint takes the supplier cost in catalog and applies the order's pricing group markup or a matching pricing rule.

      On an update, catalog is optional; send it to change the supplier cost.

      Child fields (4)
      • typestringrequired
        • Always "catalog_product_pricing"
      • catalogobject

        The supplier price the line starts from. When you send catalog, all four fields are required.

        Child fields (4)
        • datestring (date)required

          When the price was looked up, an ISO 8601 date such as 2026-11-03 (a date-time is accepted too).

        • providerstringrequired

          The supplier code, such as smr or ssa: the code the catalog item id starts with (smr for smr-10001), and the provider of that item in its product's attr_data. YoPrint stores it as sent and doesn't check it against your suppliers.

        • selectedstringrequired

          Which supplier price total represents:

          • piece: standard piece price
          • dozen: dozen price tier
          • case: case price tier
          • account: your account's negotiated price (your_price in catalog lookups)
          • sales: the supplier's sale price (sales_price in catalog lookups)
          • custom: a custom cost you entered manually
          • legacy: lines migrated from the old editor
          • One of: "piece", "dozen", "case", "account", "sales", "custom", "legacy"
        • totaldecimal pairrequired

          The supplier's cost for one unit.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
      • productobject

        Set your own product price for one unit with override: true and total. It replaces the marked-up catalog cost.

        Child fields (2)
        • overridebooleanrequired

          true to use total as given; false to let YoPrint work it out.

        • totaldecimal pair

          The amount for one unit, as a { value, dp } pair. Up to 6 decimal places are kept.

      • serviceobject

        The decoration price added to each unit. Leave it out, or send override: false, to use the job's decoration price per unit. Send override: true with total to set your own. Ignored when the line has no job (job.type standalone).

        Child fields (2)
        • overridebooleanrequired

          true to use total instead of the job's decoration price.

        • totaldecimal pair

          The decoration price for one unit. Required when override is true. Up to 6 decimal places.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
    • quantityobject

      How many units. type is always unit.

      Child fields (2)
      • typestringrequired
        • Always "unit"
      • totaldecimal pair

        The quantity as a { value, dp } pair: 24 is { "value": 24, "dp": 0 }. Up to 8 decimal places.

    • weightobject

      Optional, used for shipping. Leave it out to use the product's weight.

      One of, picked by type:

      Use the product's weightuse_system

      Take the weight from the product (in lb).

      • typestringrequired
        • Always "use_system"
      Set the weightmass

      Your own weight for one unit. unit is required; leave total out to keep the current weight.

      • typestringrequired
        • Always "mass"
      • unitstringrequired
        • One of: "lb", "kg"
      • totaldecimal pair

        The weight as a { value, dp } pair whose two parts are strings: 1.5 is { "value": "15", "dp": "1" }.

    Custom simple productuser_simple

    Change one of your own products that has no sizes or colors.

    • productobject

      What the line is. type picks the kind of line and can't change later.

      Child fields (2)
      • typestringrequired
        • Always "user_simple"
      • Child fields (1)
        • Extra text shown under the line, for example a note about the color.

    • jobobject

      Which job of this order the line belongs to. Decoration prices and quantity breaks count every line on a job, so put all sizes of a product on the same job.

      One of, picked by type:

      Linked to a joblinked

      The line belongs to one of this order's jobs and takes its decoration price.

      • typestringrequired
        • Always "linked"
      • idstringrequired

        The job's id, from the order's jobs. It must be a job of this same order.

      No jobstandalone

      The line has no job, so no decoration price.

      • typestringrequired
        • Always "standalone"
    • positioninteger

      Where the line sits on the order: lines are shown by ascending position. The web app spaces lines 100000 apart, which leaves room to insert between them. A value outside the allowed range is replaced by the next free position at the end.

    • pricingobject

      How the line is priced. YoPrint determines the product price in this order:

      1. Price override: if product.override is true, YoPrint uses product.total.
      2. Customer-supplied: if customer_supplied is true (product.properties.customer_supplied), the product price is 0.
      3. Product pricing: otherwise, YoPrint starts from product_cost.total (or the price from Products when omitted or 0) and applies any matching pricing rule.
      Child fields (4)
      • typestringrequired
        • Always "product_cost_service"
      • productobject

        Set your own product price for one unit with override: true and total.

        Child fields (2)
        • overridebooleanrequired

          true to use total as given; false to let YoPrint work it out.

        • totaldecimal pair

          The amount for one unit, as a { value, dp } pair. Up to 6 decimal places are kept.

      • Your cost for one unit. Optional: leave it out, or send a total of 0, to use the product's price from Products.

        Child fields (2)
        • overridebooleanrequired

          true when you set the cost yourself.

        • totaldecimal pairrequired

          The cost for one unit. 0 means "use the product's price".

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
      • serviceobject

        The decoration price added to each unit. Leave it out, or send override: false, to use the job's decoration price per unit. Send override: true with total to set your own. Ignored when the line has no job (job.type standalone).

        Child fields (2)
        • overridebooleanrequired

          true to use total instead of the job's decoration price.

        • totaldecimal pair

          The decoration price for one unit. Required when override is true. Up to 6 decimal places.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
    • quantityobject

      How many units. type is always unit.

      Child fields (2)
      • typestringrequired
        • Always "unit"
      • totaldecimal pair

        The quantity as a { value, dp } pair: 24 is { "value": 24, "dp": 0 }. Up to 8 decimal places.

    • weightobject

      Optional, used for shipping. Leave it out to use the product's weight.

      One of, picked by type:

      Use the product's weightuse_system

      Take the weight from the product (in lb).

      • typestringrequired
        • Always "use_system"
      Set the weightmass

      Your own weight for one unit. unit is required; leave total out to keep the current weight.

      • typestringrequired
        • Always "mass"
      • unitstringrequired
        • One of: "lb", "kg"
      • totaldecimal pair

        The weight as a { value, dp } pair whose two parts are strings: 1.5 is { "value": "15", "dp": "1" }.

    Custom variant productdb_variant

    Change one size and color of your own product.

    • productobject

      What the line is. type picks the kind of line and can't change later.

      Child fields (2)
      • typestringrequired
        • Always "db_variant"
      • Child fields (1)
        • Extra text shown under the line, for example a note about the color.

    • jobobject

      Which job of this order the line belongs to. Decoration prices and quantity breaks count every line on a job, so put all sizes of a product on the same job.

      One of, picked by type:

      Linked to a joblinked

      The line belongs to one of this order's jobs and takes its decoration price.

      • typestringrequired
        • Always "linked"
      • idstringrequired

        The job's id, from the order's jobs. It must be a job of this same order.

      No jobstandalone

      The line has no job, so no decoration price.

      • typestringrequired
        • Always "standalone"
    • positioninteger

      Where the line sits on the order: lines are shown by ascending position. The web app spaces lines 100000 apart, which leaves room to insert between them. A value outside the allowed range is replaced by the next free position at the end.

    • pricingobject

      How the line is priced. YoPrint determines the product price in this order:

      1. Price override: if product.override is true, YoPrint uses product.total.
      2. Customer-supplied: if customer_supplied is true (product.properties.customer_supplied), the product price is 0.
      3. Product pricing: otherwise, YoPrint starts from product_cost.total (or the price from Products when omitted or 0) and applies any matching pricing rule.
      Child fields (4)
      • typestringrequired
        • Always "product_cost_service"
      • productobject

        Set your own product price for one unit with override: true and total.

        Child fields (2)
        • overridebooleanrequired

          true to use total as given; false to let YoPrint work it out.

        • totaldecimal pair

          The amount for one unit, as a { value, dp } pair. Up to 6 decimal places are kept.

      • Your cost for one unit. Optional: leave it out, or send a total of 0, to use the product's price from Products.

        Child fields (2)
        • overridebooleanrequired

          true when you set the cost yourself.

        • totaldecimal pairrequired

          The cost for one unit. 0 means "use the product's price".

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
      • serviceobject

        The decoration price added to each unit. Leave it out, or send override: false, to use the job's decoration price per unit. Send override: true with total to set your own. Ignored when the line has no job (job.type standalone).

        Child fields (2)
        • overridebooleanrequired

          true to use total instead of the job's decoration price.

        • totaldecimal pair

          The decoration price for one unit. Required when override is true. Up to 6 decimal places.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
    • quantityobject

      How many units. type is always unit.

      Child fields (2)
      • typestringrequired
        • Always "unit"
      • totaldecimal pair

        The quantity as a { value, dp } pair: 24 is { "value": 24, "dp": 0 }. Up to 8 decimal places.

    • weightobject

      Optional, used for shipping. Leave it out to use the product's weight.

      One of, picked by type:

      Use the product's weightuse_system

      Take the weight from the product (in lb).

      • typestringrequired
        • Always "use_system"
      Set the weightmass

      Your own weight for one unit. unit is required; leave total out to keep the current weight.

      • typestringrequired
        • Always "mass"
      • unitstringrequired
        • One of: "lb", "kg"
      • totaldecimal pair

        The weight as a { value, dp } pair whose two parts are strings: 1.5 is { "value": "15", "dp": "1" }.

    Custom line itemcustom

    Change a one-off line with a name and a price, not linked to a product.

    • productobject

      What the line is. type picks the kind of line and can't change later.

      Child fields (2)
      • typestringrequired
        • Always "custom"
      • Child fields (2)
        • Extra text shown under the line, for example a note about the color.

        • namestring

          The line's name, as the customer sees it.

    • jobobject

      Which job of this order the line belongs to. Decoration prices and quantity breaks count every line on a job, so put all sizes of a product on the same job.

      One of, picked by type:

      Linked to a joblinked

      The line belongs to one of this order's jobs and takes its decoration price.

      • typestringrequired
        • Always "linked"
      • idstringrequired

        The job's id, from the order's jobs. It must be a job of this same order.

      No jobstandalone

      The line has no job, so no decoration price.

      • typestringrequired
        • Always "standalone"
    • positioninteger

      Where the line sits on the order: lines are shown by ascending position. The web app spaces lines 100000 apart, which leaves room to insert between them. A value outside the allowed range is replaced by the next free position at the end.

    • pricingobject

      How the line is priced. Send the unit price in product.total with override: true.

      Child fields (4)
      • typestringrequired
        • Always "custom_product"
      • productobject

        The product price for one unit. With override: true (what the web app sends) the line uses total. With override false or left out, YoPrint starts from product_cost.total (or total when no cost is set) and applies any matching pricing rule.

        Child fields (2)
        • totaldecimal pairrequired

          The price for one unit. Up to 6 decimal places are kept.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
        • overrideboolean

          true to use total as the price.

      • Optional: your cost for one unit, used for profit and margin.

        Child fields (1)
        • totaldecimal pairrequired

          Your cost for one unit.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
      • serviceobject

        The decoration price added to each unit. Leave it out, or send override: false, to use the job's decoration price per unit. Send override: true with total to set your own. Ignored when the line has no job (job.type standalone).

        Child fields (2)
        • overridebooleanrequired

          true to use total instead of the job's decoration price.

        • totaldecimal pair

          The decoration price for one unit. Required when override is true. Up to 6 decimal places.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
    • quantityobject

      How many units. type is always unit.

      Child fields (2)
      • typestringrequired
        • Always "unit"
      • totaldecimal pair

        The quantity as a { value, dp } pair: 24 is { "value": 24, "dp": 0 }. Up to 8 decimal places.

    • weightobject

      Optional, used for shipping.

      Child fields (3)
      • typestringrequired
        • Always "mass"
      • unitstringrequired
        • One of: "lb", "kg"
      • totaldecimal pair

        The weight as a { value, dp } pair whose two parts are strings: 1.5 is { "value": "15", "dp": "1" }.

    Fee line itemfee

    Change a fee, such as a rush or setup fee.

    • productobject

      What the line is. type picks the kind of line and can't change later.

      Child fields (2)
      • typestringrequired
        • Always "fee"
      • Child fields (2)
        • Extra text shown under the fee, for example what it covers.

        • namestring

          The fee's name, for example "Rush fee".

    • jobobject

      Which job of this order the line belongs to. Decoration prices and quantity breaks count every line on a job, so put all sizes of a product on the same job.

      One of, picked by type:

      Linked to a joblinked

      The line belongs to one of this order's jobs and takes its decoration price.

      • typestringrequired
        • Always "linked"
      • idstringrequired

        The job's id, from the order's jobs. It must be a job of this same order.

      No jobstandalone

      The line has no job, so no decoration price.

      • typestringrequired
        • Always "standalone"
    • positioninteger

      Where the line sits on the order: lines are shown by ascending position. The web app spaces lines 100000 apart, which leaves room to insert between them. A value outside the allowed range is replaced by the next free position at the end.

    • pricingobject

      The fee amount for one unit. Fees never take a decoration price.

      Child fields (2)
      • typestringrequired
        • Always "fee"
      • productobject
        Child fields (1)
        • totaldecimal pairrequired

          The fee for one unit, 0 or more.

          • { "value": 1250, "dp": 2 } is 12.50: value holds the digits, dp the decimal places. See Money and quantities.
    • quantityobject

      How many units. type is always unit.

      Child fields (2)
      • typestringrequired
        • Always "unit"
      • totaldecimal pair

        The quantity as a { value, dp } pair: 24 is { "value": 24, "dp": 0 }. Up to 8 decimal places.

    • weightobject

      Optional, used for shipping. Leave it out for no weight.

      Child fields (3)
      • typestringrequired
        • Always "mass"
      • unitstringrequired
        • One of: "lb", "kg"
      • totaldecimal pair

        The weight as a { value, dp } pair whose two parts are strings: 1.5 is { "value": "15", "dp": "1" }.

Delete a linedelete

Deletes a line. A line that is already deleted is skipped without an error.

  • actionstringrequired
    • Always "delete"
  • bidstringrequired

    Your own id for this operation, unique in the request. An error names it.

  • cart_item_idstringrequired

    The line's id (a hash id) from the order's line items. It must be a line of this order. (Its orditm_ unique key is also accepted, but no API answer shows it.)

More examples (1)

Add two sizes of a variant product to one job

curl
curl -X POST 'https://secure.yoprint.com/v2/api/store/your-team/v2/sales_order/V4keXwwxMQyXw7/order_item/bulk' \  -H 'Authorization: Bearer YOUR_API_KEY' \  -H 'Accept: application/json' \  -H 'X-Yoprint-Decimal-Format: exact-v1' \  -H 'Content-Type: application/json' \  -d '[    {      "action": "create",      "bid": "b1",      "payload": {        "job": {          "id": "K6iF8n29iwOZnj",          "type": "linked"        },        "position": 100000,        "pricing": {          "product": {            "override": false          },          "service": {            "override": false          },          "type": "product_cost_service"        },        "product": {          "properties": {            "customer_supplied": false,            "id": "TGbMAohWcL31V0"          },          "type": "db_variant"        },        "quantity": {          "total": {            "dp": 0,            "value": 12          },          "type": "unit"        }      }    },    {      "action": "create",      "bid": "b2",      "payload": {        "job": {          "id": "K6iF8n29iwOZnj",          "type": "linked"        },        "position": 200000,        "pricing": {          "product": {            "override": false          },          "service": {            "override": false          },          "type": "product_cost_service"        },        "product": {          "properties": {            "customer_supplied": false,            "id": "ZrdJ9i78QVmdhr"          },          "type": "db_variant"        },        "quantity": {          "total": {            "dp": 0,            "value": 18          },          "type": "unit"        }      }    }  ]'

Response

200Successful response.

  • dataarray of objectsrequired

    Every line of the order after the save.

    Fields of each item (6)
      • Always "order_item"
    • Ignore this field here: always CREATED in this answer.

    • bidstring | null

      Your bid for a line this request created; null for other lines.

    • Ignore this field here: always true on every row. Read the top-level has_changes next to data.

    • itemobject

      One line. It has the request's groups (product, pricing, quantity, job, weight, position) as saved, with the prices YoPrint worked out, and the same values again in _meta. A few groups differ from the request: the catalog cost comes back as pricing.catalog.cost with its date as a date-time, and a linked job also has its unique_key and scoped_id (JOB-1001). Each group's _meta.editable_fields_on_update lists the request paths an update accepts for that group (pricing.type is listed, but it must stay the line's own).

      Child fields (16)
      • _metaobject

        The line's own values again (id, type, order_id, unit_price, subtotal and so on). Always an object.

      • idstring
      • inventory_statusstring | null

        Stock status of the line.

      • jobobject
      • lock_versioninteger | null

        The line's own lock version (a microsecond timestamp).

      • order_idstring
      • The order's unique_key. The line's own unique_key is not in the answer: use id.

      • positioninteger
      • pricingobject
      • The pricing rule that set the line's product price, or null when no rule did. List the line items, Get one line item and the bulk save answer with the full summary below. Other answers carry only type, the two ids and the two totals.

        Child fields (12)
        • afterstring

          Full summary only: the price after the rule, as a decimal string.

        • after_totaldecimal pair

          The product price per unit after the rule. 6 decimal places. A decimal pair: the amount is value ÷ 10^dp ({ "value": 1250, "dp": 2 } is 12.50). Read dp every time: it can differ between fields and records.

        • basestring

          Full summary only: that starting price, as a decimal string with at least 2 decimal places.

        • base_typestring

          Full summary only: what the rule started from: the supplier price for catalog lines, the product's own price for other lines.

          • One of: "supplier_price", "base_price"
        • normal_pricestring | null

          Full summary only: what the line would cost with no rule. For catalog lines the supplier price plus the group's catalog markup as it is now; otherwise the same as base.

        • original_totaldecimal pair

          The product price per unit before the rule. 6 decimal places. A decimal pair: the amount is value ÷ 10^dp ({ "value": 1250, "dp": 2 } is 12.50). Read dp every time: it can differ between fields and records.

        • pricing_group_idstring | null

          The pricing group whose rule applied.

        • pricing_group_namestring | null

          Full summary only: the group's name now.

        • pricing_group_removedboolean | null

          Full summary only: true when the group was removed since. The line keeps its price.

        • pricing_rule_idstring | null

          The rule that applied.

        • ruleobject | null

          Full summary only: the rule as the group holds it now, with its current name and position (1 is the first rule checked). Null when the rule no longer exists.

          Child fields (3)
        • typestring

          product on a line.

      • productobject
      • quantityobject

        The quantity, trailing zeros dropped: 10 is { "value": 10, "dp": 0 }.

      • subtotaldecimal pair

        unit_price times the quantity. 4 decimal places: 125.00 is { "value": 1250000, "dp": 4 }. A decimal pair: the amount is value ÷ 10^dp ({ "value": 1250, "dp": 2 } is 12.50). Read dp every time: it can differ between fields and records.

      • trashedboolean

        true when the line was deleted.

      • typestring

        The kind of line: db_catalog, user_simple, db_variant, custom or fee.

      • unit_pricedecimal pair

        The price of one unit: the product price plus the decoration price. 6 decimal places: 12.50 is { "value": 12500000, "dp": 6 }. A decimal pair: the amount is value ÷ 10^dp ({ "value": 1250, "dp": 2 } is 12.50). Read dp every time: it can differ between fields and records.

    • The order's lock versions after this call. Each is a whole number (a microsecond timestamp) that changes on every save, or null.

      Child fields (1)
  • has_changesbooleanrequired

    false when the batch changed nothing (with the save intent).

  • statusintegerrequired
  • successbooleanrequired

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, with unauthorized or user_is_not_authorized.

    When
    The API key's role can't edit this order (user_is_not_authorized).
    Fix
    Ask the team owner for sales order edit permission, or assign the user 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 order or line does not exist in this team: error.code is null and error.message says "No query results for …".
    Fix
    Check the id.
  • 422The request was refused and changed nothing. validation_failed lists what to fix in error.fields; bulk_validation_payload_failed names the failing item's bid and its fields.

    When
    One operation is invalid (bulk_validation_payload_failed, with error.bid and error.fields).
    Fix
    Fix the operation named by bid and resend the whole batch.
    When
    cart_item_id is not a line of this order: validation_error "Order item not found".
    Fix
    Use line ids from this order.
    When
    A required field is missing, a type value is unknown, or a { value, dp } pair is malformed (for example sending {"value": 12.5, "dp": 1} instead of {"value": 125, "dp": 1}: value must be an integer).
    Fix
    Read error.fields; send whole numbers in value and the decimal places in dp (for example {"value": 1250, "dp": 2} for 12.50).
    When
    The product, variant or catalog item id is not found. This error has no envelope: the body is {"message": "user_simple: Simple Product not found:48213"}, where the number is YoPrint's internal number for the id you sent (db_variant: Variant Product not found:… the same way; db_catalog: Catalog Product not found:smr-10001 repeats the catalog id).
    Fix
    Use an id from Products, or a catalog item id.
    When
    job.id is not a job of this order: "This job is no longer available. Choose a job from this order and save again."
    Fix
    Use a job id from this order's jobs.
    When
    The job's decoration setup needs repair: "Review this job’s services before changing quantities or adding, removing or moving items." (validation_error, with error.fields.job.id, and error.context.reason job_service_repair_required with error.context.job_id and job_label).
    Fix
    Fix the job's services in the web app, then retry.
    When
    The product, or its size or color, is phased out or deleted (product_phased_out, product_deleted, variant_phased_out, variant_deleted).
    Fix
    Resume it in Products, or choose another product.
    When
    A price, quantity or calculated total is out of range (amount_out_of_range).
    Fix
    Check the amount and its decimal places.

Notes

  • Use this to add a product's whole size run in one save, so quantity breaks are worked out once.
  • Resending the same batch adds the lines again: creates are not deduplicated by bid.
  • Deleting a line that is already deleted counts as no change.