{"components":{"examples":{"action_not_allowed":{"summary":"The record's state does not allow this action","value":{"error":{"code":"action_not_allowed","message":null},"status":500,"success":false}},"api_access_not_in_plan":{"summary":"Your team's plan doesn't include API access","value":{"error":{"code":"api_access_not_in_plan","message":"Your team's plan doesn't include API access. Upgrade to the Pro plan or higher in YoPrint, under Billing, to use the API, webhooks and Zapier."},"status":403,"success":false}},"bulk_item_invalid":{"summary":"One item of the bulk request is invalid","value":{"error":{"bid":"line-1","code":"bulk_validation_payload_failed","field_reasons":{"quantity":{"reason":"required"}},"fields":{"quantity":["The quantity field is required."]},"message":null},"status":422,"success":false}},"business_rule":{"summary":"A business rule refused the change","value":{"error":{"code":"validation_error","message":"Cannot update external object from API."},"status":422,"success":false}},"customer_address_external_mutation":{"summary":"External customer mutation blocked","value":{"error":{"code":"validation_error","message":"External customers are read-only. Manage changes from Shopify."},"status":422,"success":false}},"customer_address_validation":{"summary":"Customer address validation failed","value":{"error":{"code":"validation_failed","field_reasons":{"role":{"reason":"required"}},"fields":{"role":["The role field is required."]},"message":null},"status":422,"success":false}},"feature_not_in_plan":{"summary":"The team's plan does not include this feature","value":{"message":"This feature is not available to your team's plan."}},"image_not_allowed":{"summary":"Image refused: over a size limit","value":{"error":{"code":"image_not_allowed","message":"Mockups can be up to 120 megapixels. This image is 23,989 × 14,476 px (347.3 megapixels)."},"status":422,"success":false}},"insufficient_permission":{"summary":"Your role lacks the permission this operation needs","value":{"message":"Insufficient Permission"}},"mockup_type_not_allowed":{"summary":"Mockup refused: not an image a preview can be made of","value":{"error":{"code":"mockup_type_not_allowed","message":"Mockups must be images: PNG, JPG, GIF, TIFF, BMP, WebP, SVG, HEIC or AVIF. Add other files as production files."},"status":422,"success":false}},"page_not_found":{"summary":"Unknown team, not a member, or an id that is not one of this team's","value":{"error":{"code":"page_not_found","message":null},"status":404,"success":false}},"payment_credit_validation":{"summary":"Payment credit validation failed","value":{"error":{"code":"validation_failed","field_reasons":{"amount":{"reason":"required"}},"fields":{"amount":["The amount field is required."]},"message":null},"status":422,"success":false}},"payment_insufficient_order_balance":{"summary":"Payment mutation blocked by insufficient order balance","value":{"error":{"code":"Insufficient Order Balance","message":null},"status":422,"success":false}},"payment_link_action_not_allowed":{"summary":"Payment link creation blocked by order state","value":{"error":{"code":"Action Not Allow","message":null},"status":422,"success":false}},"payment_link_validation":{"summary":"Payment link create validation failed","value":{"error":{"code":"validation_failed","field_reasons":{"unallocated_transactions":{"reason":"required"}},"fields":{"unallocated_transactions":["The unallocated transactions field is required."]},"message":null},"status":422,"success":false}},"record_not_found":{"summary":"No record with this id","value":{"error":{"code":null,"message":"No query results for the requested record."},"status":404,"success":false}},"server_error":{"summary":"Something failed inside YoPrint","value":{"message":"Server Error"}},"unauthenticated":{"summary":"No valid credential","value":{"error":{"code":"unauthenticated","message":null},"status":401,"success":false}},"unauthorized":{"summary":"A rule for this record does not allow it","value":{"error":{"code":"unauthorized","message":null},"status":403,"success":false}},"user_is_not_authorized":{"summary":"Your role does not allow this action","value":{"error":{"code":"user_is_not_authorized","message":"User is not authorized to perform the action"},"status":403,"success":false}},"validation_failed":{"summary":"Fields to fix","value":{"error":{"code":"validation_failed","field_reasons":{"quantity":{"reason":"required"}},"fields":{"quantity":["The quantity field is required."]},"message":null},"status":422,"success":false}}},"responses":{"BulkValidationPayloadResponse":{"content":{"application/json":{"examples":{"bulk_item_invalid":{"$ref":"#/components/examples/bulk_item_invalid"},"validation_failed":{"$ref":"#/components/examples/validation_failed"}},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"The 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`."},"CustomerAddressMutationValidationResponse":{"content":{"application/json":{"examples":{"customer_address_external_mutation":{"$ref":"#/components/examples/customer_address_external_mutation"},"customer_address_validation":{"$ref":"#/components/examples/customer_address_validation"}},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Validation failed or external Shopify customers are read-only from this API."},"FeatureGatedValidationErrorResponse":{"content":{"application/json":{"examples":{"feature_not_in_plan":{"$ref":"#/components/examples/feature_not_in_plan"},"validation_failed":{"$ref":"#/components/examples/validation_failed"}},"schema":{"$ref":"#/components/schemas/ErrorOrMessageResponse"}}},"description":"The request was refused and changed nothing: `validation_failed` lists what to fix in `error.fields`, other codes name a business rule. When the team's plan does not include the feature, the body is only `{\"message\": \"This feature is not available to your team's plan.\"}`."},"MediaUploadValidationErrorResponse":{"content":{"application/json":{"examples":{"image_not_allowed":{"$ref":"#/components/examples/image_not_allowed"},"mockup_type_not_allowed":{"$ref":"#/components/examples/mockup_type_not_allowed"},"validation_failed":{"$ref":"#/components/examples/validation_failed"}},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Validation failed, or the image was refused by the media rules: a mockup that is not an image a preview can be made of (`mockup_type_not_allowed`), or an image over a size limit (`image_not_allowed`), or a file that is a web page, a script or a program (`validation_failed` on `media`, or `upload_not_allowed`: \"This type of file cannot be uploaded.\"); `error.message` is one sentence naming the limit."},"NotFoundResponse":{"content":{"application/json":{"examples":{"page_not_found":{"$ref":"#/components/examples/page_not_found"},"record_not_found":{"$ref":"#/components/examples/record_not_found"}},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not 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."},"PaymentMutationUnprocessableEntityResponse":{"content":{"application/json":{"examples":{"payment_credit_validation":{"$ref":"#/components/examples/payment_credit_validation"},"payment_insufficient_order_balance":{"$ref":"#/components/examples/payment_insufficient_order_balance"},"payment_link_action_not_allowed":{"$ref":"#/components/examples/payment_link_action_not_allowed"},"payment_link_validation":{"$ref":"#/components/examples/payment_link_validation"}},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Validation failed or the payment mutation was rejected by business rules."},"PublicForbiddenResponse":{"content":{"application/json":{"examples":{"api_access_not_in_plan":{"$ref":"#/components/examples/api_access_not_in_plan"},"insufficient_permission":{"$ref":"#/components/examples/insufficient_permission"},"unauthorized":{"$ref":"#/components/examples/unauthorized"},"user_is_not_authorized":{"$ref":"#/components/examples/user_is_not_authorized"}},"schema":{"$ref":"#/components/schemas/ErrorOrMessageResponse"}}},"description":"You 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`."},"ServerErrorResponse":{"content":{"application/json":{"examples":{"action_not_allowed":{"$ref":"#/components/examples/action_not_allowed"},"server_error":{"$ref":"#/components/examples/server_error"}},"schema":{"$ref":"#/components/schemas/ErrorOrMessageResponse"}}},"description":"A business rule refused the request (see the operation's errors), or something failed inside YoPrint. Refusals use the error envelope with a code such as `action_not_allowed`; an unexpected failure answers `{\"message\": \"Server Error\"}`. Repeating a refusal gets the same answer; after an unexpected failure, read the record back before you retry a change."},"UnauthenticatedResponse":{"content":{"application/json":{"examples":{"unauthenticated":{"$ref":"#/components/examples/unauthenticated"}},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"The API key is missing or wrong (`unauthenticated`)."},"ValidationErrorResponse":{"content":{"application/json":{"examples":{"business_rule":{"$ref":"#/components/examples/business_rule"},"validation_failed":{"$ref":"#/components/examples/validation_failed"}},"schema":{"$ref":"#/components/schemas/ErrorOrMessageResponse"}}},"description":"The request was refused and changed nothing. `validation_failed` lists what to fix in `error.fields`; other codes name a business rule, explained in `error.message`. A few checks answer with only `{\"message\": \"...\"}`. An operation that calls another service (a payment provider, a carrier, an accounting app) can answer `connect_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."}},"schemas":{"AddLine":{"description":"Adds a line. `payload` is the same body as Add a line item.","properties":{"action":{"const":"create","type":"string"},"bid":{"description":"Your own id for this operation, unique in the request. The new line comes back with this `bid`, and an error names it.","type":"string"},"payload":{"description":"Pick the branch by `product.type`.","oneOf":[{"description":"Add a product from a supplier catalog (one size and color).","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. YoPrint determines the product price in this order:\n\n1. Price override: if `product.override` is true, YoPrint uses `product.total`.\n2. Customer-supplied: if `customer_supplied` is true (`product.properties.customer_supplied`), the product price is 0.\n3. Marked-up cost: otherwise, YoPrint takes the supplier cost in `catalog` and applies the order's pricing group markup or a matching pricing rule.\n\nA 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.\").","properties":{"catalog":{"description":"The supplier price the line starts from. When you send `catalog`, all four fields are required.","properties":{"date":{"description":"When the price was looked up, an ISO 8601 date such as 2026-11-03 (a date-time is accepted too).","format":"date","type":"string"},"provider":{"description":"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.","type":"string"},"selected":{"description":"Which supplier price `total` represents:\n\n- `piece`: standard piece price\n- `dozen`: dozen price tier\n- `case`: case price tier\n- `account`: your account's negotiated price (`your_price` in catalog lookups)\n- `sales`: the supplier's sale price (`sales_price` in catalog lookups)\n- `custom`: a custom cost you entered manually\n- `legacy`: lines migrated from the old editor","enum":["piece","dozen","case","account","sales","custom","legacy"],"type":"string"},"total":{"description":"The supplier's cost for one unit.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["provider","selected","date","total"],"type":"object"},"product":{"description":"Set your own product price for one unit with `override: true` and `total`. It replaces the marked-up catalog cost.","properties":{"override":{"description":"true to use `total` as given; false to let YoPrint work it out.","type":"boolean"},"total":{"description":"The amount for one unit, as a `{ value, dp }` pair. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"catalog_product_pricing","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"customer_supplied":{"description":"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.","type":"boolean"},"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"},"id":{"description":"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`.","type":"string"}},"required":["id","customer_supplied"],"type":"object"},"type":{"const":"db_catalog","type":"string"}},"required":["type","properties"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type","total"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out to use the product's weight.","discriminator":{"mapping":{"mass":"#/components/schemas/WeightMassCreate","use_system":"#/components/schemas/WeightUseSystem"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/WeightUseSystem"},{"$ref":"#/components/schemas/WeightMassCreate"}],"title":"Weight"}},"required":["product","pricing","quantity","job","position"],"title":"Catalog product","type":"object"},{"description":"Add one of your own products that has no sizes or colors.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. YoPrint determines the product price in this order:\n\n1. Price override: if `product.override` is true, YoPrint uses `product.total`.\n2. Customer-supplied: if `customer_supplied` is true (`product.properties.customer_supplied`), the product price is 0.\n3. Product pricing: otherwise, YoPrint starts from `product_cost.total` (or the price from Products when omitted or 0) and applies any matching pricing rule.","properties":{"product":{"description":"Set your own product price for one unit with `override: true` and `total`.","properties":{"override":{"description":"true to use `total` as given; false to let YoPrint work it out.","type":"boolean"},"total":{"description":"The amount for one unit, as a `{ value, dp }` pair. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"product_cost":{"description":"Your cost for one unit. Optional: leave it out, or send a total of 0, to use the product's price from Products.","properties":{"override":{"description":"true when you set the cost yourself.","type":"boolean"},"total":{"description":"The cost for one unit. 0 means \"use the product's price\".","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override","total"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"product_cost_service","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"customer_supplied":{"description":"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.","type":"boolean"},"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"},"id":{"description":"The product's `id` from Products.","type":"string"}},"required":["id","customer_supplied"],"type":"object"},"type":{"const":"user_simple","type":"string"}},"required":["type","properties"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type","total"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out to use the product's weight.","discriminator":{"mapping":{"mass":"#/components/schemas/WeightMassCreate","use_system":"#/components/schemas/WeightUseSystem"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/WeightUseSystem"},{"$ref":"#/components/schemas/WeightMassCreate"}],"title":"Weight"}},"required":["product","pricing","quantity","job","position"],"title":"Custom simple product","type":"object"},{"description":"Add one size and color of your own product.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. YoPrint determines the product price in this order:\n\n1. Price override: if `product.override` is true, YoPrint uses `product.total`.\n2. Customer-supplied: if `customer_supplied` is true (`product.properties.customer_supplied`), the product price is 0.\n3. Product pricing: otherwise, YoPrint starts from `product_cost.total` (or the price from Products when omitted or 0) and applies any matching pricing rule.","properties":{"product":{"description":"Set your own product price for one unit with `override: true` and `total`.","properties":{"override":{"description":"true to use `total` as given; false to let YoPrint work it out.","type":"boolean"},"total":{"description":"The amount for one unit, as a `{ value, dp }` pair. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"product_cost":{"description":"Your cost for one unit. Optional: leave it out, or send a total of 0, to use the product's price from Products.","properties":{"override":{"description":"true when you set the cost yourself.","type":"boolean"},"total":{"description":"The cost for one unit. 0 means \"use the product's price\".","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override","total"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"product_cost_service","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"customer_supplied":{"description":"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.","type":"boolean"},"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"},"id":{"description":"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.","type":"string"}},"required":["id","customer_supplied"],"type":"object"},"type":{"const":"db_variant","type":"string"}},"required":["type","properties"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type","total"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out to use the product's weight.","discriminator":{"mapping":{"mass":"#/components/schemas/WeightMassCreate","use_system":"#/components/schemas/WeightUseSystem"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/WeightUseSystem"},{"$ref":"#/components/schemas/WeightMassCreate"}],"title":"Weight"}},"required":["product","pricing","quantity","job","position"],"title":"Custom variant product","type":"object"},{"description":"Add a one-off line with a name and a price, not linked to a product.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. Send the unit price in `product.total` with `override: true`.","properties":{"product":{"description":"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.","properties":{"override":{"description":"true to use `total` as the price.","type":"boolean"},"total":{"description":"The price for one unit. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"product_cost":{"description":"Optional: your cost for one unit, used for profit and margin.","properties":{"total":{"description":"Your cost for one unit.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"custom_product","type":"string"}},"required":["type","product"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"customer_supplied":{"description":"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.","type":"boolean"},"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"},"name":{"description":"The line's name, as the customer sees it.","type":"string"}},"required":["name","customer_supplied"],"type":"object"},"type":{"const":"custom","type":"string"}},"required":["type","properties"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type","total"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out for 0 lb.","oneOf":[{"description":"Your own weight for one unit.","properties":{"total":{"description":"The weight as a `{ value, dp }` pair whose two parts are strings: 1.5 is `{ \"value\": \"15\", \"dp\": \"1\" }`.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, as a string.","type":"string"},"value":{"description":"The weight without its decimal point, as a string of digits.","type":"string"}},"required":["value","dp"],"type":"object"},"type":{"const":"mass","type":"string"},"unit":{"enum":["lb","kg"],"type":"string"}},"required":["type","unit","total"],"title":"Set the weight","type":"object"}],"title":"Weight"}},"required":["product","pricing","quantity","job","position"],"title":"Custom line item","type":"object"},{"description":"Add a fee, such as a rush or setup fee.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"The fee amount for one unit. Fees never take a decoration price.","properties":{"product":{"properties":{"total":{"description":"The fee for one unit, 0 or more.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"type":{"const":"fee","type":"string"}},"required":["type","product"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"description":{"description":"Extra text shown under the fee, for example what it covers.","type":"string"},"name":{"description":"The fee's name, for example \"Rush fee\".","type":"string"}},"required":["name"],"type":"object"},"type":{"const":"fee","type":"string"}},"required":["type","properties"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type","total"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out for no weight.","oneOf":[{"description":"Your own weight for one unit.","properties":{"total":{"description":"The weight as a `{ value, dp }` pair whose two parts are strings: 1.5 is `{ \"value\": \"15\", \"dp\": \"1\" }`.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, as a string.","type":"string"},"value":{"description":"The weight without its decimal point, as a string of digits.","type":"string"}},"required":["value","dp"],"type":"object"},"type":{"const":"mass","type":"string"},"unit":{"enum":["lb","kg"],"type":"string"}},"required":["type","unit","total"],"title":"Set the weight","type":"object"}],"title":"Weight"}},"required":["product","pricing","quantity","job","position"],"title":"Fee line item","type":"object"}],"title":"What are you adding?","x-yoprint-discriminator":{"mapping":{"custom":"Custom line item","db_catalog":"Catalog product","db_variant":"Custom variant product","fee":"Fee line item","user_simple":"Custom simple product"},"propertyPath":"product.type"}}},"required":["bid","action","payload"],"title":"Add a line","type":"object"},"BigDecimalValue":{"description":"A decimal number as its digits and the count of them after the decimal point: `{ \"value\": 1250, \"dp\": 2 }` is 12.50.","properties":{"dp":{"description":"How many of the digits come after the decimal point.","example":2,"type":"integer"},"value":{"description":"The digits without the decimal point. An integer, unless it is too large for a JSON number (beyond 9007199254740991 either way) and you sent the header `X-Yoprint-Decimal-Format: exact-v1`: then a string of digits, and the answer carries the same header. Null when there is no amount. Work out the number with decimal arithmetic, not floating point.","example":50000,"oneOf":[{"title":"integer","type":"integer"},{"pattern":"^-?(0|[1-9][0-9]*)$","title":"string of digits","type":"string"},{"title":"null","type":"null"}]}},"required":["value","dp"],"title":"Decimal pair","type":"object"},"ChangeLine":{"description":"Changes a line. `payload` is the same body as Update a line item: send only what changes.","properties":{"action":{"const":"update","type":"string"},"bid":{"description":"Your own id for this operation, unique in the request. An error names it.","type":"string"},"cart_item_id":{"description":"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.)","type":"string"},"payload":{"anyOf":[{"description":"Change a product from a supplier catalog (one size and color).","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. YoPrint determines the product price in this order:\n\n1. Price override: if `product.override` is true, YoPrint uses `product.total`.\n2. Customer-supplied: if `customer_supplied` is true (`product.properties.customer_supplied`), the product price is 0.\n3. Marked-up cost: otherwise, YoPrint takes the supplier cost in `catalog` and applies the order's pricing group markup or a matching pricing rule.\n\nOn an update, `catalog` is optional; send it to change the supplier cost.","properties":{"catalog":{"description":"The supplier price the line starts from. When you send `catalog`, all four fields are required.","properties":{"date":{"description":"When the price was looked up, an ISO 8601 date such as 2026-11-03 (a date-time is accepted too).","format":"date","type":"string"},"provider":{"description":"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.","type":"string"},"selected":{"description":"Which supplier price `total` represents:\n\n- `piece`: standard piece price\n- `dozen`: dozen price tier\n- `case`: case price tier\n- `account`: your account's negotiated price (`your_price` in catalog lookups)\n- `sales`: the supplier's sale price (`sales_price` in catalog lookups)\n- `custom`: a custom cost you entered manually\n- `legacy`: lines migrated from the old editor","enum":["piece","dozen","case","account","sales","custom","legacy"],"type":"string"},"total":{"description":"The supplier's cost for one unit.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["provider","selected","date","total"],"type":"object"},"product":{"description":"Set your own product price for one unit with `override: true` and `total`. It replaces the marked-up catalog cost.","properties":{"override":{"description":"true to use `total` as given; false to let YoPrint work it out.","type":"boolean"},"total":{"description":"The amount for one unit, as a `{ value, dp }` pair. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"catalog_product_pricing","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"}},"type":"object"},"type":{"const":"db_catalog","type":"string"}},"required":["type"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out to use the product's weight.","discriminator":{"mapping":{"mass":"#/components/schemas/WeightMassUpdate","use_system":"#/components/schemas/WeightUseSystem"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/WeightUseSystem"},{"$ref":"#/components/schemas/WeightMassUpdate"}],"title":"Weight"}},"title":"Catalog product","type":"object"},{"description":"Change one of your own products that has no sizes or colors.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. YoPrint determines the product price in this order:\n\n1. Price override: if `product.override` is true, YoPrint uses `product.total`.\n2. Customer-supplied: if `customer_supplied` is true (`product.properties.customer_supplied`), the product price is 0.\n3. Product pricing: otherwise, YoPrint starts from `product_cost.total` (or the price from Products when omitted or 0) and applies any matching pricing rule.","properties":{"product":{"description":"Set your own product price for one unit with `override: true` and `total`.","properties":{"override":{"description":"true to use `total` as given; false to let YoPrint work it out.","type":"boolean"},"total":{"description":"The amount for one unit, as a `{ value, dp }` pair. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"product_cost":{"description":"Your cost for one unit. Optional: leave it out, or send a total of 0, to use the product's price from Products.","properties":{"override":{"description":"true when you set the cost yourself.","type":"boolean"},"total":{"description":"The cost for one unit. 0 means \"use the product's price\".","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override","total"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"product_cost_service","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"}},"type":"object"},"type":{"const":"user_simple","type":"string"}},"required":["type"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out to use the product's weight.","discriminator":{"mapping":{"mass":"#/components/schemas/WeightMassUpdate","use_system":"#/components/schemas/WeightUseSystem"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/WeightUseSystem"},{"$ref":"#/components/schemas/WeightMassUpdate"}],"title":"Weight"}},"title":"Custom simple product","type":"object"},{"description":"Change one size and color of your own product.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. YoPrint determines the product price in this order:\n\n1. Price override: if `product.override` is true, YoPrint uses `product.total`.\n2. Customer-supplied: if `customer_supplied` is true (`product.properties.customer_supplied`), the product price is 0.\n3. Product pricing: otherwise, YoPrint starts from `product_cost.total` (or the price from Products when omitted or 0) and applies any matching pricing rule.","properties":{"product":{"description":"Set your own product price for one unit with `override: true` and `total`.","properties":{"override":{"description":"true to use `total` as given; false to let YoPrint work it out.","type":"boolean"},"total":{"description":"The amount for one unit, as a `{ value, dp }` pair. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"product_cost":{"description":"Your cost for one unit. Optional: leave it out, or send a total of 0, to use the product's price from Products.","properties":{"override":{"description":"true when you set the cost yourself.","type":"boolean"},"total":{"description":"The cost for one unit. 0 means \"use the product's price\".","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override","total"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"product_cost_service","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"}},"type":"object"},"type":{"const":"db_variant","type":"string"}},"required":["type"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out to use the product's weight.","discriminator":{"mapping":{"mass":"#/components/schemas/WeightMassUpdate","use_system":"#/components/schemas/WeightUseSystem"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/WeightUseSystem"},{"$ref":"#/components/schemas/WeightMassUpdate"}],"title":"Weight"}},"title":"Custom variant product","type":"object"},{"description":"Change a one-off line with a name and a price, not linked to a product.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. Send the unit price in `product.total` with `override: true`.","properties":{"product":{"description":"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.","properties":{"override":{"description":"true to use `total` as the price.","type":"boolean"},"total":{"description":"The price for one unit. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"product_cost":{"description":"Optional: your cost for one unit, used for profit and margin.","properties":{"total":{"description":"Your cost for one unit.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"custom_product","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"},"name":{"description":"The line's name, as the customer sees it.","type":"string"}},"type":"object"},"type":{"const":"custom","type":"string"}},"required":["type"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type"],"type":"object"},"weight":{"description":"Optional, used for shipping.","oneOf":[{"description":"Your own weight for one unit. `unit` is required; leave `total` out to keep the current weight.","properties":{"total":{"description":"The weight as a `{ value, dp }` pair whose two parts are strings: 1.5 is `{ \"value\": \"15\", \"dp\": \"1\" }`.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, as a string.","type":"string"},"value":{"description":"The weight without its decimal point, as a string of digits.","type":"string"}},"required":["value","dp"],"type":"object"},"type":{"const":"mass","type":"string"},"unit":{"enum":["lb","kg"],"type":"string"}},"required":["type","unit"],"title":"Set the weight","type":"object"}],"title":"Weight"}},"title":"Custom line item","type":"object"},{"description":"Change a fee, such as a rush or setup fee.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"The fee amount for one unit. Fees never take a decoration price.","properties":{"product":{"properties":{"total":{"description":"The fee for one unit, 0 or more.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"type":{"const":"fee","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"description":{"description":"Extra text shown under the fee, for example what it covers.","type":"string"},"name":{"description":"The fee's name, for example \"Rush fee\".","type":"string"}},"type":"object"},"type":{"const":"fee","type":"string"}},"required":["type"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out for no weight.","oneOf":[{"description":"Your own weight for one unit. `unit` is required; leave `total` out to keep the current weight.","properties":{"total":{"description":"The weight as a `{ value, dp }` pair whose two parts are strings: 1.5 is `{ \"value\": \"15\", \"dp\": \"1\" }`.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, as a string.","type":"string"},"value":{"description":"The weight without its decimal point, as a string of digits.","type":"string"}},"required":["value","dp"],"type":"object"},"type":{"const":"mass","type":"string"},"unit":{"enum":["lb","kg"],"type":"string"}},"required":["type","unit"],"title":"Set the weight","type":"object"}],"title":"Weight"}},"title":"Fee line item","type":"object"}],"description":"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.","title":"What kind of line are you changing?","x-yoprint-discriminator":{"mapping":{"custom":"Custom line item","db_catalog":"Catalog product","db_variant":"Custom variant product","fee":"Fee line item","user_simple":"Custom simple product"},"propertyPath":"product.type"}}},"required":["bid","action","cart_item_id","payload"],"title":"Change a line","type":"object"},"DeleteLine":{"description":"Deletes a line. A line that is already deleted is skipped without an error.","properties":{"action":{"const":"delete","type":"string"},"bid":{"description":"Your own id for this operation, unique in the request. An error names it.","type":"string"},"cart_item_id":{"description":"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.)","type":"string"}},"required":["bid","action","cart_item_id"],"title":"Delete a line","type":"object"},"ErrorOrMessageResponse":{"description":"Either the error envelope (it has `error`) or a message-only body (it has only `message`).","oneOf":[{"$ref":"#/components/schemas/ErrorResponse"},{"$ref":"#/components/schemas/MessageErrorResponse"}]},"ErrorResponse":{"additionalProperties":false,"description":"The error envelope. `error.code` names the reason in a stable, machine-readable way; `error.message` explains it for people, or is null. Branch on `code`, never on `message`.","properties":{"error":{"additionalProperties":true,"properties":{"bid":{"description":"Bulk operations: the `bid` you sent for the item that failed.","type":"string"},"code":{"description":"The reason: `unauthenticated`, `unauthorized`, `page_not_found`, `validation_failed`, or a code of the operation's own (see its errors). Null when the record you named does not exist.","example":"validation_failed","type":["string","null"]},"field_reasons":{"additionalProperties":{"additionalProperties":true,"properties":{"maximum":{"description":"With `too_large`: the largest value allowed, as a decimal string.","type":"string"},"minimum":{"description":"With `below_minimum`: the smallest value allowed, as a decimal string.","type":"string"},"reason":{"description":"Such as `required`, `invalid_number`, `whole_number`, `invalid_text`, `invalid_date`, `invalid_value`, `invalid_choice`, `unavailable_choice`, `below_minimum`, `too_large`, `precision`, `incomplete_number`, `unsafe_number` or `invalid_structure`.","type":"string"}},"required":["reason"],"type":"object"},"description":"With some `fields`: a machine-readable reason for a field, when YoPrint knows it.","type":"object"},"fields":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"description":"With `validation_failed`, and some other 422 codes: what is wrong with each field, keyed by the field's name. Nested fields use dots, such as `items.0.quantity`.","type":"object"},"message":{"description":"An explanation for people, or null. It can change: show it, don't parse it.","example":null,"type":["string","null"]}},"required":["code","message"],"type":"object"},"status":{"description":"The HTTP status code, repeated. A few operations send a refusal with HTTP 200; its body still says `success: false`, with 500 here.","example":422,"type":"integer"},"success":{"const":false,"description":"Always false on an error. Check it as well as the HTTP status.","type":"boolean"}},"required":["status","success","error"],"title":"Error","type":"object"},"Invoice":{"additionalProperties":true,"type":"object"},"JobLinked":{"description":"The line belongs to one of this order's jobs and takes its decoration price.","properties":{"id":{"description":"The job's `id`, from the order's jobs. It must be a job of this same order.","type":"string"},"type":{"const":"linked","type":"string"}},"required":["type","id"],"title":"Linked to a job","type":"object"},"JobStandalone":{"description":"The line has no job, so no decoration price.","properties":{"type":{"const":"standalone","type":"string"}},"required":["type"],"title":"No job","type":"object"},"MessageErrorResponse":{"description":"A short error body without `success` or `error`, sent by a few checks (such as a missing role permission) and by unexpected failures.","properties":{"message":{"description":"What went wrong, for people.","example":"Insufficient Permission","type":"string"}},"required":["message"],"title":"Message-only error","type":"object"},"MultiLineTax":{"description":"Named parts whose rates add up.","properties":{"apply_before_disc":{"default":false,"description":"Calculate tax before the discount. Defaults to false.","type":"boolean"},"default":{"description":"`true` makes it the team's default tax preset. `false` does nothing.","type":"boolean"},"enable":{"default":true,"description":"Defaults to true.","type":"boolean"},"line_taxes":{"description":"1 to 8 parts. YoPrint sets the preset's `total` to their sum.","items":{"properties":{"name":{"description":"The part's name, such as `State` or `County`.","example":"State","type":"string"},"total":{"description":"The part's rate. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":6000,"minimum":0,"type":"integer"}},"required":["name","total"],"type":"object"},"maxItems":8,"minItems":1,"type":"array"},"name":{"type":"string"},"shipping_taxable":{"default":true,"description":"Tax shipping too. Defaults to true.","type":"boolean"},"type":{"const":"line_tax","type":"string"}},"required":["type","name","line_taxes"],"title":"Multi Line Tax","type":"object"},"PaginationMeta":{"properties":{"count":{"example":25,"type":"integer"},"currentPage":{"example":1,"type":"integer"},"links":{"description":"Links to the neighbouring pages: `previous` and `next`, each present only when that page exists. An empty list, `[]`, when there is only one page.","example":{"next":"https://secure.yoprint.com/v1/api/store/your-team/customer?page=2"},"oneOf":[{"additionalProperties":false,"properties":{"next":{"description":"The next page.","format":"uri","type":"string"},"previous":{"description":"The previous page.","format":"uri","type":"string"}},"title":"Page links","type":"object"},{"maxItems":0,"title":"No other pages","type":"array"}]},"perPage":{"example":25,"type":"integer"},"total":{"example":250,"type":"integer"},"totalPages":{"example":10,"type":"integer"}},"required":["count","total","perPage","currentPage","totalPages","links"],"type":"object"},"Shipment":{"additionalProperties":true,"type":"object"},"SimpleProduct":{"additionalProperties":true,"properties":{"barcode":{"type":["string","null"]},"brand":{"type":["string","null"]},"color_data":{"type":"array"},"default_price":{"description":"The selling price. Null when not set. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"deleted_at":{"format":"date-time","type":["string","null"]},"deleted_by":{"description":"Who did it, as `{id, name}`; null when on sale or nobody was recorded.","properties":{"id":{"type":"string"},"name":{"type":"string"}},"type":["object","null"]},"deleted_variant_count":{"type":"null"},"description":{"type":["string","null"]},"enable":{"type":"boolean"},"id":{"type":"string"},"phased_out":{"type":"boolean"},"phased_out_at":{"format":"date-time","type":["string","null"]},"phased_out_by":{"description":"Who did it, as `{id, name}`; null when on sale or nobody was recorded.","properties":{"id":{"type":"string"},"name":{"type":"string"}},"type":["object","null"]},"phased_out_variant_count":{"type":"null"},"price_data":{"additionalProperties":true,"description":"Prices for pricing groups, as saved: keyed by the pricing group's internal number (not its hash id), each `{\"price\": <thousandths>}`. An empty list `[]` when there are none.","type":["object","array"]},"size_data":{"type":"array"},"supplier_id":{"type":["string","null"]},"taxable":{"type":"boolean"},"title":{"type":["string","null"]},"track_inventory":{"type":"boolean"},"trashed":{"type":"boolean"},"type":{"const":"simple","type":"string"},"variant_count":{"type":"null"},"vendor_id":{"type":["string","null"]},"weight":{"type":["number","string","null"]}},"required":["id","type","title","default_price","trashed","phased_out"],"title":"Simple product","type":"object"},"SimpleProductInput":{"additionalProperties":false,"description":"One item with one price.","properties":{"barcode":{"description":"The product's barcode. Saved as sent.","type":"string"},"brand":{"description":"The product's brand.","type":"string"},"default_price":{"description":"Required. Send a whole number of thousandths: `12500` is 12.50.","type":"integer"},"description":{"description":"A description of the product.","type":"string"},"dimension_x":{"type":"number"},"dimension_y":{"type":"number"},"dimension_z":{"type":"number"},"price_data":{"additionalProperties":{"properties":{"price":{"description":"Send a whole number of thousandths: `11000` is 11.00.","type":"integer"}},"required":["price"],"type":"object"},"description":"Prices for pricing groups, keyed by pricing group id: `{\"<pricing group id>\": {\"price\": 11000}}`. A line priced with that group uses this price instead of `default_price`. Send a whole number of thousandths: `11000` is 11.00.","type":"object"},"supplier_id":{"description":"The supplier's code for the product.","type":"string"},"taxable":{"description":"Whether sales tax applies to it.","type":"boolean"},"title":{"description":"Required on create. The product name shown on orders.","type":"string"},"type":{"const":"simple","type":"string"},"vendor_id":{"description":"The vendor you buy it from.","type":"string"},"weight":{"description":"The product's weight. Simple products only.","type":"number"}},"required":["type","title","default_price"],"title":"Simple product","type":"object"},"SingleLineTax":{"description":"One rate.","properties":{"apply_before_disc":{"default":false,"description":"Calculate tax before the discount. Defaults to false.","type":"boolean"},"default":{"description":"`true` makes it the team's default tax preset. `false` does nothing.","type":"boolean"},"enable":{"default":true,"description":"Defaults to true.","type":"boolean"},"name":{"type":"string"},"shipping_taxable":{"default":true,"description":"Tax shipping too. Defaults to true.","type":"boolean"},"total":{"description":"The rate. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","minimum":0,"type":"integer"},"type":{"const":"simple","type":"string"}},"required":["type","name","total"],"title":"Single Line Tax","type":"object"},"SupplierCatalogStyle":{"additionalProperties":false,"description":"`type` is `variant_catalog`. `attr_data` lists every size and color of the style.","properties":{"attr_data":{"description":"One row per size and color, most recently updated first.","items":{"additionalProperties":false,"properties":{"available":{"const":true,"type":"boolean"},"color_hex":{"type":["string","null"]},"color_id":{"type":["string","null"]},"color_image":{"type":["string","null"]},"color_label":{"type":["string","null"]},"display_dscnt":{"description":"Display discontinued status: true when YoPrint displays the discontinued badge for this variant.","type":"boolean"},"dscnt":{"description":"Discontinued: true when the supplier discontinued the variant. For S&S Activewear, also true when the variant was not updated in the last 16 days.","type":"boolean"},"id":{"description":"The catalog product id, such as `ssa-B00000001`: the `db_catalog` line's product id and the id for live pricing.","type":"string"},"provider":{"description":"The supplier code, such as `ssa`: send it as the line's `pricing.catalog.provider`.","type":"string"},"size_id":{"type":["string","null"]},"size_label":{"type":["string","null"]},"updated_at":{"format":"date-time","type":"string"},"weight":{"type":["number","string","null"]}},"required":["id","provider","dscnt"],"type":"object"},"type":"array"},"brand":{"type":["string","null"]},"color_data":{"items":{"additionalProperties":false,"properties":{"hex":{"type":"string"},"id":{"type":"string"},"image":{"description":"A color swatch image URL, when the supplier has one.","type":"string"},"label":{"type":"string"}},"required":["id","label"],"type":"object"},"type":"array"},"display_dscnt":{"description":"Display discontinued status: true when YoPrint displays the discontinued badge for this style.","type":"boolean"},"dscnt":{"description":"Discontinued: true when the supplier discontinued the style.","type":"boolean"},"id":{"description":"The style id, such as `ssa-5000`.","type":"string"},"product_type":{"description":"The supplier, such as `SSActivewear` or `SanMar`.","type":["string","null"]},"size_data":{"items":{"additionalProperties":true,"properties":{"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"style_id":{"description":"The same as `id`.","type":"string"},"style_name":{"description":"The style number people see.","type":["string","null"]},"title":{"type":["string","null"]},"trashed":{"const":false,"type":"boolean"},"type":{"const":"variant_catalog","type":"string"},"variant_type":{"enum":["size","color","size_color","none"],"type":"string"}},"required":["id","type","style_id","variant_type","attr_data"],"title":"A supplier catalog style","type":"object"},"VariantProduct":{"additionalProperties":true,"properties":{"brand":{"type":["string","null"]},"color_data":{"items":{"additionalProperties":true,"properties":{"hex":{"type":["string","null"]},"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"default_price":{"description":"Not used for variant products: each variant has its own. Null when not set. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"description":{"type":["string","null"]},"enable":{"type":"boolean"},"id":{"type":"string"},"size_data":{"items":{"additionalProperties":true,"properties":{"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"supplier_id":{"type":["string","null"]},"taxable":{"type":"boolean"},"title":{"type":["string","null"]},"trashed":{"type":"boolean"},"type":{"const":"variant","type":"string"},"variant_type":{"enum":["size","color","size_color"],"type":"string"},"vendor_id":{"type":["string","null"]}},"required":["id","type","variant_type","title","size_data","color_data","trashed"],"title":"Variant product","type":"object"},"VariantProductInput":{"additionalProperties":false,"description":"Sizes, colors or both, one variant per combination.","properties":{"barcode":{"description":"The product's barcode. Saved as sent.","type":"string"},"brand":{"description":"The product's brand.","type":"string"},"color_data":{"description":"Required for `color` and `size_color`: the colors.","items":{"properties":{"hex":{"description":"Such as `#1F2937`.","type":"string"},"id":{"description":"Your id for the color. It never changes.","type":"string"},"label":{"type":"string"}},"required":["id","label","hex"],"type":"object"},"type":"array"},"description":{"description":"A description of the product.","type":"string"},"dimension_x":{"type":"number"},"dimension_y":{"type":"number"},"dimension_z":{"type":"number"},"product":{"description":"One entry per size and color combination you sell.","items":{"additionalProperties":false,"properties":{"barcode":{"description":"Saved as sent; not checked.","type":"string"},"color_hex":{"description":"For products with colors, such as `#1F2937`.","type":"string"},"color_id":{"description":"For products with colors: your id for the color. The rule depends on the case:\n- When creating a product: use an id from `color_data`.\n- When adding a variant to a color-only product: send a new id to add a color. Reusing an existing id is a duplicate (422).\n- When adding a variant to a size-and-color product: reuse an id from `color_data` to add a new size in an existing color, or send a new id to add a color.","type":"string"},"color_label":{"description":"For products with colors. For a color the product already has, its current name is kept.","type":"string"},"default_price":{"description":"Required. This variant's selling price. Send a whole number of thousandths: `9000` is 9.00.","type":"integer"},"enable":{"description":"Saved as sent (default true); returned as `enable`. Nothing enforces it: phase a variant out to stop selling it.","type":"boolean"},"price_data":{"additionalProperties":{"properties":{"price":{"description":"Send a whole number of thousandths: `11000` is 11.00.","type":"integer"}},"required":["price"],"type":"object"},"description":"Prices for pricing groups, keyed by pricing group id: `{\"<pricing group id>\": {\"price\": 11000}}`. A line priced with that group uses this price instead of `default_price`. Send a whole number of thousandths: `11000` is 11.00.","type":"object"},"size_id":{"description":"For products with sizes: your id for the size. The rule depends on the case:\n- When creating a product: use an id from `size_data`.\n- When adding a variant to a size-only product: send a new id to add a size. Reusing an existing id is a duplicate (422).\n- When adding a variant to a size-and-color product: reuse an id from `size_data` to add a new color for an existing size, or send a new id to add a size.","type":"string"},"size_label":{"description":"For products with sizes. For a size the product already has, its current name is kept.","type":"string"},"supplier_id":{"description":"The supplier's code for this variant.","type":"string"},"track_inventory":{"description":"Saved as sent (default true); not checked.","type":"boolean"},"vendor_id":{"type":"string"},"weight":{"description":"The variant's weight.","type":"number"}},"required":["default_price"],"type":"object"},"minItems":1,"type":"array"},"size_data":{"description":"Required for `size` and `size_color`: the sizes, in display order.","items":{"properties":{"id":{"description":"Your id for the size, such as `M`. It never changes; the label can.","type":"string"},"label":{"description":"The size name shown on orders.","type":"string"}},"required":["id","label"],"type":"object"},"type":"array"},"supplier_id":{"description":"The supplier's code for the product.","type":"string"},"taxable":{"description":"Whether sales tax applies to it.","type":"boolean"},"title":{"description":"Required on create. The product name shown on orders.","type":"string"},"type":{"const":"variant","type":"string"},"variant_type":{"description":"Which options the product has.","enum":["size","color","size_color"],"type":"string"},"vendor_id":{"description":"The vendor you buy it from.","type":"string"},"weight":{"description":"The product's weight. Simple products only.","type":"number"}},"required":["type","title","variant_type","product"],"title":"Variant product","type":"object"},"WeightMassCreate":{"description":"Your own weight for one unit.","properties":{"total":{"description":"The weight as a `{ value, dp }` pair whose two parts are strings: 1.5 is `{ \"value\": \"15\", \"dp\": \"1\" }`.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, as a string.","type":"string"},"value":{"description":"The weight without its decimal point, as a string of digits.","type":"string"}},"required":["value","dp"],"type":"object"},"type":{"const":"mass","type":"string"},"unit":{"enum":["lb","kg"],"type":"string"}},"required":["type","unit","total"],"title":"Set the weight","type":"object"},"WeightMassUpdate":{"description":"Your own weight for one unit. `unit` is required; leave `total` out to keep the current weight.","properties":{"total":{"description":"The weight as a `{ value, dp }` pair whose two parts are strings: 1.5 is `{ \"value\": \"15\", \"dp\": \"1\" }`.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, as a string.","type":"string"},"value":{"description":"The weight without its decimal point, as a string of digits.","type":"string"}},"required":["value","dp"],"type":"object"},"type":{"const":"mass","type":"string"},"unit":{"enum":["lb","kg"],"type":"string"}},"required":["type","unit"],"title":"Set the weight","type":"object"},"WeightUseSystem":{"description":"Take the weight from the product (in lb).","properties":{"type":{"const":"use_system","type":"string"}},"required":["type"],"title":"Use the product's weight","type":"object"},"YourSimpleProduct":{"additionalProperties":false,"description":"`type` is `simple`.","properties":{"brand":{"type":["string","null"]},"description":{"type":["string","null"]},"id":{"description":"The product id: the `user_simple` line's product id.","type":"string"},"phased_out":{"description":"True: new sales order and quote lines refuse it.","type":"boolean"},"phased_out_at":{"format":"date-time","type":["string","null"]},"price":{"description":"The selling price before pricing rules: `default_price`. Null when not set. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"product_type":{"const":"simple","type":"string"},"supplier_id":{"type":["string","null"]},"title":{"type":["string","null"]},"trashed":{"type":"boolean"},"type":{"const":"simple","type":"string"},"weight":{"type":["number","string","null"]}},"required":["id","type","title","trashed","phased_out","price"],"title":"Your simple product","type":"object"},"YourVariantProduct":{"additionalProperties":false,"description":"`type` is `variant`. `attr_data` lists its live variants.","properties":{"attr_data":{"description":"One row per live variant.","items":{"additionalProperties":false,"properties":{"available":{"description":"The variant's enabled flag. Nothing enforces it: use `phased_out`.","type":"boolean"},"color_hex":{"type":["string","null"]},"color_id":{"type":["string","null"]},"color_image":{"description":"Always empty for your own products.","type":"string"},"color_label":{"type":["string","null"]},"id":{"description":"The variant id: the `db_variant` line's product id.","type":"string"},"phased_out":{"description":"True: new sales order and quote lines refuse this variant.","type":"boolean"},"price":{"description":"The variant's `default_price`. Never null. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"size_id":{"type":["string","null"]},"size_label":{"type":["string","null"]},"supplier_id":{"type":["string","null"]},"variant_deleted":{"description":"Always false here: deleted variants are left out.","type":"boolean"},"weight":{"type":["number","string","null"]}},"required":["id","phased_out","price"],"type":"object"},"type":"array"},"brand":{"type":["string","null"]},"color_data":{"items":{"additionalProperties":true,"properties":{"hex":{"type":["string","null"]},"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"description":{"type":["string","null"]},"id":{"description":"The product id.","type":"string"},"product_type":{"const":"variant","type":"string"},"size_data":{"items":{"additionalProperties":true,"properties":{"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"style_id":{"description":"The same as `id`.","type":"string"},"title":{"type":["string","null"]},"trashed":{"type":"boolean"},"type":{"const":"variant","type":"string"},"variant_type":{"enum":["size","color","size_color"],"type":"string"}},"required":["id","type","variant_type","size_data","color_data","attr_data"],"title":"Your variant product","type":"object"}},"securitySchemes":{"UserApiKeyBearer":{"bearerFormat":"YoPrint personal API key","description":"Your personal API key from Profile, sent as `Authorization: Bearer <key>`. This is the recommended way to send it.","scheme":"bearer","type":"http"},"UserApiKeyHeader":{"description":"The same personal API key as the raw Authorization header value, without `Bearer`. Still accepted; prefer UserApiKeyBearer.","in":"header","name":"Authorization","type":"apiKey"},"UserApiKeyQuery":{"description":"The same personal API key in the `user_api_key` query parameter. Still accepted for older integrations, but URLs end up in logs; send the key in the Authorization header instead.","in":"query","name":"user_api_key","type":"apiKey"}}},"info":{"contact":{"email":"support@yoprint.com","name":"YoPrint support"},"description":"YoPrint's public team REST API. Guides, and a page per operation: https://developer.yoprint.com/reference/. Rules for every call: https://developer.yoprint.com/llms.txt.","license":{"identifier":"LicenseRef-YoPrint-Proprietary","name":"Proprietary"},"title":"YoPrint Team Public API","version":"5.16.1"},"openapi":"3.1.0","paths":{"/v1/api/store/{team_slug}/approvals":{"get":{"description":"Lists customer approvals across all of your team's sales orders and quotes, newest first.\n\nAn approval asks the customer to sign off, in the customer portal, on either a job's artwork (`type` `job`) or the whole order (`type` `order`). The customer approves or asks for changes; `status` follows that. Approvals are created on the order (the sales order approval operations), not here.\n\nDraft orders, deleted orders and Shopify orders are left out. The page size is your team's list size setting (50 unless changed); use `page` to read further. To filter by type or status, use `POST /v1/api/store/{team_slug}/approvals/filter`.","operationId":"v1_public_approvals_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The page to read, from 1.","in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"approved_by":"customer","approved_by_user":null,"completed":false,"completed_at":null,"created_at":"2026-11-03T09:30:00+00:00","customer_id":2001,"customer_last_viewed_date":null,"customer_name":"Northwind Apparel","id":"Fi0zPeMlwKadEo","job_id":"K6iF8n29iwOZnj","job_name":"Front logo","job_scoped_id":"JOB-1001","notes_from_customer":null,"notes_to_customer":"Please check the logo size.","order_external_type":null,"order_id":"V4keXwwxMQyXw7","order_name":"Spring team shirts","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","request_by":null,"signature":null,"status":"sent-to-customer","type":"job"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"approved_by":{"description":"`user` when a team member completed it. Otherwise `customer`, even before anyone has approved it, and also when a Customer Portal contact approved it (Get an approval names the contact).","enum":["user","customer"],"type":"string"},"approved_by_user":{"description":"The hash id of the team member who completed it on the customer's behalf, if any.","type":["string","null"]},"completed":{"description":"True once the customer finished, whether they approved or asked for changes.","type":"boolean"},"completed_at":{"format":"date-time","type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"A plain number for the customer, not a hash id: no operation takes it. Use `order_id` to reach the customer.","type":["integer","null"]},"customer_last_viewed_date":{"format":"date-time","type":["string","null"]},"customer_name":{"type":["string","null"]},"id":{"type":"string"},"job_id":{"description":"Job approvals only.","type":["string","null"]},"job_name":{"description":"An empty string for order approvals.","type":"string"},"job_scoped_id":{"description":"The job number, such as `JOB-1001`. An empty string for order approvals.","type":"string"},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_external_type":{"type":["string","null"]},"order_id":{"type":["string","null"]},"order_name":{"type":["string","null"]},"order_object_type":{"description":"`sales_order` or `quote`.","enum":["sales_order","quote",null],"type":["string","null"]},"order_quote":{"description":"True when the approval is on a quote.","type":"boolean"},"order_scoped_id":{"description":"The order or quote number.","type":"string"},"request_by":{"description":"A team member's hash id, or null. Approvals created in the web app or through the API are null here: neither records who requested them.","type":["string","null"]},"signature":{"description":"The customer's signature, when they signed.","type":["string","null"]},"status":{"description":"`pending`: not sent yet. `sent-to-customer`: emailed. `viewed-by-customer`: the customer opened it. `need-changes`: the customer finished and asked for changes (\"Review requested\"). `completed`: approved.","enum":["pending","sent-to-customer","viewed-by-customer","need-changes","completed"],"type":"string"},"type":{"description":"`job`: artwork approval for one job's mockups. `order`: approval of the whole order.","enum":["job","order"],"type":"string"}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List approvals","tags":["Approvals"],"x-yoprint-docs":{"group":"Sales","notes":["`customer_id` here is a plain number, not the hash id other operations take. To reach the customer, read the order with `order_id`.","`completed` is true for both approved and changes-requested approvals; read `status` to tell them apart."],"permission":"Any member of the team. The list is not narrowed to orders you can see.","related":["v1_public_approvals_filter","v1_public_approvals_show","v1_public_approvals_send_to_customer","v2_public_order_approval_store"]}}},"/v1/api/store/{team_slug}/approvals/filter":{"post":{"description":"Lists approvals like `GET /v1/api/store/{team_slug}/approvals`, narrowed by `type` and `status`, with an optional sort. For example, everything still waiting on the customer: `status` `in` `pending`, `sent-to-customer`, `viewed-by-customer`.\n\nEach filter is `{key, operator, value}` with `operator` `in` or `nin` and `value` a list. Several filters must all match. Send `page` in the body or the query string.","operationId":"v1_public_approvals_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"filters":[{"key":"status","operator":"in","value":["pending","sent-to-customer","viewed-by-customer"]}],"sort":[{"direction":"desc","key":"created_at"}]},"schema":{"properties":{"filters":{"items":{"properties":{"key":{"enum":["type","status"],"type":"string"},"operator":{"description":"`in`: any of the values. `nin`: none of them.","enum":["in","nin"],"type":"string"},"value":{"description":"For `type`: `job`, `order`. For `status`: the approval statuses.","items":{"type":"string"},"type":"array"}},"required":["key","operator","value"],"type":"object"},"minItems":1,"type":"array"},"page":{"minimum":1,"type":"integer"},"sort":{"items":{"properties":{"direction":{"enum":["asc","desc"],"type":"string"},"key":{"enum":["id","order_id","job_id","type","completed_at","created_at","status"],"type":"string"}},"required":["key","direction"],"type":"object"},"type":"array"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"approved_by":"customer","approved_by_user":null,"completed":false,"completed_at":null,"created_at":"2026-11-03T09:30:00+00:00","customer_id":2001,"customer_last_viewed_date":null,"customer_name":"Northwind Apparel","id":"Fi0zPeMlwKadEo","job_id":"K6iF8n29iwOZnj","job_name":"Front logo","job_scoped_id":"JOB-1001","notes_from_customer":null,"notes_to_customer":"Please check the logo size.","order_external_type":null,"order_id":"V4keXwwxMQyXw7","order_name":"Spring team shirts","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","request_by":null,"signature":null,"status":"sent-to-customer","type":"job"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"approved_by":{"description":"`user` when a team member completed it. Otherwise `customer`, even before anyone has approved it, and also when a Customer Portal contact approved it (Get an approval names the contact).","enum":["user","customer"],"type":"string"},"approved_by_user":{"description":"The hash id of the team member who completed it on the customer's behalf, if any.","type":["string","null"]},"completed":{"description":"True once the customer finished, whether they approved or asked for changes.","type":"boolean"},"completed_at":{"format":"date-time","type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"A plain number for the customer, not a hash id: no operation takes it. Use `order_id` to reach the customer.","type":["integer","null"]},"customer_last_viewed_date":{"format":"date-time","type":["string","null"]},"customer_name":{"type":["string","null"]},"id":{"type":"string"},"job_id":{"description":"Job approvals only.","type":["string","null"]},"job_name":{"description":"An empty string for order approvals.","type":"string"},"job_scoped_id":{"description":"The job number, such as `JOB-1001`. An empty string for order approvals.","type":"string"},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_external_type":{"type":["string","null"]},"order_id":{"type":["string","null"]},"order_name":{"type":["string","null"]},"order_object_type":{"description":"`sales_order` or `quote`.","enum":["sales_order","quote",null],"type":["string","null"]},"order_quote":{"description":"True when the approval is on a quote.","type":"boolean"},"order_scoped_id":{"description":"The order or quote number.","type":"string"},"request_by":{"description":"A team member's hash id, or null. Approvals created in the web app or through the API are null here: neither records who requested them.","type":["string","null"]},"signature":{"description":"The customer's signature, when they signed.","type":["string","null"]},"status":{"description":"`pending`: not sent yet. `sent-to-customer`: emailed. `viewed-by-customer`: the customer opened it. `need-changes`: the customer finished and asked for changes (\"Review requested\"). `completed`: approved.","enum":["pending","sent-to-customer","viewed-by-customer","need-changes","completed"],"type":"string"},"type":{"description":"`job`: artwork approval for one job's mockups. `order`: approval of the whole order.","enum":["job","order"],"type":"string"}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Filter approvals by type or status","tags":["Approvals"],"x-yoprint-docs":{"errors":[{"fix":"Send at least one `{key, operator, value}` with an allowed key, `in` or `nin`, and a list, or leave `filters` out. Write `direction` in lower case.","status":422,"when":"`filters` is an empty list, a key or operator is not allowed, `value` is not a list, or a sort `key` or `direction` is not allowed (`validation_failed`, with the problem under `error.fields`)."}],"group":"Sales","notes":["Without `sort`, the order of results is not defined. Send a sort, such as `created_at` `desc`, when you page."],"permission":"Any member of the team. The list is not narrowed to orders you can see.","related":["v1_public_approvals_index"],"rules":["`filters` is optional. If you send it, it can't be empty. Leaving it out returns every approval, like the list. Filter keys are `type` and `status` only.","`value` must be a list, even for one value.","Sort keys: `id`, `order_id`, `job_id`, `type`, `completed_at`, `created_at`, `status`; `direction` `asc` or `desc`."]}}},"/v1/api/store/{team_slug}/approvals/{hash_id}":{"delete":{"description":"Deletes an approval that the customer has not completed yet, for good, with its mockup items. The customer's link stops working. Completed approvals (approved or changes requested) can't be deleted; they stay as the order's record.","operationId":"v1_public_approvals_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The approval's `id`, from the approvals list. A hash id; unique keys and document numbers are refused with 404.","example":"Fi0zPeMlwKadEo","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete an approval","tags":["Approvals"],"x-yoprint-docs":{"errors":[{"fix":"Keep it. Create a new approval if the customer needs to review again.","status":422,"when":"The approval is completed (`approval_already_completed`, \"This approval has already been completed. You cannot remove completed approvals.\")."},{"fix":"Shopify orders do not use approvals in YoPrint.","status":422,"when":"The order came from Shopify (`shopify_approval_workflow_locked`)."},{"fix":"Use an `id` from the approvals list.","status":404,"when":"No approval of this team has this id."}],"group":"Sales","permission":"Any member of the team.","related":["v1_public_approvals_index","v2_public_order_approval_destroy"],"rules":["Only approvals that are not completed can be deleted."],"side_effects":["For an order approval, clears the order's approval status.","People with the order open, and the customer's open Customer Portal pages, see the approval disappear. No email or webhook."]}},"get":{"description":"Looks up the approval, then returns **every approval on the same order or quote**, as a list: job and order approvals, completed or not. Find the one you asked for by `id`.\n\nEach item has the approval's notes, status and signature, and who completed it: `approved_by` is `contact`, with `approved_by_contact_id`, when a Customer Portal contact did. Job approvals also have `items` (each mockup or design with its own status and the customer's notes) and `mockup` (the images).","operationId":"v1_public_approvals_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The approval's `id`, from the approvals list. A hash id; unique keys and document numbers are refused with 404.","example":"Fi0zPeMlwKadEo","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"approved_by":"customer","approved_by_contact_id":null,"approved_by_user":null,"completed":false,"completed_at":null,"created_at":"2026-11-03T09:30:00+00:00","customer_last_viewed_contact_id":null,"customer_last_viewed_date":null,"id":"Fi0zPeMlwKadEo","items":[{"collection":"mockup","created_at":"2026-11-03T09:30:00+00:00","download_url":"https://example.com/media/front-logo.png?download=1","file_name":"front-logo.png","id":"Top25MBL9YyCKV","is_image":true,"media_id":"b0l2VJxwa3ppc7","mime_type":"image/png","name":"front-logo","notes_from_customer":null,"notes_to_customer":null,"position":1,"preview":{"large":"https://example.com/media/front-logo-1200.png","medium":"https://example.com/media/front-logo-800.png","small":"https://example.com/media/front-logo-250.png"},"preview_url":"https://example.com/media/front-logo-800.png","show_in_pdf":null,"size":182044,"status":"pending-approval","type":"media","url":"https://example.com/media/front-logo.png?download=1","view_url":"https://example.com/media/front-logo.png"}],"job_id":"K6iF8n29iwOZnj","job_name":"Front logo","job_scoped_id":"JOB-1001","mockup":[{"collection":"mockup","created_at":"2026-11-03T09:30:00+00:00","file_name":"front-logo.png","id":"Top25MBL9YyCKV","is_image":true,"media_id":"b0l2VJxwa3ppc7","mime_type":"image/png","name":"front-logo","notes_from_customer":null,"notes_to_customer":null,"position":1,"preview":{"large":"https://example.com/media/front-logo-1200.png","medium":"https://example.com/media/front-logo-800.png","small":"https://example.com/media/front-logo-250.png"},"show_in_pdf":null,"size":182044,"status":"pending-approval","url":"https://example.com/media/front-logo.png?download=1","view_url":"https://example.com/media/front-logo.png"}],"notes_from_customer":null,"notes_to_customer":"Please check the logo size.","order_external_type":null,"order_id":"V4keXwwxMQyXw7","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","request_by":null,"signature":null,"signed_terms_text":null,"status":"sent-to-customer","type":"job"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"approved_by":{"description":"`contact` when a Customer Portal contact completed it (`approved_by_contact_id`). `user` when a team member completed it. Otherwise `customer`, even before anyone has approved it.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who completed it in the Customer Portal, when YoPrint knows which contact it was. Null otherwise.","type":["string","null"]},"approved_by_user":{"description":"The hash id of the team member who completed it on the customer's behalf, if any.","type":["string","null"]},"completed":{"description":"True once the customer finished, whether they approved or asked for changes.","type":"boolean"},"completed_at":{"format":"date-time","type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"customer_last_viewed_contact_id":{"description":"The last contact known to have opened it in the Customer Portal. Null when none is known.","type":["string","null"]},"customer_last_viewed_date":{"format":"date-time","type":["string","null"]},"id":{"type":"string"},"items":{"description":"Job approvals: each mockup file or design, in order, with its own status and notes. `media` items also carry the file's details and expiring links; `mockup_design` items carry the design's revision and page previews. An empty list for order approvals.","items":{"additionalProperties":true,"properties":{"id":{"description":"The item's id.","type":"string"},"media_id":{"description":"`media` items: the file's id.","type":["string","null"]},"mockup_design_id":{"description":"`mockup_design` items: the design's id.","type":["string","null"]},"name":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"position":{"type":"integer"},"status":{"enum":["pending-approval","approved","need-changes"],"type":"string"},"type":{"description":"`media`: an uploaded mockup file. `mockup_design`: a design made in the mockup designer.","enum":["media","mockup_design"],"type":"string"}},"type":"object"},"type":"array"},"job_id":{"description":"Job approvals only.","type":["string","null"]},"job_name":{"description":"An empty string for order approvals.","type":"string"},"job_scoped_id":{"description":"The job number, such as `JOB-1001`. An empty string for order approvals.","type":"string"},"mockup":{"description":"Job approvals: the uploaded mockup files only (designs are only in `items`); an empty list when there are none. Null for order approvals.","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"file_name":{"type":"string"},"id":{"description":"The same id as the matching `media` item in `items`.","type":"string"},"media_id":{"description":"The file's id.","type":"string"},"mime_type":{"type":"string"},"name":{"type":"string"},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"position":{"type":"integer"},"status":{"enum":["pending-approval","approved","need-changes"],"type":"string"},"url":{"description":"A signed download link. It expires; don't store it.","type":"string"}},"type":"object"},"type":["array","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_external_type":{"type":["string","null"]},"order_id":{"type":["string","null"]},"order_object_type":{"description":"`sales_order` or `quote`.","enum":["sales_order","quote",null],"type":["string","null"]},"order_quote":{"description":"True when the approval is on a quote.","type":"boolean"},"order_scoped_id":{"description":"The order or quote number.","type":"string"},"request_by":{"description":"A team member's hash id, or null. Approvals created in the web app or through the API are null here: neither records who requested them.","type":["string","null"]},"signature":{"description":"The customer's signature, when they signed.","type":["string","null"]},"signed_terms_text":{"description":"The terms the customer agreed to when signing.","type":["string","null"]},"status":{"description":"`pending`: not sent yet. `sent-to-customer`: emailed. `viewed-by-customer`: the customer opened it. `need-changes`: the customer finished and asked for changes (\"Review requested\"). `completed`: approved.","enum":["pending","sent-to-customer","viewed-by-customer","need-changes","completed"],"type":"string"},"type":{"description":"`job`: artwork approval for one job's mockups. `order`: approval of the whole order.","enum":["job","order"],"type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get the approvals on an approval's order","tags":["Approvals"],"x-yoprint-docs":{"errors":[{"fix":"Use an `id` from the approvals list.","status":404,"when":"No approval of this team has this id, or its order came from Shopify."}],"group":"Sales","notes":["Unlike the list, this includes approvals on draft orders."],"permission":"Any member of the team.","related":["v1_public_approvals_index","v2_public_order_approval_show"]}}},"/v1/api/store/{team_slug}/approvals/{hash_id}/send_to_customer":{"patch":{"description":"Emails the customer a link to the approval in the customer portal. Use it to send a new approval, or to remind them. A `pending` approval becomes `sent-to-customer`; sending again later emails again and leaves the status as it is.\n\nThe email goes to the order's message participants who receive email (`can_receive_mail` true and `status` `all` or `message`), or, if there are none, the order's contact. The subject starts with the sales order or quote number in brackets (with the customer PO number, if any), then \"Job - <job name> Artwork Approval Required\" for a job approval or \"Order Approval Required\" for an order approval. It is email only, never SMS. Send no body.\n\nEmail limit: if your team makes more than 60 of these calls in a minute, or goes over the daily email limit for its plan, YoPrint blocks email sending for your whole team until YoPrint support lifts the block. Never call this in a loop.\n\nReturns the approval.","operationId":"v1_public_approvals_send_to_customer","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The approval's `id`, from the approvals list. A hash id; unique keys and document numbers are refused with 404.","example":"Fi0zPeMlwKadEo","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"approved_by":"customer","approved_by_contact_id":null,"approved_by_user":null,"completed":false,"completed_at":null,"created_at":"2026-11-03T09:30:00+00:00","customer_last_viewed_contact_id":null,"customer_last_viewed_date":null,"id":"Fi0zPeMlwKadEo","items":[{"collection":"mockup","created_at":"2026-11-03T09:30:00+00:00","download_url":"https://example.com/media/front-logo.png?download=1","file_name":"front-logo.png","id":"Top25MBL9YyCKV","is_image":true,"media_id":"b0l2VJxwa3ppc7","mime_type":"image/png","name":"front-logo","notes_from_customer":null,"notes_to_customer":null,"position":1,"preview":{"large":"https://example.com/media/front-logo-1200.png","medium":"https://example.com/media/front-logo-800.png","small":"https://example.com/media/front-logo-250.png"},"preview_url":"https://example.com/media/front-logo-800.png","show_in_pdf":null,"size":182044,"status":"pending-approval","type":"media","url":"https://example.com/media/front-logo.png?download=1","view_url":"https://example.com/media/front-logo.png"}],"job_id":"K6iF8n29iwOZnj","job_name":"Front logo","job_scoped_id":"JOB-1001","mockup":[{"collection":"mockup","created_at":"2026-11-03T09:30:00+00:00","file_name":"front-logo.png","id":"Top25MBL9YyCKV","is_image":true,"media_id":"b0l2VJxwa3ppc7","mime_type":"image/png","name":"front-logo","notes_from_customer":null,"notes_to_customer":null,"position":1,"preview":{"large":"https://example.com/media/front-logo-1200.png","medium":"https://example.com/media/front-logo-800.png","small":"https://example.com/media/front-logo-250.png"},"show_in_pdf":null,"size":182044,"status":"pending-approval","url":"https://example.com/media/front-logo.png?download=1","view_url":"https://example.com/media/front-logo.png"}],"notes_from_customer":null,"notes_to_customer":"Please check the logo size.","order_external_type":null,"order_id":"V4keXwwxMQyXw7","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","request_by":null,"signature":null,"signed_terms_text":null,"status":"sent-to-customer","type":"job"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"approved_by":{"description":"`contact` when a Customer Portal contact completed it (`approved_by_contact_id`). `user` when a team member completed it. Otherwise `customer`, even before anyone has approved it.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who completed it in the Customer Portal, when YoPrint knows which contact it was. Null otherwise.","type":["string","null"]},"approved_by_user":{"description":"The hash id of the team member who completed it on the customer's behalf, if any.","type":["string","null"]},"completed":{"description":"True once the customer finished, whether they approved or asked for changes.","type":"boolean"},"completed_at":{"format":"date-time","type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"customer_last_viewed_contact_id":{"description":"The last contact known to have opened it in the Customer Portal. Null when none is known.","type":["string","null"]},"customer_last_viewed_date":{"format":"date-time","type":["string","null"]},"id":{"type":"string"},"items":{"description":"Job approvals: each mockup file or design, in order, with its own status and notes. `media` items also carry the file's details and expiring links; `mockup_design` items carry the design's revision and page previews. An empty list for order approvals.","items":{"additionalProperties":true,"properties":{"id":{"description":"The item's id.","type":"string"},"media_id":{"description":"`media` items: the file's id.","type":["string","null"]},"mockup_design_id":{"description":"`mockup_design` items: the design's id.","type":["string","null"]},"name":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"position":{"type":"integer"},"status":{"enum":["pending-approval","approved","need-changes"],"type":"string"},"type":{"description":"`media`: an uploaded mockup file. `mockup_design`: a design made in the mockup designer.","enum":["media","mockup_design"],"type":"string"}},"type":"object"},"type":"array"},"job_id":{"description":"Job approvals only.","type":["string","null"]},"job_name":{"description":"An empty string for order approvals.","type":"string"},"job_scoped_id":{"description":"The job number, such as `JOB-1001`. An empty string for order approvals.","type":"string"},"mockup":{"description":"Job approvals: the uploaded mockup files only (designs are only in `items`); an empty list when there are none. Null for order approvals.","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"file_name":{"type":"string"},"id":{"description":"The same id as the matching `media` item in `items`.","type":"string"},"media_id":{"description":"The file's id.","type":"string"},"mime_type":{"type":"string"},"name":{"type":"string"},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"position":{"type":"integer"},"status":{"enum":["pending-approval","approved","need-changes"],"type":"string"},"url":{"description":"A signed download link. It expires; don't store it.","type":"string"}},"type":"object"},"type":["array","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_external_type":{"type":["string","null"]},"order_id":{"type":["string","null"]},"order_object_type":{"description":"`sales_order` or `quote`.","enum":["sales_order","quote",null],"type":["string","null"]},"order_quote":{"description":"True when the approval is on a quote.","type":"boolean"},"order_scoped_id":{"description":"The order or quote number.","type":"string"},"request_by":{"description":"A team member's hash id, or null. Approvals created in the web app or through the API are null here: neither records who requested them.","type":["string","null"]},"signature":{"description":"The customer's signature, when they signed.","type":["string","null"]},"signed_terms_text":{"description":"The terms the customer agreed to when signing.","type":["string","null"]},"status":{"description":"`pending`: not sent yet. `sent-to-customer`: emailed. `viewed-by-customer`: the customer opened it. `need-changes`: the customer finished and asked for changes (\"Review requested\"). `completed`: approved.","enum":["pending","sent-to-customer","viewed-by-customer","need-changes","completed"],"type":"string"},"type":{"description":"`job`: artwork approval for one job's mockups. `order`: approval of the whole order.","enum":["job","order"],"type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Email an approval request to the customer","tags":["Approvals"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Add a contact with an email address to the order, then send again.","status":422,"when":"Nobody on the order has an email address (`approval_email_no_recipient`)."},{"fix":"Create a new approval, or save the order first.","status":422,"when":"The approval is completed, or the order is still a draft or an unsaved edit copy (`approval_already_completed`, \"You cannot send completed approval to customer again.\")."},{"fix":"Shopify orders do not use approvals in YoPrint.","status":422,"when":"The order came from Shopify (`shopify_approval_workflow_locked`)."},{"fix":"Contact YoPrint support. Space out bulk sends to stay well under 60 a minute.","status":422,"when":"Your team called this more than 60 times in a minute, or its email sending was already blocked (`validation_error`, \"You are sending too many emails in a short period of time...\")."},{"fix":"Use an `id` from the approvals list.","status":404,"when":"No approval of this team has this id."}],"group":"Sales","notes":["Don't loop this over many approvals quickly: the per-team limit counts every call that reaches it, including ones that then fail with 404 or 422, and going over it blocks your team's email sending until support lifts it."],"permission":"Any member of the team.","related":["v1_public_approvals_index","v1_public_approvals_destroy"],"rules":["The approval must not be completed, and its order must be saved: not a draft, and not an unsaved edit copy.","Someone on the order must be able to receive email.","At most 60 calls a minute for your whole team. The 61st call is refused and blocks your team's email sending: from then on this operation, sending order details, payment reminders and approval reminders, and sending message templates are refused with 422 until YoPrint support lifts the block."],"side_effects":["Sends an email to the customer, recorded in the order's messages.","Logs \"approval sent\" in the order's activity.","A `pending` approval becomes `sent-to-customer`; for an order approval, the order's approval status does too.","People with the order open, and the customer's open Customer Portal pages, see the change live. No webhook fires on sending."]}}},"/v1/api/store/{team_slug}/async_upload":{"post":{"description":"Uploads one file that does not belong to anything yet, and returns its id. Then attach it with the operation for its destination, passing the id as `attachment[].id`: a job's mockups and production files, a sales order, a purchase order or a customer.\n\nSend `multipart/form-data` with the file in `media`. Choose `collection` `mockup` for mockup images (images only) or `production_file` for production files; leave it out for other files (`default`).","operationId":"v1_public_async_upload_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"example":{"collection":"mockup","media":"(binary file)"},"schema":{"properties":{"collection":{"default":"default","description":"What the file is for.","enum":["default","mockup","production_file"],"type":"string"},"media":{"description":"The file. With `collection=mockup` it must be an image a preview can be made of: PNG, JPG (JPE, JFIF), GIF, TIFF, BMP, WebP, SVG, HEIC or AVIF, and at most 120 megapixels.","format":"binary","type":"string"}},"required":["media"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assetUrl":"https://secure.yoprint.com/api/store/your-team/mockup-design-asset/b0l2VJxwa3ppc7/view","collection":"mockup","created_at":"2026-11-03T09:30:00+00:00","custom_properties":[],"file_name":"front-logo.png","id":"b0l2VJxwa3ppc7","is_image":true,"mime_type":"image/png","name":"front-logo","position":1,"preview":{"large":"https://example.com/media/front-logo-1200.png","medium":"https://example.com/media/front-logo-800.png","small":"https://example.com/media/front-logo-250.png"},"previewUrl":"https://secure.yoprint.com/api/store/your-team/mockup-design-asset/b0l2VJxwa3ppc7/preview?size=preview","show_in_pdf":null,"size":182044,"source_media_id":null,"url":"https://example.com/media/front-logo.png?download=1","view_url":"https://example.com/media/front-logo.png"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A file attached to a record has extra fields for it: `job_id` (with `job_service` and the current approval fields), `job_preset_id` (a job preset's file, with `job_service`: the preset's service ids), `order_id`, `po_id` or `customer_id`.","properties":{"assetUrl":{"description":"Images that are unattached uploads or job mockups only: a signed link the mockup editor uses. It expires; don't store it.","type":"string"},"collection":{"description":"An upload is `default`, `mockup` or `production_file`. A file attached to a record can be in another collection of that record.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"description":"Saved properties such as `location` and `show_mockup`. An empty list `[]` when there are none.","type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The upload id. Pass it as `attachment[].id` to attach the file.","type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":"string"},"name":{"description":"The original file name without its extension.","type":"string"},"position":{"description":"The file's place in its list.","type":["integer","null"]},"preview":{"description":"Preview links `small`, `medium` and `large` (250, 800 and 1200 px). Images up to 10 MB are their own preview, so they have these at once; a larger image has them once `preview_state` is `ready`. Other files have null while they are unattached uploads; once attached, some records (such as jobs) give them links to a converted preview.","properties":{"large":{"type":"string"},"medium":{"type":"string"},"small":{"type":"string"}},"type":["object","null"]},"previewUrl":{"description":"Same images only: a signed preview link for the mockup editor. It expires; don't store it.","type":"string"},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up, or the converter could not read the original (missing, broken or unsupported); it is not retried. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"The file this one was copied from, when it is a copy. Always null on job and job preset files.","type":["string","null"]},"url":{"description":"A signed download link. It expires; don't store it.","type":"string"},"view_url":{"description":"A signed link to view the file. It expires; don't store it.","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/MediaUploadValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Upload a file","tags":["Uploads"],"x-yoprint-docs":{"errors":[{"fix":"Send the file as `media` in a multipart form.","status":422,"when":"`media` is missing or not a file, `collection` is not allowed, or the file is over the Free plan limit (`validation_failed`, with the field under `error.fields`)."},{"fix":"Send the file as a production file instead, or a smaller image.","status":422,"when":"A mockup is not one of the image formats above (`error.code` `mockup_type_not_allowed`), or an image is over 120 megapixels (`error.code` `image_not_allowed`); `error.message` is one sentence naming the limit."},{"fix":"Put the file in a .zip, or send a different file type.","status":422,"when":"The file is a web page, a script or a program, judged by its extension and by its detected type (for example .html, .js, .php, .py, .sh, .exe, .bat, .jar, .apk, .app, .dmg). `error.fields.media` says \"This type of file cannot be uploaded.\" (`validation_failed`)."},{"fix":"Keep files under 100 MB. Don't retry the same file.","status":413,"when":"The request is over 100 MB. The web server refuses it before YoPrint reads it, so the body is not JSON."}],"group":"Imports and exports","notes":["The `url` and `view_url` links are signed and expire. Keep the `id`, not the links.","Attach the upload soon after uploading it. An upload can be attached once; after that, it belongs to its record."],"permission":"Any member of the team.","related":["v1_public_async_upload_show","v1_public_async_upload_destroy","v2_public_order_media_attach"],"rules":["`media` is required and must be a file.","On the Free plan a file can be at most 5,240 KB. On paid plans the whole request (the file and the form around it) can be at most 100 MB.","`location` (text) and `show_mockup` (a boolean) are checked but not saved here; set them with the update operation."],"side_effects":["Stores the file. It stays until you attach or delete it; unattached uploads are not cleaned up automatically."]}}},"/v1/api/store/{team_slug}/async_upload/{hash_id}":{"delete":{"description":"Deletes a file. Use it to throw away an upload you no longer need.\n\nTo delete only if it is still unattached, send `cleanup_only=true`: if the file was attached in the meantime, nothing happens and the call still succeeds. Without it, the call deletes any file of your team, including one attached to a job, but not a job preset's file: remove that from the job preset in Settings.","operationId":"v1_public_async_upload_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The file's `id`, from the upload answer. A hash id; unique keys and document numbers are refused with 404.","example":"b0l2VJxwa3ppc7","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}},{"description":"`true`: delete only if the file is still an unattached upload.","in":"query","name":"cleanup_only","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"For a job file in open approvals: also remove it from every open job approval.","in":"query","name":"approval_request_action","required":false,"schema":{"enum":["remove_open_items"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete an uploaded file","tags":["Uploads"],"x-yoprint-docs":{"errors":[{"fix":"Remove the file from the job preset instead.","status":422,"when":"The file belongs to a job preset (`error.code` `validation_error`, \"This file belongs to a job preset. Remove it from the job preset in Settings.\"). Nothing is deleted."},{"fix":"Use the `id` the upload returned.","status":404,"when":"No file of this team has this id."},{"fix":"Read the file back before retrying.","status":500,"when":"The file could not be deleted (`delete_fail`, `message` null)."}],"group":"Imports and exports","notes":["Prefer `cleanup_only=true` when you clean up after a failed attach, so you never delete a file someone attached."],"permission":"Any member of the team.","related":["v1_public_async_upload_store"],"side_effects":["The file is soft-deleted: it disappears from YoPrint.","A job file in an open approval is deleted but stays in that approval, unless you send `approval_request_action=remove_open_items`.","With `remove_open_items`, the file is taken out of every open job approval it is in. An open approval left with no items is removed; the others are updated, and open Customer Portal pages are told to refresh.","With `remove_open_items`, or when no approval is open: a job file that past approvals refer to is kept for that history instead of being deleted."]}},"get":{"description":"Returns a file by id: its name, type, size and fresh signed links. It works for any file on your team, attached or not.","operationId":"v1_public_async_upload_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The file's `id`, from the upload answer. A hash id; unique keys and document numbers are refused with 404.","example":"b0l2VJxwa3ppc7","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"assetUrl":"https://secure.yoprint.com/api/store/your-team/mockup-design-asset/b0l2VJxwa3ppc7/view","collection":"mockup","created_at":"2026-11-03T09:30:00+00:00","custom_properties":[],"file_name":"front-logo.png","id":"b0l2VJxwa3ppc7","is_image":true,"mime_type":"image/png","name":"front-logo","position":1,"preview":{"large":"https://example.com/media/front-logo-1200.png","medium":"https://example.com/media/front-logo-800.png","small":"https://example.com/media/front-logo-250.png"},"previewUrl":"https://secure.yoprint.com/api/store/your-team/mockup-design-asset/b0l2VJxwa3ppc7/preview?size=preview","show_in_pdf":null,"size":182044,"source_media_id":null,"url":"https://example.com/media/front-logo.png?download=1","view_url":"https://example.com/media/front-logo.png"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A file attached to a record has extra fields for it: `job_id` (with `job_service` and the current approval fields), `job_preset_id` (a job preset's file, with `job_service`: the preset's service ids), `order_id`, `po_id` or `customer_id`.","properties":{"assetUrl":{"description":"Images that are unattached uploads or job mockups only: a signed link the mockup editor uses. It expires; don't store it.","type":"string"},"collection":{"description":"An upload is `default`, `mockup` or `production_file`. A file attached to a record can be in another collection of that record.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"description":"Saved properties such as `location` and `show_mockup`. An empty list `[]` when there are none.","type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The upload id. Pass it as `attachment[].id` to attach the file.","type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":"string"},"name":{"description":"The original file name without its extension.","type":"string"},"position":{"description":"The file's place in its list.","type":["integer","null"]},"preview":{"description":"Preview links `small`, `medium` and `large` (250, 800 and 1200 px). Images up to 10 MB are their own preview, so they have these at once; a larger image has them once `preview_state` is `ready`. Other files have null while they are unattached uploads; once attached, some records (such as jobs) give them links to a converted preview.","properties":{"large":{"type":"string"},"medium":{"type":"string"},"small":{"type":"string"}},"type":["object","null"]},"previewUrl":{"description":"Same images only: a signed preview link for the mockup editor. It expires; don't store it.","type":"string"},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up, or the converter could not read the original (missing, broken or unsupported); it is not retried. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"The file this one was copied from, when it is a copy. Always null on job and job preset files.","type":["string","null"]},"url":{"description":"A signed download link. It expires; don't store it.","type":"string"},"view_url":{"description":"A signed link to view the file. It expires; don't store it.","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get an uploaded file","tags":["Uploads"],"x-yoprint-docs":{"errors":[{"fix":"Use the `id` the upload returned.","status":404,"when":"No file of this team has this id."}],"group":"Imports and exports","permission":"Any member of the team.","related":["v1_public_async_upload_store"]}},"patch":{"description":"Use `PUT` to set these. `PATCH` is checked with the upload rules: it needs a `multipart/form-data` body with a `media` file (and, for `collection` `mockup`, an image), or it answers 422. The file is then ignored: only `location` and `show_mockup` are saved, as with `PUT`. A form value is text, so `show_mockup` must be `1` (or `0`) and is saved as the text `\"1\"`, not `true`.","operationId":"v1_public_async_upload_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The file's `id`, from the upload answer. A hash id; unique keys and document numbers are refused with 404.","example":"b0l2VJxwa3ppc7","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"properties":{"collection":{"description":"Optional. `mockup` requires `media` to be an image: PNG, JPG, GIF, TIFF, BMP, WebP, SVG, HEIC or AVIF.","enum":["default","mockup","production_file"],"type":"string"},"location":{"description":"Where the artwork goes, such as \"Front\".","type":"string"},"media":{"description":"Required, and ignored: any file.","format":"binary","type":"string"},"show_mockup":{"description":"`1` to show it on the mockup. `0` is ignored (it is not saved).","enum":["1","0"],"type":"string"}},"required":["media"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assetUrl":"https://secure.yoprint.com/api/store/your-team/mockup-design-asset/b0l2VJxwa3ppc7/view","collection":"mockup","created_at":"2026-11-03T09:30:00+00:00","custom_properties":{"location":"Front","show_mockup":true},"file_name":"front-logo.png","id":"b0l2VJxwa3ppc7","is_image":true,"mime_type":"image/png","name":"front-logo","position":1,"preview":{"large":"https://example.com/media/front-logo-1200.png","medium":"https://example.com/media/front-logo-800.png","small":"https://example.com/media/front-logo-250.png"},"previewUrl":"https://secure.yoprint.com/api/store/your-team/mockup-design-asset/b0l2VJxwa3ppc7/preview?size=preview","show_in_pdf":null,"size":182044,"source_media_id":null,"url":"https://example.com/media/front-logo.png?download=1","view_url":"https://example.com/media/front-logo.png"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A file attached to a record has extra fields for it: `job_id` (with `job_service` and the current approval fields), `job_preset_id` (a job preset's file, with `job_service`: the preset's service ids), `order_id`, `po_id` or `customer_id`.","properties":{"assetUrl":{"description":"Images that are unattached uploads or job mockups only: a signed link the mockup editor uses. It expires; don't store it.","type":"string"},"collection":{"description":"An upload is `default`, `mockup` or `production_file`. A file attached to a record can be in another collection of that record.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"description":"Saved properties such as `location` and `show_mockup`. An empty list `[]` when there are none.","type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The upload id. Pass it as `attachment[].id` to attach the file.","type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":"string"},"name":{"description":"The original file name without its extension.","type":"string"},"position":{"description":"The file's place in its list.","type":["integer","null"]},"preview":{"description":"Preview links `small`, `medium` and `large` (250, 800 and 1200 px). Images up to 10 MB are their own preview, so they have these at once; a larger image has them once `preview_state` is `ready`. Other files have null while they are unattached uploads; once attached, some records (such as jobs) give them links to a converted preview.","properties":{"large":{"type":"string"},"medium":{"type":"string"},"small":{"type":"string"}},"type":["object","null"]},"previewUrl":{"description":"Same images only: a signed preview link for the mockup editor. It expires; don't store it.","type":"string"},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up, or the converter could not read the original (missing, broken or unsupported); it is not retried. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"The file this one was copied from, when it is a copy. Always null on job and job preset files.","type":["string","null"]},"url":{"description":"A signed download link. It expires; don't store it.","type":"string"},"view_url":{"description":"A signed link to view the file. It expires; don't store it.","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/MediaUploadValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set an uploaded file's location or mockup flag with PATCH","tags":["Uploads"],"x-yoprint-docs":{"errors":[{"fix":"Put the file in a .zip, or send a different file type.","status":422,"when":"A new `media` file is a web page, a script or a program, judged by its extension and by its detected type (for example .html, .js, .php, .py, .sh, .exe, .bat, .jar, .apk, .app, .dmg). `error.fields.media` says \"This type of file cannot be uploaded.\" (`validation_failed`)."},{"fix":"Use `PUT` with JSON.","status":422,"when":"A value has the wrong type, or you used `PATCH` without a `media` file (`validation_failed`; `error.fields` names the field)."},{"fix":"Use the `id` the upload returned.","status":404,"when":"No file of this team has this id."}],"group":"Imports and exports","notes":["It works on any file of your team, including files already attached to a job."],"permission":"Any member of the team.","related":["v1_public_async_upload_show"],"rules":["`location` is text; `show_mockup` is a boolean."]}},"put":{"description":"Saves `location` and `show_mockup` on a file, as custom properties. Use `PUT` with a JSON body.\n\nOnly values that are not empty or false are saved: you can set `show_mockup` to `true` but not back to `false`, and you can't clear `location`.","operationId":"v1_public_async_upload_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The file's `id`, from the upload answer. A hash id; unique keys and document numbers are refused with 404.","example":"b0l2VJxwa3ppc7","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"location":"Front","show_mockup":true},"schema":{"properties":{"location":{"description":"Where the artwork goes, such as \"Front\".","type":"string"},"show_mockup":{"type":"boolean"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assetUrl":"https://secure.yoprint.com/api/store/your-team/mockup-design-asset/b0l2VJxwa3ppc7/view","collection":"mockup","created_at":"2026-11-03T09:30:00+00:00","custom_properties":{"location":"Front","show_mockup":true},"file_name":"front-logo.png","id":"b0l2VJxwa3ppc7","is_image":true,"mime_type":"image/png","name":"front-logo","position":1,"preview":{"large":"https://example.com/media/front-logo-1200.png","medium":"https://example.com/media/front-logo-800.png","small":"https://example.com/media/front-logo-250.png"},"previewUrl":"https://secure.yoprint.com/api/store/your-team/mockup-design-asset/b0l2VJxwa3ppc7/preview?size=preview","show_in_pdf":null,"size":182044,"source_media_id":null,"url":"https://example.com/media/front-logo.png?download=1","view_url":"https://example.com/media/front-logo.png"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A file attached to a record has extra fields for it: `job_id` (with `job_service` and the current approval fields), `job_preset_id` (a job preset's file, with `job_service`: the preset's service ids), `order_id`, `po_id` or `customer_id`.","properties":{"assetUrl":{"description":"Images that are unattached uploads or job mockups only: a signed link the mockup editor uses. It expires; don't store it.","type":"string"},"collection":{"description":"An upload is `default`, `mockup` or `production_file`. A file attached to a record can be in another collection of that record.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"description":"Saved properties such as `location` and `show_mockup`. An empty list `[]` when there are none.","type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The upload id. Pass it as `attachment[].id` to attach the file.","type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":"string"},"name":{"description":"The original file name without its extension.","type":"string"},"position":{"description":"The file's place in its list.","type":["integer","null"]},"preview":{"description":"Preview links `small`, `medium` and `large` (250, 800 and 1200 px). Images up to 10 MB are their own preview, so they have these at once; a larger image has them once `preview_state` is `ready`. Other files have null while they are unattached uploads; once attached, some records (such as jobs) give them links to a converted preview.","properties":{"large":{"type":"string"},"medium":{"type":"string"},"small":{"type":"string"}},"type":["object","null"]},"previewUrl":{"description":"Same images only: a signed preview link for the mockup editor. It expires; don't store it.","type":"string"},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up, or the converter could not read the original (missing, broken or unsupported); it is not retried. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"The file this one was copied from, when it is a copy. Always null on job and job preset files.","type":["string","null"]},"url":{"description":"A signed download link. It expires; don't store it.","type":"string"},"view_url":{"description":"A signed link to view the file. It expires; don't store it.","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/MediaUploadValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set an uploaded file's location or mockup flag","tags":["Uploads"],"x-yoprint-docs":{"errors":[{"fix":"Put the file in a .zip, or send a different file type.","status":422,"when":"A new `media` file is a web page, a script or a program, judged by its extension and by its detected type (for example .html, .js, .php, .py, .sh, .exe, .bat, .jar, .apk, .app, .dmg). `error.fields.media` says \"This type of file cannot be uploaded.\" (`validation_failed`)."},{"fix":"Use `PUT` with JSON.","status":422,"when":"A value has the wrong type, or you used `PATCH` without a `media` file (`validation_failed`; `error.fields` names the field)."},{"fix":"Use the `id` the upload returned.","status":404,"when":"No file of this team has this id."}],"group":"Imports and exports","notes":["It works on any file of your team, including files already attached to a job."],"permission":"Any member of the team.","related":["v1_public_async_upload_show"],"rules":["`location` is text; `show_mockup` is a boolean."]}}},"/v1/api/store/{team_slug}/available_identifier":{"get":{"description":"Returns the number the next record of a type will get, such as `SO1002` for the next sales order. It is a preview: nothing is reserved, and someone else may take the number first.\n\nNumbers are the prefix and the counter plus one, padded to 4 digits (`SO0042`); from 10,000 they get one leading zero (`SO010000`).\n\n| `type` | Prefix |\n| --- | --- |\n| `sales_order` | SO |\n| `quote` | QT |\n| `purchase_order` | PO |\n| `stock_transfer` | ST |\n| `stock_adjustment` | SA |\n| `general_defect` | DF |\n| `production_defect` | PD |","operationId":"v1_public_misc_available_identifier","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"example":"sales_order","in":"query","name":"type","required":true,"schema":{"enum":["sales_order","quote","purchase_order","stock_transfer","stock_adjustment","general_defect","production_defect"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"identifier":"SO1002"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"identifier":{"type":"string"}},"required":["identifier"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Preview the next document number","tags":["Document numbers"],"x-yoprint-docs":{"errors":[{"fix":"Send one of the listed types.","status":422,"when":"`type` is missing or not in the list (`validation_failed`; `error.fields` names the field)."}],"group":"Sales","notes":["Quotes are numbered from the sales order counter, so the next quote gets the number `type=sales_order` returns. `type=quote` reads a separate counter that quotes do not use.","To choose a number yourself, send it when you create the record instead."],"permission":"Any member of the team.","rules":["`type` is required and must be one of the values in the table."],"side_effects":["On a team that has never numbered this type, the first call starts its counter, so the first real number is 2, not 1."]}}},"/v1/api/store/{team_slug}/comment/{hash_id}/restore":{"patch":{"description":"Brings back a deleted comment. Restoring a comment that is not deleted does nothing and succeeds. Send no body.","operationId":"v1_public_comment_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The deleted comment's `id`. A hash id; unique keys and document numbers are refused with 404.","example":"JiDNJJ08el0QrD","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a deleted comment","tags":["Comments"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Use the deleted comment's `id`.","status":404,"when":"No comment of this team has this id."}],"group":"Sales","permission":"Any member of the team, for any comment on the team. It does not check who wrote the comment or whether you can see its order.","related":["v1_public_comment_destroy","v1_public_comment_show"],"side_effects":["People with the order open see the comment come back."]}}},"/v1/api/store/{team_slug}/comment/{id}":{"delete":{"description":"Deletes a comment. It is a soft delete: the comment is hidden from the order but kept, and `PATCH /v1/api/store/{team_slug}/comment/{hash_id}/restore` brings it back.","operationId":"v1_public_comment_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The comment's `id`. A hash id; unique keys and document numbers are refused with 404.","example":"JiDNJJ08el0QrD","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a comment","tags":["Comments"],"x-yoprint-docs":{"errors":[{"fix":"Use a comment `id` from the order's comment list.","status":404,"when":"No comment of this team has this id."}],"group":"Sales","notes":["Deleting a comment that is already deleted succeeds again."],"permission":"Any member of the team, for any comment on the team. It does not check who wrote the comment or whether you can see its order.","related":["v1_public_comment_restore"],"side_effects":["People with the order open see the comment disappear."]}},"get":{"description":"Returns one comment by id, whatever it is on: a sales order, a quote, a job or a purchase order. Deleted comments are returned too, with `trashed: true`.\n\nComments are internal notes for your team; customers never see them. To list or add comments, use the operations on the sales order, job or purchase order.","operationId":"v1_public_comment_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The comment's `id`. A hash id; unique keys and document numbers are refused with 404.","example":"JiDNJJ08el0QrD","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"comment":"<p>Customer approved the blue ink.</p>","created_at":"2026-11-03T09:30:00+00:00","id":"JiDNJJ08el0QrD","is_edited":false,"job_id":null,"job_name":null,"job_scoped_id":null,"order_id":"V4keXwwxMQyXw7","purchase_order_id":null,"trashed":false,"type":"user_comment","updated_at":"2026-11-03T09:30:00+00:00","user_id":"VG7s3tFzyQbO2N"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"comment":{"description":"The comment as HTML.","type":"string"},"created_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"is_edited":{"description":"True once the comment changed after it was written. Deleting and restoring also count.","type":"boolean"},"job_id":{"description":"Set for comments on a job.","type":["string","null"]},"job_name":{"type":["string","null"]},"job_scoped_id":{"type":["string","null"]},"order_id":{"description":"Set for comments on a sales order, a quote or one of their jobs.","type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"trashed":{"description":"True when the comment is deleted.","type":"boolean"},"type":{"description":"`user_comment` for a comment written in YoPrint. `user` for one a team member sent by replying to a YoPrint email.","type":"string"},"updated_at":{"format":"date-time","type":"string"},"user_id":{"description":"The hash id of the team member who wrote it.","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a comment","tags":["Comments"],"x-yoprint-docs":{"errors":[{"fix":"Use a comment `id` from the order's comment list.","status":404,"when":"No comment of this team has this id."}],"group":"Sales","permission":"Any member of the team, for any comment on the team. It does not check who wrote the comment or whether you can see its order.","related":["v1_public_comment_update_patch","v1_public_comment_destroy","v2_public_order_comment_index"]}},"patch":{"description":"Use `PUT` to edit a comment. `PATCH` does the same but does not check `comment`: an empty `comment` is saved, and a missing one changes nothing.","operationId":"v1_public_comment_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The comment's `id`. A hash id; unique keys and document numbers are refused with 404.","example":"JiDNJJ08el0QrD","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"comment":"<p>Customer approved the navy ink instead.</p>"},"schema":{"properties":{"comment":{"description":"The new text, as HTML. Not checked.","type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":{"comment":"<p>Customer approved the navy ink instead.</p>","created_at":"2026-11-03T09:30:00+00:00","id":"JiDNJJ08el0QrD","is_edited":true,"job_id":null,"job_name":null,"job_scoped_id":null,"order_id":"V4keXwwxMQyXw7","purchase_order_id":null,"trashed":false,"type":"user_comment","updated_at":"2026-11-03T10:05:00+00:00","user_id":"VG7s3tFzyQbO2N"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"comment":{"description":"The comment as HTML.","type":"string"},"created_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"is_edited":{"description":"True once the comment changed after it was written. Deleting and restoring also count.","type":"boolean"},"job_id":{"description":"Set for comments on a job.","type":["string","null"]},"job_name":{"type":["string","null"]},"job_scoped_id":{"type":["string","null"]},"order_id":{"description":"Set for comments on a sales order, a quote or one of their jobs.","type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"trashed":{"description":"True when the comment is deleted.","type":"boolean"},"type":{"description":"`user_comment` for a comment written in YoPrint. `user` for one a team member sent by replying to a YoPrint email.","type":"string"},"updated_at":{"format":"date-time","type":"string"},"user_id":{"description":"The hash id of the team member who wrote it.","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Edit a comment without checks","tags":["Comments"],"x-yoprint-docs":{"errors":[{"fix":"Use a comment `id` from the order's comment list.","status":404,"when":"No comment of this team has this id."}],"group":"Sales","notes":["The HTML is stored as sent. Escape anything that came from untrusted input before you send it."],"permission":"Any member of the team, for any comment on the team. It does not check who wrote the comment or whether you can see its order.","related":["v1_public_comment_show"],"rules":["With `PUT`, `comment` is required and must be text.","Only `comment` can change. The author and what it is on stay the same."],"side_effects":["People with the order, job or purchase order open see the edit live. No email."]}},"put":{"description":"Replaces a comment's text. Send the whole new text as HTML in `comment`. Returns the comment; `is_edited` becomes true when the text changed. Sending the same text changes nothing.\n\nEditing does not notify anyone by email; people with the order open see the change live.","operationId":"v1_public_comment_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The comment's `id`. A hash id; unique keys and document numbers are refused with 404.","example":"JiDNJJ08el0QrD","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"comment":"<p>Customer approved the navy ink instead.</p>"},"schema":{"properties":{"comment":{"description":"The new text, as HTML. It replaces the old text.","type":"string"}},"required":["comment"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"comment":"<p>Customer approved the navy ink instead.</p>","created_at":"2026-11-03T09:30:00+00:00","id":"JiDNJJ08el0QrD","is_edited":true,"job_id":null,"job_name":null,"job_scoped_id":null,"order_id":"V4keXwwxMQyXw7","purchase_order_id":null,"trashed":false,"type":"user_comment","updated_at":"2026-11-03T10:05:00+00:00","user_id":"VG7s3tFzyQbO2N"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"comment":{"description":"The comment as HTML.","type":"string"},"created_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"is_edited":{"description":"True once the comment changed after it was written. Deleting and restoring also count.","type":"boolean"},"job_id":{"description":"Set for comments on a job.","type":["string","null"]},"job_name":{"type":["string","null"]},"job_scoped_id":{"type":["string","null"]},"order_id":{"description":"Set for comments on a sales order, a quote or one of their jobs.","type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"trashed":{"description":"True when the comment is deleted.","type":"boolean"},"type":{"description":"`user_comment` for a comment written in YoPrint. `user` for one a team member sent by replying to a YoPrint email.","type":"string"},"updated_at":{"format":"date-time","type":"string"},"user_id":{"description":"The hash id of the team member who wrote it.","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Edit a comment","tags":["Comments"],"x-yoprint-docs":{"errors":[{"fix":"Send the full new text in `comment`.","status":422,"when":"`comment` is missing or not text (`PUT`) (`validation_failed`; `error.fields` names the field)."},{"fix":"Use a comment `id` from the order's comment list.","status":404,"when":"No comment of this team has this id."}],"group":"Sales","notes":["The HTML is stored as sent. Escape anything that came from untrusted input before you send it."],"permission":"Any member of the team, for any comment on the team. It does not check who wrote the comment or whether you can see its order.","related":["v1_public_comment_show"],"rules":["With `PUT`, `comment` is required and must be text.","Only `comment` can change. The author and what it is on stay the same."],"side_effects":["People with the order, job or purchase order open see the edit live. No email."]}}},"/v1/api/store/{team_slug}/contact/{id}":{"delete":{"description":"Deletes a customer or vendor contact. The primary contact can't be deleted: make another contact primary first.","operationId":"v1_public_contact_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The contact's id: a customer or vendor contact. A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a contact by id","tags":["Contacts"],"x-yoprint-docs":{"errors":[{"fix":"Set another contact as primary first.","status":422,"when":"The contact is primary (`error.code` `delete_fail`, \"The primary contact can't be removed. Set another contact as primary first.\"), or synced from Shopify (`validation_error`)."},{"fix":"Check the id.","status":404,"when":"No live contact with this id. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_contact_primary","v1_public_customer_contact_restore"],"rules":["Contacts synced from Shopify are read-only (422)."],"side_effects":["Sends the `customer_contact.deleted` webhook (this route sends it for vendor contacts too).","For a customer contact, removes the Customer Portal access it gave for its customer, and any access denial with it. When the portal account then has no active access to any customer, its signed-in sessions end."]}},"get":{"description":"Returns one live contact, of a customer (`customer_id`, `send_invoice`) or of a vendor (`vendor_id`). Use it when you have a contact id, for example from a sales order, but not its owner.","operationId":"v1_public_contact_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The contact's id: a customer or vendor contact. A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a contact by id","tags":["Contacts"],"x-yoprint-docs":{"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_contact_show","v1_public_vendor_contact_show"]}},"patch":{"description":"Changes the fields you send on a customer or vendor contact, and returns it.\n\nUse `PUT`: it checks the fields. `PATCH` takes the same body but checks nothing. Prefer Update a customer contact or Update a vendor contact when you know the owner.\n\nFor a customer contact that gives someone Customer Portal access, a changed email moves that access, as Update a customer contact describes; send `portal_email_scope` and `portal_reconnect_confirmed` the same way.","operationId":"v1_public_contact_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The contact's id: a customer or vendor contact. A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"email":"alex@example.com","first_name":"Alex"},"schema":{"additionalProperties":false,"properties":{"default_receive_sms":{"type":"boolean"},"email":{"format":"email","type":"string"},"fax":{"description":"Checked as a real number for `fax_country`.","type":"string"},"fax_country":{"type":"string"},"first_name":{"description":"The contact's first name.","type":"string"},"last_name":{"description":"The contact's last name.","type":"string"},"phone":{"description":"Send `phone_country` with it.","type":"string"},"phone_country":{"description":"Two-letter country code of `phone`, such as `US`. Required with `phone`.","type":"string"},"portal_email_scope":{"description":"Customer contacts only. Read only when you change the email of a contact that gives someone Customer Portal access. `all_customers` (the default) changes that portal account's sign-in email, and the email of its contacts on every customer it can open. `this_customer` moves only this customer's access to the account for the new email. Required when the account can open more than one customer.","enum":["all_customers","this_customer"],"type":"string"},"portal_reconnect_confirmed":{"description":"Customer contacts only. Send `true` to confirm moving this contact's Customer Portal access to the account that already uses the new email. Defaults to false.","type":"boolean"},"send_invoice":{"description":"Customer contacts.","type":"boolean"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a contact by id (PATCH)","tags":["Contacts"],"x-yoprint-docs":{"errors":[{"fix":"Change Shopify contacts in Shopify.","status":422,"when":"The contact is synced from Shopify (`validation_error`)."},{"fix":"Send the country code with the number.","status":422,"when":"A phone is not valid for its country, or on a customer contact `portal_email_scope` or `portal_reconnect_confirmed` has a wrong value. `error.code` is `validation_failed`."},{"fix":"Update the existing contact instead, or use another email.","status":409,"when":"Another live contact of this customer already has this email, ignoring case and surrounding spaces (`error.code` `customer_portal_duplicate_contact_email`, \"This customer already has a contact with that email. Edit the existing contact or use a different email.\")."},{"fix":"Send a valid email of at most 191 characters.","status":422,"when":"On a live customer, the email is longer than 191 characters or is not a valid address (`error.code` `customer_portal_email_invalid`, \"Enter a valid email address using supported characters.\")."},{"fix":"Send `portal_email_scope`: `all_customers` or `this_customer`.","status":409,"when":"The contact gives Customer Portal access to an account that can open several customers, and `portal_email_scope` was not sent (`error.code` `customer_portal_email_scope_required`)."},{"fix":"Send `portal_reconnect_confirmed: true` to move the access to that account, or use another email.","status":409,"when":"The new email already belongs to another Customer Portal account and `portal_reconnect_confirmed` is not `true` (`customer_portal_email_reconnect_required`), or that account is disabled or deleted (`customer_portal_account_unavailable`), or it already has another contact on this customer (`customer_portal_duplicate_contact_email`)."},{"fix":"Ask a member who can update those customers, or send `portal_email_scope: this_customer`.","status":403,"when":"The change moves portal access on a customer your role can't update: you need Manage Customers \"Manage All\", or \"Manage Assigned to User\" and to be assigned to every customer the change covers. This 403 has a short body, `{\"message\": \"You need permission to update every linked customer.\"}`."},{"fix":"Check the id.","status":404,"when":"No live contact with this id. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team. Moving the Customer Portal access of a customer contact (a changed email) also needs Manage Customers on the customers it covers.","related":["v1_public_customer_contact_update_patch","v1_public_vendor_contact_update_patch"],"rules":["`is_external` and `external_type` are ignored: sending them (for example a value you read back) is not refused and changes nothing. Only the Shopify sync sets them.","Contacts synced from Shopify are read-only (422 \"Shopify-managed customer contacts are read-only. Manage changes from Shopify.\").","Only the contact itself is checked: unlike Update a customer contact, this route doesn't refuse contacts of Shopify or system customers.","`send_invoice` and `default_receive_sms` are saved but not checked here, even with `PUT`: send JSON booleans.","For a customer contact, `portal_email_scope` and `portal_reconnect_confirmed` are checked with `PUT` and `PATCH` alike.","`is_primary` is not changed here.","Customer contacts: on a live customer (not a system or Shopify customer) a contact's email is saved trimmed and in lower case, and two live contacts of the customer can't have the same email (compared the same way). Other customers may use the same email.","Customer contacts: changing the email of a contact that gives someone Customer Portal access moves that access with it: see `portal_email_scope` and `portal_reconnect_confirmed`. Sending `email: \"\"` clears the email and removes the contact's portal access for this customer.","To clear a text field, send an empty string; `null` is ignored (it is dropped before the request is read)."],"side_effects":["For a customer contact, sends the `customer_contact.updated` webhook.","Customer contacts: portal access moves with a changed email. With `all_customers` and no other account on the new email, the account's sign-in email changes, its password is cleared, its signed-in sessions end, its contacts on other customers get the same email (without webhooks), and the old address is emailed that the sign-in email changed. Otherwise the access (only this customer's with `this_customer`) moves to the account that uses the new email, which is created, invited, when there is none.","Customer contacts: when the contact's email already belongs to a Customer Portal account on your team that can't open this customer yet, saving the contact gives that account access to this customer (active when the account is set up with a verified email or a password, invited otherwise). No email is sent."]}},"put":{"description":"Changes the fields you send on a customer or vendor contact, and returns it.\n\nUse `PUT`: it checks the fields. `PATCH` takes the same body but checks nothing. Prefer Update a customer contact or Update a vendor contact when you know the owner.\n\nFor a customer contact that gives someone Customer Portal access, a changed email moves that access, as Update a customer contact describes; send `portal_email_scope` and `portal_reconnect_confirmed` the same way.","operationId":"v1_public_contact_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The contact's id: a customer or vendor contact. A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"email":"alex@example.com","first_name":"Alex"},"schema":{"additionalProperties":false,"properties":{"default_receive_sms":{"type":"boolean"},"email":{"format":"email","type":"string"},"fax":{"description":"Checked as a real number for `fax_country`.","type":"string"},"fax_country":{"type":"string"},"first_name":{"description":"The contact's first name.","type":"string"},"last_name":{"description":"The contact's last name.","type":"string"},"phone":{"description":"Send `phone_country` with it.","type":"string"},"phone_country":{"description":"Two-letter country code of `phone`, such as `US`. Required with `phone`.","type":"string"},"portal_email_scope":{"description":"Customer contacts only. Read only when you change the email of a contact that gives someone Customer Portal access. `all_customers` (the default) changes that portal account's sign-in email, and the email of its contacts on every customer it can open. `this_customer` moves only this customer's access to the account for the new email. Required when the account can open more than one customer.","enum":["all_customers","this_customer"],"type":"string"},"portal_reconnect_confirmed":{"description":"Customer contacts only. Send `true` to confirm moving this contact's Customer Portal access to the account that already uses the new email. Defaults to false.","type":"boolean"},"send_invoice":{"description":"Customer contacts.","type":"boolean"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a contact by id","tags":["Contacts"],"x-yoprint-docs":{"errors":[{"fix":"Change Shopify contacts in Shopify.","status":422,"when":"The contact is synced from Shopify (`validation_error`)."},{"fix":"Send the country code with the number.","status":422,"when":"A phone is not valid for its country, or on a customer contact `portal_email_scope` or `portal_reconnect_confirmed` has a wrong value. `error.code` is `validation_failed`."},{"fix":"Update the existing contact instead, or use another email.","status":409,"when":"Another live contact of this customer already has this email, ignoring case and surrounding spaces (`error.code` `customer_portal_duplicate_contact_email`, \"This customer already has a contact with that email. Edit the existing contact or use a different email.\")."},{"fix":"Send a valid email of at most 191 characters.","status":422,"when":"On a live customer, the email is longer than 191 characters or is not a valid address (`error.code` `customer_portal_email_invalid`, \"Enter a valid email address using supported characters.\")."},{"fix":"Send `portal_email_scope`: `all_customers` or `this_customer`.","status":409,"when":"The contact gives Customer Portal access to an account that can open several customers, and `portal_email_scope` was not sent (`error.code` `customer_portal_email_scope_required`)."},{"fix":"Send `portal_reconnect_confirmed: true` to move the access to that account, or use another email.","status":409,"when":"The new email already belongs to another Customer Portal account and `portal_reconnect_confirmed` is not `true` (`customer_portal_email_reconnect_required`), or that account is disabled or deleted (`customer_portal_account_unavailable`), or it already has another contact on this customer (`customer_portal_duplicate_contact_email`)."},{"fix":"Ask a member who can update those customers, or send `portal_email_scope: this_customer`.","status":403,"when":"The change moves portal access on a customer your role can't update: you need Manage Customers \"Manage All\", or \"Manage Assigned to User\" and to be assigned to every customer the change covers. This 403 has a short body, `{\"message\": \"You need permission to update every linked customer.\"}`."},{"fix":"Check the id.","status":404,"when":"No live contact with this id. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team. Moving the Customer Portal access of a customer contact (a changed email) also needs Manage Customers on the customers it covers.","related":["v1_public_customer_contact_update_patch","v1_public_vendor_contact_update_patch"],"rules":["`is_external` and `external_type` are ignored: sending them (for example a value you read back) is not refused and changes nothing. Only the Shopify sync sets them.","Contacts synced from Shopify are read-only (422 \"Shopify-managed customer contacts are read-only. Manage changes from Shopify.\").","Only the contact itself is checked: unlike Update a customer contact, this route doesn't refuse contacts of Shopify or system customers.","`send_invoice` and `default_receive_sms` are saved but not checked here, even with `PUT`: send JSON booleans.","For a customer contact, `portal_email_scope` and `portal_reconnect_confirmed` are checked with `PUT` and `PATCH` alike.","`is_primary` is not changed here.","Customer contacts: on a live customer (not a system or Shopify customer) a contact's email is saved trimmed and in lower case, and two live contacts of the customer can't have the same email (compared the same way). Other customers may use the same email.","Customer contacts: changing the email of a contact that gives someone Customer Portal access moves that access with it: see `portal_email_scope` and `portal_reconnect_confirmed`. Sending `email: \"\"` clears the email and removes the contact's portal access for this customer.","To clear a text field, send an empty string; `null` is ignored (it is dropped before the request is read)."],"side_effects":["For a customer contact, sends the `customer_contact.updated` webhook.","Customer contacts: portal access moves with a changed email. With `all_customers` and no other account on the new email, the account's sign-in email changes, its password is cleared, its signed-in sessions end, its contacts on other customers get the same email (without webhooks), and the old address is emailed that the sign-in email changed. Otherwise the access (only this customer's with `this_customer`) moves to the account that uses the new email, which is created, invited, when there is none.","Customer contacts: when the contact's email already belongs to a Customer Portal account on your team that can't open this customer yet, saving the contact gives that account access to this customer (active when the account is set up with a verified email or a password, invited otherwise). No email is sent."]}}},"/v1/api/store/{team_slug}/csv/template/customer":{"put":{"description":"Returns `customer_import_template.csv`: the header row and one example row for a customer CSV import. It is a file, not JSON.\n\nColumns: `customer_name`, `customer_website`, `customer_internal_notes`, `customer_tax_exempt` (`TRUE` or `FALSE`), `customer_resale_number`, `contact_first_name`, `contact_last_name`, `contact_email`, `contact_phone`, `contact_phone_country`, `contact_fax`, `contact_fax_country`, then billing and shipping addresses. Each address has a single-line column (`billing_address`, `shipping_address`) for a whole address in one cell, and structured columns (`*_address1`, `*_address2`, `*_city`, `*_state`, `*_postcode`, `*_country_code`). Fill one form or the other.\n\nCustomer CSV files are imported in the YoPrint web app (Import Portal). The public API has no customer CSV upload; to create customers from your own system, use the customer operations.","operationId":"v1_public_csv_template_customer","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"format":"binary","type":"string"}}},"description":"The template, UTF-8 with a byte order mark, sent as an attachment named customer_import_template.csv.","headers":{"Content-Disposition":{"description":"attachment; filename=\"<name>.csv\"","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download the customer CSV template","tags":["CSV imports"],"x-yoprint-docs":{"body":"none","group":"Imports and exports","notes":["The route uses `PUT` but sends nothing back to the server and changes nothing. Send no body.","The example row is sample data. Delete it before you import."],"permission":"Any member of the team.","related":["v1_public_customer_store","v1_public_customer_upsert","v1_public_csv_template_vendor","v1_public_csv_template_simple_product"]}}},"/v1/api/store/{team_slug}/csv/template/service_pricing":{"put":{"description":"Returns `service_pricing_template.csv`: an example price table for one service, with three options (`1 Color`, `2 Color`, `4 Color`) and price breaks at 1, 10 and 30. It is a file, not JSON. Fill it in and upload it with `POST /v1/api/store/{team_slug}/imports/csv`.\n\nThe first column is `qty/type`: the quantity where each price break starts. Every other column is one option of the service (for example `1 Color`, `2 Color`), and each cell is that option's price at that quantity. A cell can hold two prices, `first|additional` (for example `10.00|11.00`): the price for the first print location, then the price for each additional location.","operationId":"v1_public_csv_template_service_pricing","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"format":"binary","type":"string"}}},"description":"The template, UTF-8 with a byte order mark, sent as an attachment named service_pricing_template.csv.","headers":{"Content-Disposition":{"description":"attachment; filename=\"<name>.csv\"","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download the service pricing CSV template","tags":["CSV imports"],"x-yoprint-docs":{"body":"none","group":"Imports and exports","notes":["The route uses `PUT` but changes nothing. Send no body.","The rules each cell must follow are on the upload operation."],"permission":"Any member of the team.","related":["v1_public_imports_csv_store"]}}},"/v1/api/store/{team_slug}/csv/template/simple_product":{"put":{"description":"Returns `simple_product_import_template.csv`: the header row and two example rows for a custom simple product CSV import. It is a file, not JSON.\n\nColumns: `brand`, `title`, `description`, `supplier_code`, `weight`, `price`. Keep these header names: the Import Portal matches columns to fields by their exact names. `brand` + `title` + `supplier_code` identify a product: two rows with the same three values are a duplicate.\n\nProduct CSV files are imported in the YoPrint web app (Import Portal). The public API has no product CSV upload; to create products from your own system, use the product operations.","operationId":"v1_public_csv_template_simple_product","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"format":"binary","type":"string"}}},"description":"The template, UTF-8 with a byte order mark, sent as an attachment named simple_product_import_template.csv.","headers":{"Content-Disposition":{"description":"attachment; filename=\"<name>.csv\"","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download the simple product CSV template","tags":["CSV imports"],"x-yoprint-docs":{"body":"none","group":"Imports and exports","notes":["The route uses `PUT` but changes nothing. Send no body.","The example rows are sample data. Delete them before you import."],"permission":"Any member of the team.","related":["v1_public_products_store","v1_public_csv_template_variant_product"]}}},"/v1/api/store/{team_slug}/csv/template/variant_product":{"put":{"description":"Returns `variant_product_import_template.csv`: the header row and two example rows for a custom variant product CSV import. It is a file, not JSON.\n\nOne row is one variant (one size and color). Rows with the same `supplier_style_code`, `brand` and `title` belong to one product. Columns: `supplier_style_code`, `brand`, `title`, `description`, `supplier_code` (the variant's own code), `weight` (pounds), `size_id`, `size_label`, `color_id`, `color_label`, `color_hex`, `price`. Keep these header names: the Import Portal matches columns to fields by their exact names.\n\nProduct CSV files are imported in the YoPrint web app (Import Portal). The public API has no product CSV upload.","operationId":"v1_public_csv_template_variant_product","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"format":"binary","type":"string"}}},"description":"The template, UTF-8 with a byte order mark, sent as an attachment named variant_product_import_template.csv.","headers":{"Content-Disposition":{"description":"attachment; filename=\"<name>.csv\"","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download the variant product CSV template","tags":["CSV imports"],"x-yoprint-docs":{"body":"none","group":"Imports and exports","notes":["The route uses `PUT` but changes nothing. Send no body.","The example rows are sample data. Delete them before you import."],"permission":"Any member of the team.","related":["v1_public_products_store","v1_public_product_variant_store","v1_public_csv_template_simple_product"]}}},"/v1/api/store/{team_slug}/csv/template/vendor":{"put":{"description":"Returns `vendor_import_template.csv`: the header row and one example row for a vendor CSV import. It is a file, not JSON.\n\nColumns: `vendor_name`, `vendor_website`, `vendor_internal_notes`, `vendor_default_vendor_note`, `vendor_account_number`, `contact_first_name`, `contact_last_name`, `contact_email`, `contact_phone`, `contact_phone_country`, `contact_fax`, `contact_fax_country`.\n\nVendor CSV files are imported in the YoPrint web app (Import Portal). The public API has no vendor CSV upload.","operationId":"v1_public_csv_template_vendor","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"format":"binary","type":"string"}}},"description":"The template, UTF-8 with a byte order mark, sent as an attachment named vendor_import_template.csv.","headers":{"Content-Disposition":{"description":"attachment; filename=\"<name>.csv\"","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download the vendor CSV template","tags":["CSV imports"],"x-yoprint-docs":{"body":"none","group":"Imports and exports","notes":["The route uses `PUT` but changes nothing. Send no body.","The example row is sample data. Delete it before you import."],"permission":"Any member of the team.","related":["v1_public_vendor_store","v1_public_csv_template_customer"]}}},"/v1/api/store/{team_slug}/current_user_feed":{"get":{"description":"Lists your notifications on this team, newest first: activity that concerns you, such as new comments, customer replies, payments received and approvals answered.\n\n**By default only unseen, unarchived items are returned.** Send `not_seen_yet=0` to include seen items, and `show_archive=1` to include archived ones too (it adds them; it does not return only archived items). The page size is your team's list size setting (50 unless changed).\n\nCustomer Portal payment notifications (`type` `customer_payment`) are listed only when your role may see that customer's finances; others are left out of the page and of the total.","operationId":"v1_public_current_user_feed_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"`1` (default): only unseen items. `0`: seen and unseen.","in":"query","name":"not_seen_yet","required":false,"schema":{"default":1,"enum":[0,1],"type":"integer"}},{"description":"`0` (default): leave out archived items. `1`: include them.","in":"query","name":"show_archive","required":false,"schema":{"default":0,"enum":[0,1],"type":"integer"}},{"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"activity":{"action":"new_comment","created_at":"2026-11-03T09:30:00+00:00","id":"r5rAJkp7z5ZNZI","message_key":"order.new_comment","object":{"comment":{"comment":"Customer approved the blue ink.","id":"JiDNJJ08el0QrD"},"order":{"id":"V4keXwwxMQyXw7","object_type":"sales_order","quote":false,"scoped_id":"SO1001"},"team":{"id":"1ulms05RCQN3k2","name":"Example Print Shop"},"user":{"avatar_url":"https://example.com/avatar.png","id":"VG7s3tFzyQbO2N","name":"Alex Rivera"}},"team":{"id":"OwgPxM73OKqou3","name":"Example Print Shop","slug":"your-team"},"type":"order"},"archive":false,"created_at":"2026-11-03T09:30:00+00:00","id":"H3w5wUZaIrCb52","seen":false}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"activity":{"additionalProperties":true,"description":"What happened.","properties":{"action":{"description":"What happened. For `customer_payment`: `dispute_opened`, `dispute_under_review`, `dispute_won`, `funds_withheld`, `chargeback_confirmed`, `payment_reversed`, `payment_needs_attention`, `deadline_approaching`, `deadline_overdue`, `funds_released`, `funds_restored`, `case_won_awaiting_funds`, `payment_resolved`, `provider_refund_applied` or `provider_refund_failed`; `payment_access_changed` when you can no longer see that payment.","type":"string"},"created_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"message_key":{"description":"Identifies the kind of notification, for your own wording: `<type>.<action>`, such as `order.new_comment`.","type":"string"},"object":{"additionalProperties":true,"description":"The details, which depend on the kind: for example the order, the comment and who wrote it (`user`: `id`, `name`, `avatar_url`). An empty array `[]` when there are none. For `customer_payment`, the payment as it was then (`payment`, with the orders it touched in `payment.affected_orders`, limited to the ones you may see); `[]` when you can no longer see that payment.","type":["object","array"]},"team":{"properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"}},"type":"object"},"type":{"description":"What the notification is about, such as `order`. `customer_payment` for Customer Portal payment events (disputes, chargebacks, refunds and holds).","type":"string"}},"type":"object"},"archive":{"type":"boolean"},"created_at":{"format":"date-time","type":"string"},"id":{"description":"The feed item id. Use it with the mark operations.","type":"string"},"seen":{"type":"boolean"}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List your notifications","tags":["Notifications"],"x-yoprint-docs":{"errors":[{"fix":"Send `1` or `0`.","status":422,"when":"`not_seen_yet` or `show_archive` is not `0` or `1` (`validation_failed`; `error.fields` names the field)."}],"group":"Messages and activity","permission":"Your own feed only: the key's owner. Payment notifications need more, see the rules.","related":["v1_public_current_user_feed_seen","v1_public_current_user_feed_mark_all_as_seen","v1_public_current_user_feed_archive"],"rules":["`not_seen_yet` and `show_archive` take `1` or `0`. `true` and `false` are refused.","A `customer_payment` notification is listed for the team owner, or for a role with View Customer Sales Aggregates and Manage Customers (\"Manage All\", or \"Manage Assigned to User\" when the customer is assigned to you). Its `payment.affected_orders` lists only the orders you may see, and none without View Sales Order Pricing.","Access is checked again for each row: if you lose access after a payment notification was listed, it comes back with `action` `payment_access_changed`, `message_key` `customer_payment.payment_access_changed` and `object` `[]`.","A key whose user is no longer a member of the team gets an empty list."]}}},"/v1/api/store/{team_slug}/current_user_feed/archive":{"put":{"description":"Archives the listed notifications, which hides them from the default list. It does not mark them as seen. Send a JSON **array** of `{id}` objects as the whole body.","operationId":"v1_public_current_user_feed_archive","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"H3w5wUZaIrCb52"},{"id":"I2jYDEbcQRl0AW"}],"schema":{"description":"The feed items to change: a JSON array of `{id}` objects, not an object.","items":{"properties":{"id":{"description":"A feed item id.","type":"string"}},"required":["id"],"type":"object"},"minItems":1,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Archive notifications","tags":["Notifications"],"x-yoprint-docs":{"errors":[{"fix":"Send ids from the feed list.","status":422,"when":"An item has no `id`, or an id is not valid (`validation_failed`; `error.fields` names the field)."},{"fix":"Send at least one item. The message is misleading: nothing is wrong with your key.","status":500,"when":"The list is empty, or the body is missing or `{}`: `{\"status\": 500, \"success\": false, \"error\": {\"code\": \"invalid_user\", \"message\": \"Current Auth User is not valid!\"}}`."}],"group":"Messages and activity","notes":["Ids that are not yours are skipped without an error.","Only your own feed changes; other people's feeds stay as they are."],"permission":"Your own feed only.","related":["v1_public_current_user_feed_unarchive","v1_public_current_user_feed_mark_all_as_archive"]}}},"/v1/api/store/{team_slug}/current_user_feed/mark_all_as_archive":{"put":{"description":"Archives every unarchived notification in your feed on this team, and marks them seen. Send no body.","operationId":"v1_public_current_user_feed_mark_all_as_archive","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Archive all your notifications","tags":["Notifications"],"x-yoprint-docs":{"body":"none","group":"Messages and activity","notes":["Unlike archiving single items, this also marks them seen."],"permission":"Your own feed only.","related":["v1_public_current_user_feed_archive","v1_public_current_user_feed_mark_all_as_seen"]}}},"/v1/api/store/{team_slug}/current_user_feed/mark_all_as_seen":{"put":{"description":"Marks every unseen notification in your feed on this team as seen. Send no body.","operationId":"v1_public_current_user_feed_mark_all_as_seen","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Mark all your notifications as seen","tags":["Notifications"],"x-yoprint-docs":{"body":"none","group":"Messages and activity","permission":"Your own feed only.","related":["v1_public_current_user_feed_seen","v1_public_current_user_feed_mark_all_as_archive"]}}},"/v1/api/store/{team_slug}/current_user_feed/seen":{"put":{"description":"Marks the listed notifications as seen. They then drop out of the default list. Send a JSON **array** of `{id}` objects as the whole body.","operationId":"v1_public_current_user_feed_seen","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"H3w5wUZaIrCb52"},{"id":"I2jYDEbcQRl0AW"}],"schema":{"description":"The feed items to change: a JSON array of `{id}` objects, not an object.","items":{"properties":{"id":{"description":"A feed item id.","type":"string"}},"required":["id"],"type":"object"},"minItems":1,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Mark notifications as seen","tags":["Notifications"],"x-yoprint-docs":{"errors":[{"fix":"Send ids from the feed list.","status":422,"when":"An item has no `id`, or an id is not valid (`validation_failed`; `error.fields` names the field)."},{"fix":"Send at least one item. The message is misleading: nothing is wrong with your key.","status":500,"when":"The list is empty, or the body is missing or `{}`: `{\"status\": 500, \"success\": false, \"error\": {\"code\": \"invalid_user\", \"message\": \"Current Auth User is not valid!\"}}`."}],"group":"Messages and activity","notes":["Ids that are not yours are skipped without an error.","Only your own feed changes; other people's feeds stay as they are."],"permission":"Your own feed only.","related":["v1_public_current_user_feed_unseen","v1_public_current_user_feed_mark_all_as_seen"]}}},"/v1/api/store/{team_slug}/current_user_feed/unarchive":{"put":{"description":"Moves the listed notifications out of the archive. Send a JSON **array** of `{id}` objects as the whole body.","operationId":"v1_public_current_user_feed_unarchive","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"H3w5wUZaIrCb52"},{"id":"I2jYDEbcQRl0AW"}],"schema":{"description":"The feed items to change: a JSON array of `{id}` objects, not an object.","items":{"properties":{"id":{"description":"A feed item id.","type":"string"}},"required":["id"],"type":"object"},"minItems":1,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Unarchive notifications","tags":["Notifications"],"x-yoprint-docs":{"errors":[{"fix":"Send ids from the feed list.","status":422,"when":"An item has no `id`, or an id is not valid (`validation_failed`; `error.fields` names the field)."},{"fix":"Send at least one item. The message is misleading: nothing is wrong with your key.","status":500,"when":"The list is empty, or the body is missing or `{}`: `{\"status\": 500, \"success\": false, \"error\": {\"code\": \"invalid_user\", \"message\": \"Current Auth User is not valid!\"}}`."}],"group":"Messages and activity","notes":["Ids that are not yours are skipped without an error.","Only your own feed changes; other people's feeds stay as they are."],"permission":"Your own feed only.","related":["v1_public_current_user_feed_archive"]}}},"/v1/api/store/{team_slug}/current_user_feed/unseen":{"put":{"description":"Marks the listed notifications as not seen again. Send a JSON **array** of `{id}` objects as the whole body.","operationId":"v1_public_current_user_feed_unseen","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"H3w5wUZaIrCb52"},{"id":"I2jYDEbcQRl0AW"}],"schema":{"description":"The feed items to change: a JSON array of `{id}` objects, not an object.","items":{"properties":{"id":{"description":"A feed item id.","type":"string"}},"required":["id"],"type":"object"},"minItems":1,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Mark notifications as not seen","tags":["Notifications"],"x-yoprint-docs":{"errors":[{"fix":"Send ids from the feed list.","status":422,"when":"An item has no `id`, or an id is not valid (`validation_failed`; `error.fields` names the field)."},{"fix":"Send at least one item. The message is misleading: nothing is wrong with your key.","status":500,"when":"The list is empty, or the body is missing or `{}`: `{\"status\": 500, \"success\": false, \"error\": {\"code\": \"invalid_user\", \"message\": \"Current Auth User is not valid!\"}}`."}],"group":"Messages and activity","notes":["Ids that are not yours are skipped without an error.","Only your own feed changes; other people's feeds stay as they are."],"permission":"Your own feed only.","related":["v1_public_current_user_feed_seen"]}}},"/v1/api/store/{team_slug}/current_user_preference":{"get":{"description":"Returns the preferences the YoPrint web app saved for you on this team, as one free-form object. YoPrint itself reads none of these keys; they hold web app settings such as grid column layouts (`column_order`) and how sales orders open (`sales_order_open_behavior`).\n\nWith no preferences saved yet, `data` is an empty array `[]`, not an object.","operationId":"v1_public_current_user_preference_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"sales_order_open_behavior":{"global_search":"preview_window","sales_order_list":"full_page"},"version":1},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"The keys the web app uses today. Other keys you saved come back too.","properties":{"column_order":{"additionalProperties":true,"description":"Grid column layouts, keyed by the web app's grid name. Each value is that grid's list of column states. An empty one reads back as `[]`.","type":["object","array"]},"sales_order_open_behavior":{"description":"How the web app opens a sales order from each place. An empty one reads back as `[]`.","properties":{"global_search":{"enum":["preview_window","full_page","new_tab"],"type":"string"},"related_link":{"enum":["preview_window","full_page","new_tab"],"type":"string"},"sales_order_list":{"enum":["preview_window","full_page","new_tab"],"type":"string"}},"type":["object","array"]},"version":{"description":"The web app's version of these settings.","type":"number"}},"type":["object","array"]},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get your preferences for this team","tags":["Your preferences"],"x-yoprint-docs":{"group":"Messages and activity","permission":"Your own preferences only.","related":["v1_public_current_user_preference_update"]}},"post":{"description":"Merges `preference` into your saved preferences on this team and returns the result. The merge is one level deep: each top-level key you send replaces that key whole, and keys you leave out stay as they were.\n\nKeys can't be removed: a `null` value, at any depth, is dropped before it reaches YoPrint, except under a few key names YoPrint keeps nulls for on every request (such as `start_date`, `due_date` or `billing_address_id`), which are saved as `null`. These settings drive the YoPrint web app, so changing keys it uses changes what you see there.","operationId":"v1_public_current_user_preference_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"preference":{"sales_order_open_behavior":{"global_search":"new_tab","related_link":"preview_window","sales_order_list":"full_page"}}},"schema":{"properties":{"preference":{"additionalProperties":true,"description":"Top-level keys to set. Send an object. Left out or empty, nothing changes and the answer is your current preferences.","type":"object"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":{"sales_order_open_behavior":{"global_search":"new_tab","related_link":"preview_window","sales_order_list":"full_page"},"version":1},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"All your preferences after the merge. An empty array `[]` when there are none.","properties":{"column_order":{"additionalProperties":true,"description":"Grid column layouts, keyed by the web app's grid name. Each value is that grid's list of column states. An empty one reads back as `[]`.","type":["object","array"]},"sales_order_open_behavior":{"description":"How the web app opens a sales order from each place. An empty one reads back as `[]`.","properties":{"global_search":{"enum":["preview_window","full_page","new_tab"],"type":"string"},"related_link":{"enum":["preview_window","full_page","new_tab"],"type":"string"},"sales_order_list":{"enum":["preview_window","full_page","new_tab"],"type":"string"}},"type":["object","array"]},"version":{"description":"The web app's version of these settings.","type":"number"}},"type":["object","array"]},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Save your preferences for this team","tags":["Your preferences"],"x-yoprint-docs":{"errors":[{"fix":"Send an object.","status":500,"when":"`preference` is a string, a number or `true` instead of an object: a server error, not a 422. Empty values (`\"\"`, `0`, `false`) change nothing instead."}],"group":"Messages and activity","permission":"Your own preferences only.","related":["v1_public_current_user_preference_show"],"rules":["Send `preference` as a JSON object. Nothing inside it is checked. Left out, empty, `false` or `0`, nothing changes."],"side_effects":["Your other open YoPrint tabs pick up the change."]}}},"/v1/api/store/{team_slug}/customer":{"get":{"description":"Lists the team's customers, without deleted and system customers. The order is not defined: to sort, or to filter, use Search customers with filters (`POST customer/filter`).\n\nMembers who may see only customers assigned to them get only those. Rows leave out `contacts` and `addresses`; read one customer to get them.\n\nThere is no search filter for name, email, or phone. To find a customer by contact email or phone, use Create or update a customer by contact (`POST customer/upsert`), or export customers to CSV.\n\nThe list is paged: `pagination` gives `total`, `count`, `perPage`, `currentPage` and `totalPages`. Ask for the next page with `page`; the page size is the team's setting (50 unless changed), and `per_page` is ignored.","operationId":"v1_public_customer_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The page to return. Pages hold the team's page size (`pagination_per_page` in team settings: 50 unless changed, 5 to 100). `per_page` is not read here.","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"account_warning":null,"assigned_users":[{"avatar_url":"https://example.com/avatars/alex.png","id":"lOURnovd3hkIQI","name":"Alex Rivera"}],"created_at":"2026-10-01T09:00:00+00:00","customer_portal_enabled":null,"customer_portal_id":"HWYGf6vzKsjwpS","customer_portal_id_override":null,"customer_portal_link":null,"customer_portal_payment_option":null,"customer_profiles":[{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"}],"default_payment_term_id":null,"default_pricing_group_id":null,"default_warehouse_id":null,"deposit_due_amount":0,"display_customer_portal_id":"HWYGf6vzKsjwpS","external_type":null,"has_customer_portal_id_override":false,"held_credit":0,"hide":false,"id":"V4keXwwxMQyXw7","internal_notes":null,"is_editable":true,"is_external":false,"is_system":false,"last_ordered_date":"2026-10-28T08:00:00+00:00","media":[{"collection":"tax_exemption","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"customer_id":"V4keXwwxMQyXw7","file_name":"resale-certificate.pdf","id":"4GR9C3ZTMYtda5","is_image":false,"mime_type":"application/pdf","name":"Resale certificate 2026.pdf","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/4GR9C3ZTMYtda5/download","view_url":"https://example.com/media/4GR9C3ZTMYtda5/view"}],"name":"Northwind Apparel","ordered_amount":125000,"overdue_amount":0,"pdf":{"invoice_statement":"https://example.com/pdf/customer_invoice_statement/V4keXwwxMQyXw7"},"quote_amount":0,"resale_number":null,"shopify_compliance_deletion":null,"system_type":null,"tags":[{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"}],"tax_exempt":false,"third_party_billing_default":"none","trashed":false,"unpaid_amount":25000,"updated_at":"2026-11-01T09:00:00+00:00","vat_number":null,"wallet_currency":{"default":true,"id":"icHZvqV1nkXRcA","iso":"USD","name":"US Dollar","symbol":"$","trashed":false},"wallet_fund":50000,"website":"https://example.com"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A customer, without `contacts` and `addresses` (read one customer to get them).","properties":{"account_warning":{"additionalProperties":false,"description":"Why YoPrint shows a warning next to the customer's name. Null when there is nothing to warn about.","properties":{"open_dispute":{"additionalProperties":false,"description":"The customer's payments under a dispute that is open or under review; null when there is none.","properties":{"count":{"description":"How many payments are disputed.","type":"integer"},"payment_amount":{"description":"The total of the disputed payments, each counted once. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]}},"required":["payment_amount","count"],"type":["object","null"]},"owed_amount":{"description":"What the customer owes back because `wallet_fund` is negative, as a positive amount; null when it is not negative. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]}},"required":["owed_amount","open_dispute"],"type":["object","null"]},"assigned_users":{"description":"The users assigned to the customer. Unlike List the users assigned to a customer, people who have left the team stay in this list.","items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","avatar_url","name"],"type":"object"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"customer_portal_enabled":{"description":"Whether the customer's contacts can open the Customer Portal (Portal settings > Customer portal in YoPrint). `false`: the portal is off for this customer. `true`, or null (never set), means on.","type":["boolean","null"]},"customer_portal_id":{"description":"The id used in the customer's portal address. Null for Shopify customers.","type":["string","null"]},"customer_portal_id_override":{"type":["string","null"]},"customer_portal_link":{"description":"Always null: YoPrint no longer returns a portal sign-in link for the customer. The field stays for older integrations.","type":"null"},"customer_portal_payment_option":{"description":"Whether the customer can pay online in the portal. Null follows the team setting (and is always null for Shopify customers).","enum":["ENABLED","DISABLED",null],"type":["string","null"]},"customer_profiles":{"description":"Brand profiles.","items":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"type":"array"},"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"default_warehouse_id":{"type":["string","null"]},"deposit_due_amount":{"description":"Deposits still due. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"display_customer_portal_id":{"description":"The Customer Portal ID shown to people: the override when set, otherwise `customer_portal_id`. `-` for Shopify customers.","type":"string"},"external_type":{"description":"`shopify` for customers synced from Shopify.","type":["string","null"]},"has_customer_portal_id_override":{"type":"boolean"},"held_credit":{"description":"The part of `wallet_fund` held while a payment is under an open dispute or a provider review: it can't be applied to orders or taken out until the hold ends. Never more than `wallet_fund`; 0 when `wallet_fund` is 0 or negative. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"hide":{"description":"True when the customer is archived.","type":"boolean"},"id":{"description":"The customer id. Use it in paths and as `customer_id` on sales orders and quotes.","type":"string"},"internal_notes":{"type":["string","null"]},"is_editable":{"description":"False for Shopify and system customers: they can't be changed through this API.","type":"boolean"},"is_external":{"type":"boolean"},"is_system":{"type":"boolean"},"last_ordered_date":{"description":"The issue date of the customer's latest published sales order. Null when it has none.","format":"date-time","type":["string","null"]},"media":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"name":{"description":"Null for a customer created by upsert without a name.","type":["string","null"]},"ordered_amount":{"description":"Total of the customer's published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"overdue_amount":{"description":"Unpaid amounts past their payment due date. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"pdf":{"additionalProperties":false,"properties":{"invoice_statement":{"description":"A link that downloads the customer's invoice statement PDF. Its token opens only this customer's statement and stops working 9,000 hours (about a year) after the answer was made. Anyone with the link can download the statement: don't share it.","type":"string"}},"required":["invoice_statement"],"type":"object"},"quote_amount":{"description":"Total of open quotes. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"resale_number":{"type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"type":["object","null"]},"system_type":{"type":["string","null"]},"tags":{"items":{"additionalProperties":false,"properties":{"color_hex":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"tax_exempt":{"type":"boolean"},"third_party_billing_default":{"description":"How a shipping label for this customer is billed by default. `default_carrier_account`: YoPrint's label and rate dialogs start on the customer's default carrier account (third-party billing). `none`: they start with no third-party billing.","enum":["none","default_carrier_account"],"type":"string"},"trashed":{"description":"True when the customer is deleted.","type":"boolean"},"unpaid_amount":{"description":"What the customer still owes on published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"updated_at":{"format":"date-time","type":"string"},"vat_number":{"description":"The customer's tax number (shown as Tax number in YoPrint).","type":["string","null"]},"wallet_currency":{"additionalProperties":false,"description":"The team's default currency, the one `wallet_fund` is in. `iso` is its code.","properties":{"default":{"type":"boolean"},"id":{"type":"string"},"iso":{"description":"The ISO 4217 code, such as `USD`.","type":["string","null"]},"name":{"type":["string","null"]},"symbol":{"type":["string","null"]},"trashed":{"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"wallet_fund":{"description":"Customer credit balance. Negative when the customer owes credit back, for example after a refund of a payment whose credit was already spent. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"website":{"type":["string","null"]}},"required":["id","name","tax_exempt","trashed","hide","is_external","is_system","is_editable","created_at","updated_at"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List customers","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team owner to give your role the Manage Customers permission.","status":403,"when":"Your role cannot see customers. This 403 has a short body, `{\"message\": \"You do not have permission to view customer\"}`."}],"group":"Customers","permission":"Needs the Manage Customers permission. At \"Manage Assigned to User\" you see only customers assigned to you; without it the answer is 403.","related":["v1_public_customer_filter","v1_public_customer_show","v1_public_customer_store"]}},"post":{"description":"Creates a customer, with its contacts and its billing and shipping addresses, in one request. Returns the new customer with `contacts` and `addresses`.\n\nOnly `customer.name` and `customer.tax_exempt` are required. A sales order names one of the customer's contacts and its billing and shipping addresses (`customer_contact_id`, `billing_address_id`, `shipping_address_id`), so send them here or add them later. A contact needs at least a first name.\n\n- Mark one contact `is_primary: true` to make it the primary contact. If none is marked, the customer has no primary contact until you set one.\n- The first billing address and the first shipping address become primary, whatever `is_primary` says.\n- You are assigned to the new customer.\n\nWhen you later create a sales order or quote for this customer, it takes the customer's primary brand profile, default payment term, default pricing group and default warehouse. A default pricing group that was removed since is skipped: the order gets the team's default group.","operationId":"v1_public_customer_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"full":{"summary":"A company with a contact and both addresses","value":{"billing":[{"address1":"100 Example Street","address2":"Suite 200","city":"Springfield","country_code":"US","is_primary":true,"label":"Head office","postcode":"62701","state_code":"IL"}],"contact":[{"email":"alex@example.com","first_name":"Alex","is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true}],"customer":{"name":"Northwind Apparel","tax_exempt":false,"website":"https://example.com"},"shipping":[{"address1":"100 Example Street","address2":"Dock 4","city":"Springfield","country_code":"US","is_primary":true,"label":"Warehouse","postcode":"62701","state_code":"IL"}]}},"minimal":{"summary":"Just the required fields","value":{"customer":{"name":"Northwind Apparel","tax_exempt":false}}}},"schema":{"additionalProperties":false,"properties":{"billing":{"description":"Billing addresses. At most one may have `is_primary: true`.","items":{"additionalProperties":false,"properties":{"address1":{"description":"Required. Street line 1.","type":"string"},"address2":{"description":"Street line 2, such as a suite or unit.","type":"string"},"city":{"description":"The city.","type":"string"},"country":{"description":"The country name. Shown as the country of `country_code` when blank.","type":"string"},"country_code":{"description":"Required. Two-letter country code, such as `US`.","type":"string"},"is_primary":{"description":"Required, but the first address of each role always becomes primary and later ones never do. Use the set-primary operation to change it.","type":"boolean"},"label":{"description":"Required. A name for the address, shown in pickers: \"Head office\".","type":"string"},"note":{"description":"A note kept with the address, such as delivery instructions.","type":"string"},"postcode":{"description":"The postal or ZIP code.","type":"string"},"state":{"description":"The state or province name, such as \"Illinois\". For US and Canada addresses, send either `state` or `state_code` (or both matching): YoPrint resolves and stores both. For other countries, send the name in `state`. Sending `null` is ignored; omit the field to leave it unset.","type":"string"},"state_code":{"description":"The two-letter state or province code, such as `IL` or `ON`. Used for US and Canada addresses: send either `state_code` or `state`. Sending `null` is ignored; omit the field to leave it unset.","type":"string"}},"required":["label","address1","country_code","is_primary"],"type":"object"},"type":"array"},"contact":{"description":"The customer's contacts. At most one may have `is_primary: true`.","items":{"additionalProperties":false,"properties":{"default_receive_sms":{"description":"When this contact is set on a sales order, it receives text messages about the order by default. Saved as sent; defaults to false.","type":"boolean"},"email":{"description":"The contact's email. Messages you send to this contact go here.","format":"email","type":"string"},"fax":{"description":"Checked as a real number for `fax_country`.","type":"string"},"fax_country":{"description":"Two-letter country code of `fax`.","type":"string"},"first_name":{"description":"Required. The contact's first name.","type":"string"},"is_primary":{"description":"Required.","type":"boolean"},"last_name":{"description":"The contact's last name.","type":"string"},"phone":{"description":"Checked as a real number for `phone_country`. Send `phone_country` with it.","type":"string"},"phone_country":{"description":"Two-letter country code of `phone`, such as `US`. Required with `phone`.","example":"US","type":"string"},"send_invoice":{"description":"Required. Stored with the contact and returned as `send_invoice`.","type":"boolean"}},"required":["first_name","send_invoice","is_primary"],"type":"object"},"type":"array"},"customer":{"additionalProperties":false,"properties":{"customer_portal_enabled":{"description":"`false` creates the customer with the Customer Portal off: its contacts can't open the portal. Leave it out, or send `true` or null, for on.","type":["boolean","null"]},"customer_portal_payment_option":{"description":"Whether the customer can pay online in the customer portal. Leave it out to follow the team setting.","enum":["ENABLED","DISABLED",null],"type":["string","null"]},"default_payment_term_id":{"description":"A payment term id. New sales orders for this customer use it.","type":["string","null"]},"hide":{"description":"True creates the customer archived. Not checked on create: send a JSON boolean.","type":"boolean"},"internal_notes":{"description":"Notes for your team only.","type":"string"},"name":{"description":"The customer's name, usually the company. Names need not be unique.","type":"string"},"resale_number":{"description":"The customer's resale or tax certificate number.","type":"string"},"tax_exempt":{"description":"True when no sales tax applies to this customer.","type":"boolean"},"third_party_billing_default":{"description":"How the customer's shipping labels are billed by default (see the customer object). Leave it out for `none`.","enum":["none","default_carrier_account"],"type":"string"},"vat_number":{"description":"The customer's tax number (Tax number in YoPrint).","type":"string"},"website":{"description":"The website address.","type":"string"}},"required":["name","tax_exempt"],"type":"object"},"shipping":{"description":"Shipping addresses. At most one may have `is_primary: true`.","items":{"additionalProperties":false,"properties":{"address1":{"description":"Required. Street line 1.","type":"string"},"address2":{"description":"Street line 2, such as a suite or unit.","type":"string"},"city":{"description":"The city.","type":"string"},"country":{"description":"The country name. Shown as the country of `country_code` when blank.","type":"string"},"country_code":{"description":"Required. Two-letter country code, such as `US`.","type":"string"},"is_primary":{"description":"Required, but the first address of each role always becomes primary and later ones never do. Use the set-primary operation to change it.","type":"boolean"},"label":{"description":"Required. A name for the address, shown in pickers: \"Head office\".","type":"string"},"note":{"description":"A note kept with the address, such as delivery instructions.","type":"string"},"postcode":{"description":"The postal or ZIP code.","type":"string"},"state":{"description":"The state or province name, such as \"Illinois\". For US and Canada addresses, send either `state` or `state_code` (or both matching): YoPrint resolves and stores both. For other countries, send the name in `state`. Sending `null` is ignored; omit the field to leave it unset.","type":"string"},"state_code":{"description":"The two-letter state or province code, such as `IL` or `ON`. Used for US and Canada addresses: send either `state_code` or `state`. Sending `null` is ignored; omit the field to leave it unset.","type":"string"}},"required":["label","address1","country_code","is_primary"],"type":"object"},"type":"array"}},"required":["customer"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_warning":null,"addresses":[{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false},{"address1":"100 Example Street","address2":"Dock 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"swtHxyIfOvF62K","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Warehouse","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false}],"assigned_users":[{"avatar_url":"https://example.com/avatars/alex.png","id":"lOURnovd3hkIQI","name":"Alex Rivera"}],"contacts":[{"created_at":"2026-11-03T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-03T09:00:00+00:00"}],"created_at":"2026-11-03T09:00:00+00:00","customer_portal_enabled":null,"customer_portal_id":"HWYGf6vzKsjwpS","customer_portal_id_override":null,"customer_portal_link":null,"customer_portal_payment_option":null,"customer_profiles":[],"default_payment_term_id":null,"default_pricing_group_id":null,"default_warehouse_id":null,"deposit_due_amount":0,"display_customer_portal_id":"HWYGf6vzKsjwpS","external_type":null,"has_customer_portal_id_override":false,"held_credit":0,"hide":false,"id":"V4keXwwxMQyXw7","internal_notes":null,"is_editable":true,"is_external":false,"is_system":false,"last_ordered_date":null,"media":[],"name":"Northwind Apparel","ordered_amount":0,"overdue_amount":0,"pdf":{"invoice_statement":"https://example.com/pdf/customer_invoice_statement/V4keXwwxMQyXw7"},"quote_amount":0,"resale_number":null,"shopify_compliance_deletion":null,"system_type":null,"tags":[],"tax_exempt":false,"third_party_billing_default":"none","trashed":false,"unpaid_amount":0,"updated_at":"2026-11-03T09:00:00+00:00","vat_number":null,"wallet_currency":{"default":true,"id":"icHZvqV1nkXRcA","iso":"USD","name":"US Dollar","symbol":"$","trashed":false},"wallet_fund":0,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"account_warning":{"additionalProperties":false,"description":"Why YoPrint shows a warning next to the customer's name. Null when there is nothing to warn about.","properties":{"open_dispute":{"additionalProperties":false,"description":"The customer's payments under a dispute that is open or under review; null when there is none.","properties":{"count":{"description":"How many payments are disputed.","type":"integer"},"payment_amount":{"description":"The total of the disputed payments, each counted once. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]}},"required":["payment_amount","count"],"type":["object","null"]},"owed_amount":{"description":"What the customer owes back because `wallet_fund` is negative, as a positive amount; null when it is not negative. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]}},"required":["owed_amount","open_dispute"],"type":["object","null"]},"addresses":{"description":"Billing and shipping addresses that are not deleted, old copies replaced by an edit included (`is_current_source: false`).","items":{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},"type":"array"},"assigned_users":{"description":"The users assigned to the customer. Unlike List the users assigned to a customer, people who have left the team stay in this list.","items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","avatar_url","name"],"type":"object"},"type":"array"},"contacts":{"description":"Every contact, deleted ones included (`trashed`).","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"customer_portal_enabled":{"description":"Whether the customer's contacts can open the Customer Portal (Portal settings > Customer portal in YoPrint). `false`: the portal is off for this customer. `true`, or null (never set), means on.","type":["boolean","null"]},"customer_portal_id":{"description":"The id used in the customer's portal address. Null for Shopify customers.","type":["string","null"]},"customer_portal_id_override":{"type":["string","null"]},"customer_portal_link":{"description":"Always null: YoPrint no longer returns a portal sign-in link for the customer. The field stays for older integrations.","type":"null"},"customer_portal_payment_option":{"description":"Whether the customer can pay online in the portal. Null follows the team setting (and is always null for Shopify customers).","enum":["ENABLED","DISABLED",null],"type":["string","null"]},"customer_profiles":{"description":"Brand profiles.","items":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"type":"array"},"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"default_warehouse_id":{"type":["string","null"]},"deposit_due_amount":{"description":"Deposits still due. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"display_customer_portal_id":{"description":"The Customer Portal ID shown to people: the override when set, otherwise `customer_portal_id`. `-` for Shopify customers.","type":"string"},"external_type":{"description":"`shopify` for customers synced from Shopify.","type":["string","null"]},"has_customer_portal_id_override":{"type":"boolean"},"held_credit":{"description":"The part of `wallet_fund` held while a payment is under an open dispute or a provider review: it can't be applied to orders or taken out until the hold ends. Never more than `wallet_fund`; 0 when `wallet_fund` is 0 or negative. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"hide":{"description":"True when the customer is archived.","type":"boolean"},"id":{"description":"The customer id. Use it in paths and as `customer_id` on sales orders and quotes.","type":"string"},"internal_notes":{"type":["string","null"]},"is_editable":{"description":"False for Shopify and system customers: they can't be changed through this API.","type":"boolean"},"is_external":{"type":"boolean"},"is_system":{"type":"boolean"},"last_ordered_date":{"description":"The issue date of the customer's latest published sales order. Null when it has none.","format":"date-time","type":["string","null"]},"media":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"name":{"description":"Null for a customer created by upsert without a name.","type":["string","null"]},"ordered_amount":{"description":"Total of the customer's published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"overdue_amount":{"description":"Unpaid amounts past their payment due date. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"pdf":{"additionalProperties":false,"properties":{"invoice_statement":{"description":"A link that downloads the customer's invoice statement PDF. Its token opens only this customer's statement and stops working 9,000 hours (about a year) after the answer was made. Anyone with the link can download the statement: don't share it.","type":"string"}},"required":["invoice_statement"],"type":"object"},"quote_amount":{"description":"Total of open quotes. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"resale_number":{"type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"type":["object","null"]},"system_type":{"type":["string","null"]},"tags":{"items":{"additionalProperties":false,"properties":{"color_hex":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"tax_exempt":{"type":"boolean"},"third_party_billing_default":{"description":"How a shipping label for this customer is billed by default. `default_carrier_account`: YoPrint's label and rate dialogs start on the customer's default carrier account (third-party billing). `none`: they start with no third-party billing.","enum":["none","default_carrier_account"],"type":"string"},"trashed":{"description":"True when the customer is deleted.","type":"boolean"},"unpaid_amount":{"description":"What the customer still owes on published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"updated_at":{"format":"date-time","type":"string"},"vat_number":{"description":"The customer's tax number (shown as Tax number in YoPrint).","type":["string","null"]},"wallet_currency":{"additionalProperties":false,"description":"The team's default currency, the one `wallet_fund` is in. `iso` is its code.","properties":{"default":{"type":"boolean"},"id":{"type":"string"},"iso":{"description":"The ISO 4217 code, such as `USD`.","type":["string","null"]},"name":{"type":["string","null"]},"symbol":{"type":["string","null"]},"trashed":{"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"wallet_fund":{"description":"Customer credit balance. Negative when the customer owes credit back, for example after a refund of a payment whose credit was already spent. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"website":{"type":["string","null"]}},"required":["id","name","tax_exempt","trashed","hide","is_external","is_system","is_editable","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a customer","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Fix each field named in `error.fields`; its keys are paths such as `contact.0.first_name` or `billing` (for two primaries).","status":422,"when":"A required field is missing, a phone is not valid for its country, a US or Canadian state can't be matched, or two items in one list are primary. `error.code` is `validation_failed`."},{"fix":"Send each email once.","status":409,"when":"Two contacts in the request have the same email, ignoring case and surrounding spaces (`error.code` `customer_portal_duplicate_contact_email`). Nothing is saved."},{"fix":"Send a valid email of at most 191 characters.","status":422,"when":"On a live customer, the email is longer than 191 characters or is not a valid address (`error.code` `customer_portal_email_invalid`, \"Enter a valid email address using supported characters.\")."},{"fix":"Ask a team owner for the Manage Customers permission.","status":403,"when":"Your role cannot create customers. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Customers","notes":["A field sent as `null` is dropped before the request is read, except `customer.default_payment_term_id`, `customer.customer_portal_payment_option` and `customer.customer_portal_enabled`, which are saved as null."],"permission":"Needs the Manage Customers permission (either level can create customers).","related":["v1_public_customer_upsert","v1_public_customer_update_patch","v1_public_customer_contact_store","v1_public_customer_address_store","v1_public_payment_term_index"],"rules":["`is_external` and `external_type` are ignored on customers and their contacts: sending them (for example a value you read back) is not refused and changes nothing. Only the Shopify sync sets them. Other fields not listed here are not part of the API.","Everything is saved together or not at all.","Each contact needs `first_name`, `send_invoice` and `is_primary`. A phone needs `phone_country` and must be a valid number for that country.","Each address needs `label`, `address1`, `country_code` and `is_primary`. For `US` and `CA`, `state` and `state_code` must name a real state or province; YoPrint fills in the other half of the pair.","At most one contact, one billing address and one shipping address may be sent with `is_primary: true` (422 \"You cannot set more than 1 primary address\").","Nothing checks for duplicate customers: two customers may share a name, an email or a phone. To find or create by contact email or phone, use Create or update a customer by contact (`customer/upsert`).","On a live customer (not a system or Shopify customer) a contact's email is saved trimmed and in lower case, and two live contacts of the customer can't have the same email (compared the same way). Other customers may use the same email. So two contacts in one request can't share an email.","Only `customer.default_payment_term_id` is read as an id on create. To set a default pricing group or default warehouse, create the customer, then update it."],"side_effects":["Sends the `customer.created` webhook.","Assigns you to the customer.","When the contact's email already belongs to a Customer Portal account on your team that can't open this customer yet, saving the contact gives that account access to this customer (active when the account is set up with a verified email or a password, invited otherwise). No email is sent."]}}},"/v1/api/store/{team_slug}/customer/filter":{"post":{"description":"Lists customers that match every filter you send, sorted the way you ask. System customers are never returned. Deleted customers are left out unless you filter on `trashed_only`.\n\nEach filter is `{key, operator, value}`; all of them must match. What `operator` and `value` may be depends on the key:\n\n| `key` | Means | `operator` | `value` |\n| --- | --- | --- | --- |\n| `assigned_users` | Assigned to any of these users | `in`, `nin` | Array of user ids. `system-current-user` means you. |\n| `assigned_to_me` | Assigned to you | `eq` | `true` |\n| `tag` | Has any of these tags | `in`, `nin` | Array of tag ids |\n| `hide` | Archived | `eq`, `neq` | `true` or `false` (JSON booleans) |\n| `tax_exempt` | Tax exempt | `eq`, `neq` | `true` or `false` |\n| `trashed_only` | Deleted customers only | `eq` | `true` |\n| `external_type` | Synced from Shopify | `in`, `nin` | `[\"shopify\"]` |\n| `ordered_amount`, `unpaid_amount`, `deposit_due_amount`, `overdue_amount`, `quote_amount`, `wallet_fund` | The customer's totals | `eq`, `gte`, `lte` | Send a whole number of thousandths: `100000` is 100.00 |\n| `last_ordered_date` | Last order date | `eq`, `gte`, `lte` | Whole days from today (UTC), see below |\n\n`last_ordered_date` filters by a whole number of days from today (in UTC):\n\n| Operator | Compares with | Example | Meaning |\n| --- | --- | --- | --- |\n| `eq N` | Whole UTC day N days from today | `0` or `-1` | Ordered today (`0`) or yesterday (`-1`) |\n| `gte N` | On or after now **plus** N days | `-30` | Ordered in the last 30 days (`gte -30`) |\n| `lte N` | On or before now **minus** N days | `90` | Inactive for 90+ days (not ordered in last 90 days: `lte 90`) |\n\nBecause `gte` adds days and `lte` subtracts days, use negative numbers with `gte` to look back in time, and positive numbers with `lte`. Customers who never ordered have no `last_ordered_date` and never match. (Sales order v2 date filters work differently; see Filtering and sorting).\n\n`sort` is a list of `{key, direction}`, applied in order. Sort keys: `name`, `last_ordered_date`, `ordered_amount`, `unpaid_amount`, `deposit_due_amount`, `wallet_fund`, `overdue_amount`, `quote_amount`, `created_at`; `direction` is `asc` or `desc`. Without `sort` the order is not defined, so always sort when you page.\n\nThe list is paged: `pagination` gives `total`, `count`, `perPage`, `currentPage` and `totalPages`. Ask for the next page with `page`; the page size is the team's setting (50 unless changed), and `per_page` is ignored. Send `page` in the body or the query string.","operationId":"v1_public_customer_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The page to return. Pages hold the team's page size (`pagination_per_page` in team settings: 50 unless changed, 5 to 100). `per_page` is not read here.","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"requestBody":{"content":{"application/json":{"examples":{"deleted":{"summary":"Deleted customers","value":{"filters":[{"key":"trashed_only","operator":"eq","value":true}]}},"owing":{"summary":"Customers who owe more than 100.00, biggest first","value":{"filters":[{"key":"unpaid_amount","operator":"gte","value":100000}],"page":1,"sort":[{"direction":"desc","key":"unpaid_amount"}]}},"recent_tagged":{"summary":"Tagged customers who ordered in the last 30 days","value":{"filters":[{"key":"tag","operator":"in","value":["zzVW0sylTIm6oo"]},{"key":"last_ordered_date","operator":"gte","value":-30},{"key":"hide","operator":"eq","value":false}],"sort":[{"direction":"asc","key":"name"}]}}},"schema":{"additionalProperties":false,"properties":{"filters":{"description":"Filters that must all match. Leave the key out for no filter; an empty list is refused.","items":{"additionalProperties":false,"properties":{"key":{"enum":["assigned_users","assigned_to_me","trashed_only","overdue_amount","quote_amount","deposit_due_amount","unpaid_amount","ordered_amount","last_ordered_date","wallet_fund","tag","hide","tax_exempt","external_type"],"type":"string"},"operator":{"enum":["eq","neq","gte","lte","in","nin"],"type":"string"},"value":{"description":"A boolean, a number or an array of ids, by key (see the table)."}},"required":["key","operator","value"],"type":"object"},"minItems":1,"type":"array"},"page":{"minimum":1,"type":"integer"},"sort":{"items":{"additionalProperties":false,"properties":{"direction":{"enum":["asc","desc"],"type":"string"},"key":{"enum":["name","last_ordered_date","ordered_amount","unpaid_amount","deposit_due_amount","wallet_fund","overdue_amount","quote_amount","created_at"],"type":"string"}},"required":["key","direction"],"type":"object"},"type":"array"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"account_warning":null,"assigned_users":[{"avatar_url":"https://example.com/avatars/alex.png","id":"lOURnovd3hkIQI","name":"Alex Rivera"}],"created_at":"2026-10-01T09:00:00+00:00","customer_portal_enabled":null,"customer_portal_id":"HWYGf6vzKsjwpS","customer_portal_id_override":null,"customer_portal_link":null,"customer_portal_payment_option":null,"customer_profiles":[{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"}],"default_payment_term_id":null,"default_pricing_group_id":null,"default_warehouse_id":null,"deposit_due_amount":0,"display_customer_portal_id":"HWYGf6vzKsjwpS","external_type":null,"has_customer_portal_id_override":false,"held_credit":0,"hide":false,"id":"V4keXwwxMQyXw7","internal_notes":null,"is_editable":true,"is_external":false,"is_system":false,"last_ordered_date":"2026-10-28T08:00:00+00:00","media":[{"collection":"tax_exemption","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"customer_id":"V4keXwwxMQyXw7","file_name":"resale-certificate.pdf","id":"4GR9C3ZTMYtda5","is_image":false,"mime_type":"application/pdf","name":"Resale certificate 2026.pdf","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/4GR9C3ZTMYtda5/download","view_url":"https://example.com/media/4GR9C3ZTMYtda5/view"}],"name":"Northwind Apparel","ordered_amount":125000,"overdue_amount":0,"pdf":{"invoice_statement":"https://example.com/pdf/customer_invoice_statement/V4keXwwxMQyXw7"},"quote_amount":0,"resale_number":null,"shopify_compliance_deletion":null,"system_type":null,"tags":[{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"}],"tax_exempt":false,"third_party_billing_default":"none","trashed":false,"unpaid_amount":25000,"updated_at":"2026-11-01T09:00:00+00:00","vat_number":null,"wallet_currency":{"default":true,"id":"icHZvqV1nkXRcA","iso":"USD","name":"US Dollar","symbol":"$","trashed":false},"wallet_fund":50000,"website":"https://example.com"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A customer, without `contacts` and `addresses` (read one customer to get them).","properties":{"account_warning":{"additionalProperties":false,"description":"Why YoPrint shows a warning next to the customer's name. Null when there is nothing to warn about.","properties":{"open_dispute":{"additionalProperties":false,"description":"The customer's payments under a dispute that is open or under review; null when there is none.","properties":{"count":{"description":"How many payments are disputed.","type":"integer"},"payment_amount":{"description":"The total of the disputed payments, each counted once. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]}},"required":["payment_amount","count"],"type":["object","null"]},"owed_amount":{"description":"What the customer owes back because `wallet_fund` is negative, as a positive amount; null when it is not negative. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]}},"required":["owed_amount","open_dispute"],"type":["object","null"]},"assigned_users":{"description":"The users assigned to the customer. Unlike List the users assigned to a customer, people who have left the team stay in this list.","items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","avatar_url","name"],"type":"object"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"customer_portal_enabled":{"description":"Whether the customer's contacts can open the Customer Portal (Portal settings > Customer portal in YoPrint). `false`: the portal is off for this customer. `true`, or null (never set), means on.","type":["boolean","null"]},"customer_portal_id":{"description":"The id used in the customer's portal address. Null for Shopify customers.","type":["string","null"]},"customer_portal_id_override":{"type":["string","null"]},"customer_portal_link":{"description":"Always null: YoPrint no longer returns a portal sign-in link for the customer. The field stays for older integrations.","type":"null"},"customer_portal_payment_option":{"description":"Whether the customer can pay online in the portal. Null follows the team setting (and is always null for Shopify customers).","enum":["ENABLED","DISABLED",null],"type":["string","null"]},"customer_profiles":{"description":"Brand profiles.","items":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"type":"array"},"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"default_warehouse_id":{"type":["string","null"]},"deposit_due_amount":{"description":"Deposits still due. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"display_customer_portal_id":{"description":"The Customer Portal ID shown to people: the override when set, otherwise `customer_portal_id`. `-` for Shopify customers.","type":"string"},"external_type":{"description":"`shopify` for customers synced from Shopify.","type":["string","null"]},"has_customer_portal_id_override":{"type":"boolean"},"held_credit":{"description":"The part of `wallet_fund` held while a payment is under an open dispute or a provider review: it can't be applied to orders or taken out until the hold ends. Never more than `wallet_fund`; 0 when `wallet_fund` is 0 or negative. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"hide":{"description":"True when the customer is archived.","type":"boolean"},"id":{"description":"The customer id. Use it in paths and as `customer_id` on sales orders and quotes.","type":"string"},"internal_notes":{"type":["string","null"]},"is_editable":{"description":"False for Shopify and system customers: they can't be changed through this API.","type":"boolean"},"is_external":{"type":"boolean"},"is_system":{"type":"boolean"},"last_ordered_date":{"description":"The issue date of the customer's latest published sales order. Null when it has none.","format":"date-time","type":["string","null"]},"media":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"name":{"description":"Null for a customer created by upsert without a name.","type":["string","null"]},"ordered_amount":{"description":"Total of the customer's published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"overdue_amount":{"description":"Unpaid amounts past their payment due date. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"pdf":{"additionalProperties":false,"properties":{"invoice_statement":{"description":"A link that downloads the customer's invoice statement PDF. Its token opens only this customer's statement and stops working 9,000 hours (about a year) after the answer was made. Anyone with the link can download the statement: don't share it.","type":"string"}},"required":["invoice_statement"],"type":"object"},"quote_amount":{"description":"Total of open quotes. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"resale_number":{"type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"type":["object","null"]},"system_type":{"type":["string","null"]},"tags":{"items":{"additionalProperties":false,"properties":{"color_hex":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"tax_exempt":{"type":"boolean"},"third_party_billing_default":{"description":"How a shipping label for this customer is billed by default. `default_carrier_account`: YoPrint's label and rate dialogs start on the customer's default carrier account (third-party billing). `none`: they start with no third-party billing.","enum":["none","default_carrier_account"],"type":"string"},"trashed":{"description":"True when the customer is deleted.","type":"boolean"},"unpaid_amount":{"description":"What the customer still owes on published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"updated_at":{"format":"date-time","type":"string"},"vat_number":{"description":"The customer's tax number (shown as Tax number in YoPrint).","type":["string","null"]},"wallet_currency":{"additionalProperties":false,"description":"The team's default currency, the one `wallet_fund` is in. `iso` is its code.","properties":{"default":{"type":"boolean"},"id":{"type":"string"},"iso":{"description":"The ISO 4217 code, such as `USD`.","type":["string","null"]},"name":{"type":["string","null"]},"symbol":{"type":["string","null"]},"trashed":{"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"wallet_fund":{"description":"Customer credit balance. Negative when the customer owes credit back, for example after a refund of a payment whose credit was already spent. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"website":{"type":["string","null"]}},"required":["id","name","tax_exempt","trashed","hide","is_external","is_system","is_editable","created_at","updated_at"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Search customers with filters","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Check the table: for example `hide` takes `eq` with a JSON boolean, `tag` takes `in` with an array.","status":422,"when":"A filter has an unknown key, an operator its key does not allow or a value of the wrong type (`error.fields.filters`), or a sort key is not sortable (`error.fields.sort`). `error.code` is `validation_failed`."},{"fix":"Ask a team owner for the Manage Customers permission.","status":403,"when":"Your role cannot see customers. This 403 has a short body, `{\"message\": \"You do not have permission to view customer\"}`."}],"group":"Customers","notes":["Ids in `value` may be hash ids; they are decoded for you."],"permission":"Needs the Manage Customers permission. At \"Manage Assigned to User\" only customers assigned to you are searched; without it the answer is 403.","related":["v1_public_customer_index","v1_public_tag_index"],"rules":["Booleans must be JSON `true` or `false`, not strings. Amounts and day counts must be numbers. Id lists must be arrays, even for one id.","There is no name, email or keyword filter on this operation. To find a customer by email, see the notes of Create or update a customer by contact.","`trashed_only` returns deleted customers whatever its value; leave it out to get live ones.","`tag` with `nin` returns customers that have at least one tag outside the list; customers with no tags are not returned.","`assigned_users` with `nin` works the same way: customers with at least one assigned user outside the list. Customers nobody is assigned to are not returned.","Send amount values as whole numbers of thousandths (`100000` is 100.00). Do not send fractions or numbers with a decimal point (such as `100000.5`): they pass initial validation but cause an HTTP 500 server error."]}}},"/v1/api/store/{team_slug}/customer/upsert":{"post":{"description":"Finds a customer by one contact's email or phone and updates it, or creates a new customer with that contact. It always writes something: the public API has no read-only lookup of a customer by email or phone (see the notes for the ways to find one).\n\nWith `perform_upsert: true` YoPrint looks among the team's live customers for one with a contact (deleted contacts included) whose `email` equals `contact.email`, or whose `phone` equals `contact.phone`, and takes the first. To match by email, send only `contact.email`.\n\n- **A customer matches:** every top-level customer field you send is written to it: `name`, `website`, `internal_notes`, `tax_exempt`, `vat_number`, `resale_number`, `default_payment_term_id`, `default_pricing_group_id`, `default_warehouse_id`, `customer_portal_payment_option`, `customer_portal_enabled`, `third_party_billing_default` and `hide`. Fields you leave out keep their values. The contact is not changed and no contact is added. The `customer.updated` webhook is sent even when nothing changed.\n- **Nothing matches**, or `perform_upsert: false`: a new customer is created from the top-level fields, with `contact` as its only contact. That contact is not made primary. Without `name`, the new customer has no name.\n\nThe answer is the customer with `contacts` in both cases and doesn't say which happened: a customer created by this call has a `created_at` from now.","operationId":"v1_public_customer_upsert","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"contact":{"email":"alex@example.com","first_name":"Alex","is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true},"name":"Northwind Apparel","perform_upsert":true,"tax_exempt":false},"schema":{"additionalProperties":false,"properties":{"contact":{"additionalProperties":false,"description":"The contact to match on and, for a new customer, to create. `email` and `phone` are what is matched.","properties":{"default_receive_sms":{"description":"When this contact is set on a sales order, it receives text messages about the order by default. Saved as sent; defaults to false.","type":"boolean"},"email":{"description":"The contact's email. Messages you send to this contact go here.","format":"email","type":"string"},"fax":{"description":"Checked as a real number for `fax_country`.","type":"string"},"fax_country":{"description":"Two-letter country code of `fax`.","type":"string"},"first_name":{"description":"Required. The contact's first name.","type":"string"},"is_primary":{"description":"Required.","type":"boolean"},"last_name":{"description":"The contact's last name.","type":"string"},"phone":{"description":"Checked as a real number for `phone_country`. Send `phone_country` with it.","type":"string"},"phone_country":{"description":"Two-letter country code of `phone`, such as `US`. Required with `phone`.","example":"US","type":"string"},"send_invoice":{"description":"Required. Stored with the contact and returned as `send_invoice`.","type":"boolean"}},"required":["first_name","send_invoice","is_primary"],"type":"object"},"customer_portal_enabled":{"description":"`false` turns the Customer Portal off for the customer; `true` or null turns it on. Null is saved as null, not dropped.","type":["boolean","null"]},"customer_portal_payment_option":{"enum":["ENABLED","DISABLED",null],"type":["string","null"]},"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"default_warehouse_id":{"description":"A current company location (store location) id.","type":["string","null"]},"hide":{"description":"True to archive.","type":"boolean"},"internal_notes":{"description":"Notes for your team only.","type":"string"},"name":{"description":"The customer's name. Send it: without it, a new customer has no name.","type":"string"},"perform_upsert":{"description":"True to look for an existing customer first. False always creates.","type":"boolean"},"resale_number":{"description":"The customer's resale or tax certificate number.","type":"string"},"tax_exempt":{"description":"True when no sales tax applies to this customer.","type":"boolean"},"third_party_billing_default":{"description":"How the customer's shipping labels are billed by default (see the customer object). A new customer without it gets `none`.","enum":["none","default_carrier_account"],"type":"string"},"vat_number":{"description":"Tax number.","type":"string"},"website":{"description":"The website address.","type":"string"}},"required":["perform_upsert","contact"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_warning":null,"addresses":[{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":true},{"address1":"100 Example Street","address2":"Dock 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"swtHxyIfOvF62K","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Warehouse","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false}],"assigned_users":[{"avatar_url":"https://example.com/avatars/alex.png","id":"lOURnovd3hkIQI","name":"Alex Rivera"}],"contacts":[{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"}],"created_at":"2026-10-01T09:00:00+00:00","customer_portal_enabled":null,"customer_portal_id":"HWYGf6vzKsjwpS","customer_portal_id_override":null,"customer_portal_link":null,"customer_portal_payment_option":null,"customer_profiles":[{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"}],"default_payment_term_id":null,"default_pricing_group_id":null,"default_warehouse_id":null,"deposit_due_amount":0,"display_customer_portal_id":"HWYGf6vzKsjwpS","external_type":null,"has_customer_portal_id_override":false,"held_credit":0,"hide":false,"id":"V4keXwwxMQyXw7","internal_notes":null,"is_editable":true,"is_external":false,"is_system":false,"last_ordered_date":"2026-10-28T08:00:00+00:00","media":[{"collection":"tax_exemption","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"customer_id":"V4keXwwxMQyXw7","file_name":"resale-certificate.pdf","id":"4GR9C3ZTMYtda5","is_image":false,"mime_type":"application/pdf","name":"Resale certificate 2026.pdf","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/4GR9C3ZTMYtda5/download","view_url":"https://example.com/media/4GR9C3ZTMYtda5/view"}],"name":"Northwind Apparel","ordered_amount":125000,"overdue_amount":0,"pdf":{"invoice_statement":"https://example.com/pdf/customer_invoice_statement/V4keXwwxMQyXw7"},"quote_amount":0,"resale_number":null,"shopify_compliance_deletion":null,"system_type":null,"tags":[{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"}],"tax_exempt":false,"third_party_billing_default":"none","trashed":false,"unpaid_amount":25000,"updated_at":"2026-11-01T09:00:00+00:00","vat_number":null,"wallet_currency":{"default":true,"id":"icHZvqV1nkXRcA","iso":"USD","name":"US Dollar","symbol":"$","trashed":false},"wallet_fund":50000,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"account_warning":{"additionalProperties":false,"description":"Why YoPrint shows a warning next to the customer's name. Null when there is nothing to warn about.","properties":{"open_dispute":{"additionalProperties":false,"description":"The customer's payments under a dispute that is open or under review; null when there is none.","properties":{"count":{"description":"How many payments are disputed.","type":"integer"},"payment_amount":{"description":"The total of the disputed payments, each counted once. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]}},"required":["payment_amount","count"],"type":["object","null"]},"owed_amount":{"description":"What the customer owes back because `wallet_fund` is negative, as a positive amount; null when it is not negative. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]}},"required":["owed_amount","open_dispute"],"type":["object","null"]},"addresses":{"description":"Billing and shipping addresses that are not deleted, old copies replaced by an edit included (`is_current_source: false`).","items":{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},"type":"array"},"assigned_users":{"description":"The users assigned to the customer. Unlike List the users assigned to a customer, people who have left the team stay in this list.","items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","avatar_url","name"],"type":"object"},"type":"array"},"contacts":{"description":"Every contact, deleted ones included (`trashed`).","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"customer_portal_enabled":{"description":"Whether the customer's contacts can open the Customer Portal (Portal settings > Customer portal in YoPrint). `false`: the portal is off for this customer. `true`, or null (never set), means on.","type":["boolean","null"]},"customer_portal_id":{"description":"The id used in the customer's portal address. Null for Shopify customers.","type":["string","null"]},"customer_portal_id_override":{"type":["string","null"]},"customer_portal_link":{"description":"Always null: YoPrint no longer returns a portal sign-in link for the customer. The field stays for older integrations.","type":"null"},"customer_portal_payment_option":{"description":"Whether the customer can pay online in the portal. Null follows the team setting (and is always null for Shopify customers).","enum":["ENABLED","DISABLED",null],"type":["string","null"]},"customer_profiles":{"description":"Brand profiles.","items":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"type":"array"},"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"default_warehouse_id":{"type":["string","null"]},"deposit_due_amount":{"description":"Deposits still due. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"display_customer_portal_id":{"description":"The Customer Portal ID shown to people: the override when set, otherwise `customer_portal_id`. `-` for Shopify customers.","type":"string"},"external_type":{"description":"`shopify` for customers synced from Shopify.","type":["string","null"]},"has_customer_portal_id_override":{"type":"boolean"},"held_credit":{"description":"The part of `wallet_fund` held while a payment is under an open dispute or a provider review: it can't be applied to orders or taken out until the hold ends. Never more than `wallet_fund`; 0 when `wallet_fund` is 0 or negative. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"hide":{"description":"True when the customer is archived.","type":"boolean"},"id":{"description":"The customer id. Use it in paths and as `customer_id` on sales orders and quotes.","type":"string"},"internal_notes":{"type":["string","null"]},"is_editable":{"description":"False for Shopify and system customers: they can't be changed through this API.","type":"boolean"},"is_external":{"type":"boolean"},"is_system":{"type":"boolean"},"last_ordered_date":{"description":"The issue date of the customer's latest published sales order. Null when it has none.","format":"date-time","type":["string","null"]},"media":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"name":{"description":"Null for a customer created by upsert without a name.","type":["string","null"]},"ordered_amount":{"description":"Total of the customer's published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"overdue_amount":{"description":"Unpaid amounts past their payment due date. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"pdf":{"additionalProperties":false,"properties":{"invoice_statement":{"description":"A link that downloads the customer's invoice statement PDF. Its token opens only this customer's statement and stops working 9,000 hours (about a year) after the answer was made. Anyone with the link can download the statement: don't share it.","type":"string"}},"required":["invoice_statement"],"type":"object"},"quote_amount":{"description":"Total of open quotes. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"resale_number":{"type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"type":["object","null"]},"system_type":{"type":["string","null"]},"tags":{"items":{"additionalProperties":false,"properties":{"color_hex":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"tax_exempt":{"type":"boolean"},"third_party_billing_default":{"description":"How a shipping label for this customer is billed by default. `default_carrier_account`: YoPrint's label and rate dialogs start on the customer's default carrier account (third-party billing). `none`: they start with no third-party billing.","enum":["none","default_carrier_account"],"type":"string"},"trashed":{"description":"True when the customer is deleted.","type":"boolean"},"unpaid_amount":{"description":"What the customer still owes on published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"updated_at":{"format":"date-time","type":"string"},"vat_number":{"description":"The customer's tax number (shown as Tax number in YoPrint).","type":["string","null"]},"wallet_currency":{"additionalProperties":false,"description":"The team's default currency, the one `wallet_fund` is in. `iso` is its code.","properties":{"default":{"type":"boolean"},"id":{"type":"string"},"iso":{"description":"The ISO 4217 code, such as `USD`.","type":["string","null"]},"name":{"type":["string","null"]},"symbol":{"type":["string","null"]},"trashed":{"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"wallet_fund":{"description":"Customer credit balance. Negative when the customer owes credit back, for example after a refund of a payment whose credit was already spent. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"website":{"type":["string","null"]}},"required":["id","name","tax_exempt","trashed","hide","is_external","is_system","is_editable","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":null,"address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"4wlvetojbGb1qm","is_current_source":false,"is_default_warehouse":false,"is_external":false,"is_primary":false,"label":"Old warehouse","nexus":true,"note":null,"owner_id":"wJ4pqoTlhaVKLM","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":true},"message_code":"blocked_external_or_compliance","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_external_or_compliance","stale_base":null},"message":"blocked_external_or_compliance","success":false},"schema":{"additionalProperties":false,"properties":{"address_save_result":{"additionalProperties":true,"description":"What the save did.","properties":{"current_address":{"additionalProperties":true,"description":"On a refusal: the address to edit instead.","type":["object","null"]},"message_code":{"description":"The message code for what happened, identical to `save_mode`.","type":"string"},"operation_key":{"description":"The key you sent, or one YoPrint made.","type":["string","null"]},"previous_address":{"additionalProperties":true,"type":["object","null"]},"replacement_address":{"additionalProperties":true,"type":["object","null"]},"save_mode":{"enum":["updated_in_place_unused","created_replacement_address_used","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"stale_base":{"additionalProperties":true,"type":["object","null"]}},"required":["save_mode","message_code","operation_key"],"type":"object"},"message":{"description":"The `save_mode`.","enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"type":"object"}}},"description":"`default_warehouse_id` names a company location that is deleted, synced from another system or redacted (`blocked_external_or_compliance`; `current_address` is that location), or one replaced by an edit (`blocked_superseded_historical_address`; `current_address` is its replacement). Not the usual error envelope: `success: false`, `address_save_result` and `message` (the `save_mode`); no `status` or `error`."},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create or update a customer by contact","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Send `perform_upsert` and a `contact` with `first_name`, `send_invoice` and `is_primary`.","status":422,"when":"`perform_upsert` or a required contact field is missing, or the phone is not valid for `phone_country`. `error.code` is `validation_failed`."},{"fix":"Use the id of a current company location from List company locations.","status":422,"when":"`default_warehouse_id` is not a company location of the team (`error.code` `invalid_default_warehouse`)."},{"fix":"Send a valid email of at most 191 characters.","status":422,"when":"A new customer's `contact.email` is longer than 191 characters (`error.code` `customer_portal_email_invalid`, \"Enter a valid email address using supported characters.\"). Nothing is saved."},{"fix":"For `blocked_superseded_historical_address`, use `address_save_result.current_address.id`. For `blocked_external_or_compliance`, `current_address` is the same location: pick another current one from List company locations.","status":409,"when":"`default_warehouse_id` names a company location that was replaced by an edit (`address_save_result.save_mode` `blocked_superseded_historical_address`), or one that was deleted, is synced from another system or was redacted (`blocked_external_or_compliance`). Not the usual error envelope: the body has `success: false`, `address_save_result` and `message`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."}],"group":"Customers","notes":["The contact is not updated on a match. To change it, update it with the customer contact operations.","To find a customer by email without writing, there is no filter or search. Either page through List customers and read each customer's contacts with List a customer's contacts (one call per customer), or run Export customers: its CSV has one row per contact, with the customer's `id` and `contact_email`.","Retries: with `perform_upsert: true`, repeating a call that timed out matches the customer it created and writes the same fields again (and sends another webhook). With `perform_upsert: false`, a repeat creates a second customer."],"permission":"Any member of the team. No customer permission is checked, and a matched customer is updated even when it isn't assigned to you.","related":["v1_public_customer_store","v1_public_customer_contact_upsert","v1_public_customer_update_patch","v1_public_customer_contact_primary","v1_public_data_export_export_customer"],"rules":["`is_external` and `external_type` are ignored on customers and their contacts: sending them (for example a value you read back) is not refused and changes nothing. Only the Shopify sync sets them. Other fields not listed here are not part of the API.","`contact` is required and needs `first_name`, `send_invoice` and `is_primary`, even when an existing customer is matched.","Matching looks at every live customer of the team, archived ones included, and takes the first match. Send `email` or `phone`, not both: with both, either may match.","With `perform_upsert: true`, send `contact.email` or `contact.phone`. With neither, the first customer that has any contact is matched and updated.","A matched Shopify or system customer is refused (422), and nothing is written.","`default_warehouse_id` must be a current company location.","The contact of a new customer is never made primary, whatever `is_primary` says (it is required but not used). Make it primary with Set the primary contact."],"side_effects":["Sends `customer.updated` when a customer is matched, or `customer.created` when one is created.","A new customer is assigned to you. Its contact's email is saved trimmed and in lower case.","For a new customer: when the contact's email already belongs to a Customer Portal account on your team that can't open this customer yet, saving the contact gives that account access to this customer (active when the account is set up with a verified email or a password, invited otherwise). No email is sent."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}":{"delete":{"description":"Deletes a customer. The customer can be restored later; its sales orders, quotes, invoices and payments stay as they are.\n\nRefused with 422 `delete_fail` while the customer has an open quote or sales order: any saved quote or sales order whose status is not a final (end) status. Finish, cancel or delete those first, or archive the customer instead (`hide: true`).","operationId":"v1_public_customer_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a customer","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Move those orders to a final status or delete them, or archive the customer with `hide: true`.","status":422,"when":"The customer has an open quote or sales order (`error.code` `delete_fail`, `error.message` \"This customer can't be removed while it has an open quote or sales order.\")."},{"fix":"Ask for Manage Customers \"Manage All\", or to be assigned to the customer.","status":403,"when":"Your role can't change this customer: it has no Manage Customers permission, or it manages only customers assigned to you and this one is not. This 403 has a short body, `{\"message\": \"No Permission to update Customer\"}`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the id. Find deleted customers with the `trashed_only` filter and restore them first.","status":404,"when":"No live customer with this id in the team: deleted customers are not found here. `error.code` is null and `error.message` names the record type."}],"group":"Customers","notes":["Deleted customers are hidden from lists. Find them with the `trashed_only` filter and bring them back with Restore a customer."],"permission":"Needs the Manage Customers permission: \"Manage All\" for any customer, or \"Manage Assigned to User\" for customers assigned to you.","related":["v1_public_customer_restore","v1_public_customer_update_patch"],"rules":["Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."],"side_effects":["Sends the `customer.deleted` webhook."]}},"get":{"description":"Returns one customer, deleted ones included (`trashed`), with its `contacts` (deleted ones included), `addresses` (current and old copies), `customer_profiles`, `assigned_users`, `tags` and `media`. The answer also says how much credit is held (`held_credit`) and why the customer carries a warning (`account_warning`).","operationId":"v1_public_customer_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_warning":null,"addresses":[{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":true},{"address1":"100 Example Street","address2":"Dock 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"swtHxyIfOvF62K","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Warehouse","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false}],"assigned_users":[{"avatar_url":"https://example.com/avatars/alex.png","id":"lOURnovd3hkIQI","name":"Alex Rivera"}],"contacts":[{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"}],"created_at":"2026-10-01T09:00:00+00:00","customer_portal_enabled":null,"customer_portal_id":"HWYGf6vzKsjwpS","customer_portal_id_override":null,"customer_portal_link":null,"customer_portal_payment_option":null,"customer_profiles":[{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"}],"default_payment_term_id":null,"default_pricing_group_id":null,"default_warehouse_id":null,"deposit_due_amount":0,"display_customer_portal_id":"HWYGf6vzKsjwpS","external_type":null,"has_customer_portal_id_override":false,"held_credit":0,"hide":false,"id":"V4keXwwxMQyXw7","internal_notes":null,"is_editable":true,"is_external":false,"is_system":false,"last_ordered_date":"2026-10-28T08:00:00+00:00","media":[{"collection":"tax_exemption","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"customer_id":"V4keXwwxMQyXw7","file_name":"resale-certificate.pdf","id":"4GR9C3ZTMYtda5","is_image":false,"mime_type":"application/pdf","name":"Resale certificate 2026.pdf","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/4GR9C3ZTMYtda5/download","view_url":"https://example.com/media/4GR9C3ZTMYtda5/view"}],"name":"Northwind Apparel","ordered_amount":125000,"overdue_amount":0,"pdf":{"invoice_statement":"https://example.com/pdf/customer_invoice_statement/V4keXwwxMQyXw7"},"quote_amount":0,"resale_number":null,"shopify_compliance_deletion":null,"system_type":null,"tags":[{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"}],"tax_exempt":false,"third_party_billing_default":"none","trashed":false,"unpaid_amount":25000,"updated_at":"2026-11-01T09:00:00+00:00","vat_number":null,"wallet_currency":{"default":true,"id":"icHZvqV1nkXRcA","iso":"USD","name":"US Dollar","symbol":"$","trashed":false},"wallet_fund":50000,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"account_warning":{"additionalProperties":false,"description":"Why YoPrint shows a warning next to the customer's name. Null when there is nothing to warn about.","properties":{"open_dispute":{"additionalProperties":false,"description":"The customer's payments under a dispute that is open or under review; null when there is none.","properties":{"count":{"description":"How many payments are disputed.","type":"integer"},"payment_amount":{"description":"The total of the disputed payments, each counted once. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]}},"required":["payment_amount","count"],"type":["object","null"]},"owed_amount":{"description":"What the customer owes back because `wallet_fund` is negative, as a positive amount; null when it is not negative. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]}},"required":["owed_amount","open_dispute"],"type":["object","null"]},"addresses":{"description":"Billing and shipping addresses that are not deleted, old copies replaced by an edit included (`is_current_source: false`).","items":{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},"type":"array"},"assigned_users":{"description":"The users assigned to the customer. Unlike List the users assigned to a customer, people who have left the team stay in this list.","items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","avatar_url","name"],"type":"object"},"type":"array"},"contacts":{"description":"Every contact, deleted ones included (`trashed`).","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"customer_portal_enabled":{"description":"Whether the customer's contacts can open the Customer Portal (Portal settings > Customer portal in YoPrint). `false`: the portal is off for this customer. `true`, or null (never set), means on.","type":["boolean","null"]},"customer_portal_id":{"description":"The id used in the customer's portal address. Null for Shopify customers.","type":["string","null"]},"customer_portal_id_override":{"type":["string","null"]},"customer_portal_link":{"description":"Always null: YoPrint no longer returns a portal sign-in link for the customer. The field stays for older integrations.","type":"null"},"customer_portal_payment_option":{"description":"Whether the customer can pay online in the portal. Null follows the team setting (and is always null for Shopify customers).","enum":["ENABLED","DISABLED",null],"type":["string","null"]},"customer_profiles":{"description":"Brand profiles.","items":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"type":"array"},"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"default_warehouse_id":{"type":["string","null"]},"deposit_due_amount":{"description":"Deposits still due. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"display_customer_portal_id":{"description":"The Customer Portal ID shown to people: the override when set, otherwise `customer_portal_id`. `-` for Shopify customers.","type":"string"},"external_type":{"description":"`shopify` for customers synced from Shopify.","type":["string","null"]},"has_customer_portal_id_override":{"type":"boolean"},"held_credit":{"description":"The part of `wallet_fund` held while a payment is under an open dispute or a provider review: it can't be applied to orders or taken out until the hold ends. Never more than `wallet_fund`; 0 when `wallet_fund` is 0 or negative. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"hide":{"description":"True when the customer is archived.","type":"boolean"},"id":{"description":"The customer id. Use it in paths and as `customer_id` on sales orders and quotes.","type":"string"},"internal_notes":{"type":["string","null"]},"is_editable":{"description":"False for Shopify and system customers: they can't be changed through this API.","type":"boolean"},"is_external":{"type":"boolean"},"is_system":{"type":"boolean"},"last_ordered_date":{"description":"The issue date of the customer's latest published sales order. Null when it has none.","format":"date-time","type":["string","null"]},"media":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"name":{"description":"Null for a customer created by upsert without a name.","type":["string","null"]},"ordered_amount":{"description":"Total of the customer's published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"overdue_amount":{"description":"Unpaid amounts past their payment due date. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"pdf":{"additionalProperties":false,"properties":{"invoice_statement":{"description":"A link that downloads the customer's invoice statement PDF. Its token opens only this customer's statement and stops working 9,000 hours (about a year) after the answer was made. Anyone with the link can download the statement: don't share it.","type":"string"}},"required":["invoice_statement"],"type":"object"},"quote_amount":{"description":"Total of open quotes. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"resale_number":{"type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"type":["object","null"]},"system_type":{"type":["string","null"]},"tags":{"items":{"additionalProperties":false,"properties":{"color_hex":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"tax_exempt":{"type":"boolean"},"third_party_billing_default":{"description":"How a shipping label for this customer is billed by default. `default_carrier_account`: YoPrint's label and rate dialogs start on the customer's default carrier account (third-party billing). `none`: they start with no third-party billing.","enum":["none","default_carrier_account"],"type":"string"},"trashed":{"description":"True when the customer is deleted.","type":"boolean"},"unpaid_amount":{"description":"What the customer still owes on published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"updated_at":{"format":"date-time","type":"string"},"vat_number":{"description":"The customer's tax number (shown as Tax number in YoPrint).","type":["string","null"]},"wallet_currency":{"additionalProperties":false,"description":"The team's default currency, the one `wallet_fund` is in. `iso` is its code.","properties":{"default":{"type":"boolean"},"id":{"type":"string"},"iso":{"description":"The ISO 4217 code, such as `USD`.","type":["string","null"]},"name":{"type":["string","null"]},"symbol":{"type":["string","null"]},"trashed":{"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"wallet_fund":{"description":"Customer credit balance. Negative when the customer owes credit back, for example after a refund of a payment whose credit was already spent. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"website":{"type":["string","null"]}},"required":["id","name","tax_exempt","trashed","hide","is_external","is_system","is_editable","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a customer","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Ask for Manage Customers \"Manage All\", or to be assigned to the customer.","status":403,"when":"Your role has no Manage Customers permission, or it manages only customers assigned to you and this one is not. This 403 has a short body, `{\"message\": \"You do not have permission to view customer\"}`."},{"fix":"Check the id.","status":404,"when":"No customer with this id in the team, deleted or not. `error.code` is null and `error.message` names the record type."}],"group":"Customers","notes":["To list only a customer's current addresses, use List customer addresses: it hides replaced copies.","`pdf.invoice_statement` downloads the customer's statement without signing in. Do not log or share it."],"permission":"Needs the Manage Customers permission. At \"Manage Assigned to User\" only customers assigned to you are allowed; other customers answer 403.","related":["v1_public_customer_update_patch","v1_public_customer_activity_summary","v1_public_customer_address_index"]}},"patch":{"description":"Changes the customer's own fields. Send only the fields you want to change. Contacts, addresses and brand profiles have their own operations.\n\nUse `PUT`: it checks the fields below. `PATCH` takes the same body but checks nothing. Returns the customer with `contacts`.","operationId":"v1_public_customer_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"archive":{"summary":"Archive a customer","value":{"hide":true}},"defaults":{"summary":"Set the defaults new orders use","value":{"default_payment_term_id":"bONlIEdEsNFoAl","default_pricing_group_id":"lRnxHMMGPGfVN3","default_warehouse_id":"ILBTtiKrRcSSGA"}},"portal_off":{"summary":"Turn the Customer Portal off for a customer","value":{"customer_portal_enabled":false}}},"schema":{"additionalProperties":false,"properties":{"customer_portal_enabled":{"description":"`false` turns the Customer Portal off for this customer: its contacts can no longer open the portal, through existing links or signed-in sessions. `true` or null turns it back on. Its records and payment settings are kept.","type":["boolean","null"]},"customer_portal_payment_option":{"description":"Null goes back to the team setting.","enum":["ENABLED","DISABLED",null],"type":["string","null"]},"default_payment_term_id":{"description":"A payment term id, or null to clear it.","type":["string","null"]},"default_pricing_group_id":{"description":"A pricing group id, or null to clear it. New sales orders for this customer use it. Pricing groups are not listed on the public API: copy `pricing_group_id` from a sales order or quote that uses the group (Get a sales order or quote), or `default_pricing_group_id` from another customer that has it.","type":["string","null"]},"default_warehouse_id":{"description":"A current company location (store location) id, or null to clear it. New sales orders for this customer ship from it.","type":["string","null"]},"hide":{"description":"True archives the customer, false brings it back.","type":"boolean"},"internal_notes":{"description":"Notes for your team only.","type":"string"},"name":{"description":"The customer's name, usually the company.","type":"string"},"resale_number":{"description":"The customer's resale or tax certificate number.","type":"string"},"tax_exempt":{"description":"True when no sales tax applies to this customer.","type":"boolean"},"third_party_billing_default":{"description":"`default_carrier_account` starts the customer's shipping labels on its default carrier account; `none` starts them with no third-party billing.","enum":["none","default_carrier_account"],"type":"string"},"vat_number":{"description":"Tax number.","type":"string"},"website":{"description":"The website address.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_warning":null,"addresses":[{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":true},{"address1":"100 Example Street","address2":"Dock 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"swtHxyIfOvF62K","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Warehouse","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false}],"assigned_users":[{"avatar_url":"https://example.com/avatars/alex.png","id":"lOURnovd3hkIQI","name":"Alex Rivera"}],"contacts":[{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"}],"created_at":"2026-10-01T09:00:00+00:00","customer_portal_enabled":null,"customer_portal_id":"HWYGf6vzKsjwpS","customer_portal_id_override":null,"customer_portal_link":null,"customer_portal_payment_option":null,"customer_profiles":[{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"}],"default_payment_term_id":"bONlIEdEsNFoAl","default_pricing_group_id":"lRnxHMMGPGfVN3","default_warehouse_id":"ILBTtiKrRcSSGA","deposit_due_amount":0,"display_customer_portal_id":"HWYGf6vzKsjwpS","external_type":null,"has_customer_portal_id_override":false,"held_credit":0,"hide":false,"id":"V4keXwwxMQyXw7","internal_notes":null,"is_editable":true,"is_external":false,"is_system":false,"last_ordered_date":"2026-10-28T08:00:00+00:00","media":[{"collection":"tax_exemption","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"customer_id":"V4keXwwxMQyXw7","file_name":"resale-certificate.pdf","id":"4GR9C3ZTMYtda5","is_image":false,"mime_type":"application/pdf","name":"Resale certificate 2026.pdf","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/4GR9C3ZTMYtda5/download","view_url":"https://example.com/media/4GR9C3ZTMYtda5/view"}],"name":"Northwind Apparel","ordered_amount":125000,"overdue_amount":0,"pdf":{"invoice_statement":"https://example.com/pdf/customer_invoice_statement/V4keXwwxMQyXw7"},"quote_amount":0,"resale_number":null,"shopify_compliance_deletion":null,"system_type":null,"tags":[{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"}],"tax_exempt":false,"third_party_billing_default":"none","trashed":false,"unpaid_amount":25000,"updated_at":"2026-11-01T09:00:00+00:00","vat_number":null,"wallet_currency":{"default":true,"id":"icHZvqV1nkXRcA","iso":"USD","name":"US Dollar","symbol":"$","trashed":false},"wallet_fund":50000,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"account_warning":{"additionalProperties":false,"description":"Why YoPrint shows a warning next to the customer's name. Null when there is nothing to warn about.","properties":{"open_dispute":{"additionalProperties":false,"description":"The customer's payments under a dispute that is open or under review; null when there is none.","properties":{"count":{"description":"How many payments are disputed.","type":"integer"},"payment_amount":{"description":"The total of the disputed payments, each counted once. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]}},"required":["payment_amount","count"],"type":["object","null"]},"owed_amount":{"description":"What the customer owes back because `wallet_fund` is negative, as a positive amount; null when it is not negative. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]}},"required":["owed_amount","open_dispute"],"type":["object","null"]},"addresses":{"description":"Billing and shipping addresses that are not deleted, old copies replaced by an edit included (`is_current_source: false`).","items":{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},"type":"array"},"assigned_users":{"description":"The users assigned to the customer. Unlike List the users assigned to a customer, people who have left the team stay in this list.","items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","avatar_url","name"],"type":"object"},"type":"array"},"contacts":{"description":"Every contact, deleted ones included (`trashed`).","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"customer_portal_enabled":{"description":"Whether the customer's contacts can open the Customer Portal (Portal settings > Customer portal in YoPrint). `false`: the portal is off for this customer. `true`, or null (never set), means on.","type":["boolean","null"]},"customer_portal_id":{"description":"The id used in the customer's portal address. Null for Shopify customers.","type":["string","null"]},"customer_portal_id_override":{"type":["string","null"]},"customer_portal_link":{"description":"Always null: YoPrint no longer returns a portal sign-in link for the customer. The field stays for older integrations.","type":"null"},"customer_portal_payment_option":{"description":"Whether the customer can pay online in the portal. Null follows the team setting (and is always null for Shopify customers).","enum":["ENABLED","DISABLED",null],"type":["string","null"]},"customer_profiles":{"description":"Brand profiles.","items":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"type":"array"},"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"default_warehouse_id":{"type":["string","null"]},"deposit_due_amount":{"description":"Deposits still due. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"display_customer_portal_id":{"description":"The Customer Portal ID shown to people: the override when set, otherwise `customer_portal_id`. `-` for Shopify customers.","type":"string"},"external_type":{"description":"`shopify` for customers synced from Shopify.","type":["string","null"]},"has_customer_portal_id_override":{"type":"boolean"},"held_credit":{"description":"The part of `wallet_fund` held while a payment is under an open dispute or a provider review: it can't be applied to orders or taken out until the hold ends. Never more than `wallet_fund`; 0 when `wallet_fund` is 0 or negative. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"hide":{"description":"True when the customer is archived.","type":"boolean"},"id":{"description":"The customer id. Use it in paths and as `customer_id` on sales orders and quotes.","type":"string"},"internal_notes":{"type":["string","null"]},"is_editable":{"description":"False for Shopify and system customers: they can't be changed through this API.","type":"boolean"},"is_external":{"type":"boolean"},"is_system":{"type":"boolean"},"last_ordered_date":{"description":"The issue date of the customer's latest published sales order. Null when it has none.","format":"date-time","type":["string","null"]},"media":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"name":{"description":"Null for a customer created by upsert without a name.","type":["string","null"]},"ordered_amount":{"description":"Total of the customer's published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"overdue_amount":{"description":"Unpaid amounts past their payment due date. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"pdf":{"additionalProperties":false,"properties":{"invoice_statement":{"description":"A link that downloads the customer's invoice statement PDF. Its token opens only this customer's statement and stops working 9,000 hours (about a year) after the answer was made. Anyone with the link can download the statement: don't share it.","type":"string"}},"required":["invoice_statement"],"type":"object"},"quote_amount":{"description":"Total of open quotes. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"resale_number":{"type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"type":["object","null"]},"system_type":{"type":["string","null"]},"tags":{"items":{"additionalProperties":false,"properties":{"color_hex":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"tax_exempt":{"type":"boolean"},"third_party_billing_default":{"description":"How a shipping label for this customer is billed by default. `default_carrier_account`: YoPrint's label and rate dialogs start on the customer's default carrier account (third-party billing). `none`: they start with no third-party billing.","enum":["none","default_carrier_account"],"type":"string"},"trashed":{"description":"True when the customer is deleted.","type":"boolean"},"unpaid_amount":{"description":"What the customer still owes on published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"updated_at":{"format":"date-time","type":"string"},"vat_number":{"description":"The customer's tax number (shown as Tax number in YoPrint).","type":["string","null"]},"wallet_currency":{"additionalProperties":false,"description":"The team's default currency, the one `wallet_fund` is in. `iso` is its code.","properties":{"default":{"type":"boolean"},"id":{"type":"string"},"iso":{"description":"The ISO 4217 code, such as `USD`.","type":["string","null"]},"name":{"type":["string","null"]},"symbol":{"type":["string","null"]},"trashed":{"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"wallet_fund":{"description":"Customer credit balance. Negative when the customer owes credit back, for example after a refund of a payment whose credit was already spent. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"website":{"type":["string","null"]}},"required":["id","name","tax_exempt","trashed","hide","is_external","is_system","is_editable","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":null,"address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"4wlvetojbGb1qm","is_current_source":false,"is_default_warehouse":false,"is_external":false,"is_primary":false,"label":"Old warehouse","nexus":true,"note":null,"owner_id":"wJ4pqoTlhaVKLM","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":true},"message_code":"blocked_external_or_compliance","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_external_or_compliance","stale_base":null},"message":"blocked_external_or_compliance","success":false},"schema":{"additionalProperties":false,"properties":{"address_save_result":{"additionalProperties":true,"description":"What the save did.","properties":{"current_address":{"additionalProperties":true,"description":"On a refusal: the address to edit instead.","type":["object","null"]},"message_code":{"description":"The message code for what happened, identical to `save_mode`.","type":"string"},"operation_key":{"description":"The key you sent, or one YoPrint made.","type":["string","null"]},"previous_address":{"additionalProperties":true,"type":["object","null"]},"replacement_address":{"additionalProperties":true,"type":["object","null"]},"save_mode":{"enum":["updated_in_place_unused","created_replacement_address_used","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"stale_base":{"additionalProperties":true,"type":["object","null"]}},"required":["save_mode","message_code","operation_key"],"type":"object"},"message":{"description":"The `save_mode`.","enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"type":"object"}}},"description":"`default_warehouse_id` names a company location that is deleted, synced from another system or redacted (`blocked_external_or_compliance`; `current_address` is that location), or one replaced by an edit (`blocked_superseded_historical_address`; `current_address` is its replacement). Not the usual error envelope: `success: false`, `address_save_result` and `message` (the `save_mode`); no `status` or `error`."},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a customer (PATCH)","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Ask for Manage Customers \"Manage All\", or to be assigned to the customer.","status":403,"when":"Your role can't change this customer: it has no Manage Customers permission, or it manages only customers assigned to you and this one is not. This 403 has a short body, `{\"message\": \"No Permission to update Customer\"}`."},{"fix":"Use the id of a current company location from List company locations; check the field types.","status":422,"when":"`default_warehouse_id` is not a company location of the team (`error.code` `invalid_default_warehouse`), or a field has the wrong type (`validation_failed`)."},{"fix":"Copy `pricing_group_id` from a sales order that uses a live group, or turn the group on in Pricing groups.","status":422,"when":"`default_pricing_group_id` can't be used: not one of the team's published groups (`validation_error`, \"Choose one of your pricing groups.\" on `default_pricing_group_id` in `error.fields`), removed (`pricing_group_removed`, with `error.pricing_group`), or turned off (`pricing_group_disabled`, with `error.pricing_group` and `error.fields`)."},{"fix":"For `blocked_superseded_historical_address`, use `address_save_result.current_address.id`. For `blocked_external_or_compliance`, `current_address` is the same location: pick another current one from List company locations.","status":409,"when":"`default_warehouse_id` names a company location that was replaced by an edit (`address_save_result.save_mode` `blocked_superseded_historical_address`), or one that was deleted, is synced from another system or was redacted (`blocked_external_or_compliance`). Not the usual error envelope: the body has `success: false`, `address_save_result` and `message`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the id. Find deleted customers with the `trashed_only` filter and restore them first.","status":404,"when":"No live customer with this id in the team: deleted customers are not found here. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission: \"Manage All\" for any customer, or \"Manage Assigned to User\" for customers assigned to you.","related":["v1_public_customer_show","v1_public_customer_contact_update_patch","v1_public_customer_address_update","v1_public_location_index","v1_public_payment_term_index"],"rules":["`is_external` and `external_type` are ignored on customers and their contacts: sending them (for example a value you read back) is not refused and changes nothing. Only the Shopify sync sets them. Other fields not listed here are not part of the API.","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\").","`default_warehouse_id` must be a current company location of the team.","A new `default_pricing_group_id` must be one of the team's published pricing groups that is turned on. Sending the customer's current group again is fine even if it was turned off since.","`default_payment_term_id`, `default_pricing_group_id`, `default_warehouse_id`, `customer_portal_payment_option` and `customer_portal_enabled` can be cleared with `null`. Any other field sent as `null` is dropped; send an empty string to blank a text field.","Changing the defaults affects new sales orders only; existing ones keep theirs."],"side_effects":["Sends the `customer.updated` webhook.","Open Customer Portal pages of this customer are told to refresh."]}},"put":{"description":"Changes the customer's own fields. Send only the fields you want to change. Contacts, addresses and brand profiles have their own operations.\n\nUse `PUT`: it checks the fields below. `PATCH` takes the same body but checks nothing. Returns the customer with `contacts`.","operationId":"v1_public_customer_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"archive":{"summary":"Archive a customer","value":{"hide":true}},"defaults":{"summary":"Set the defaults new orders use","value":{"default_payment_term_id":"bONlIEdEsNFoAl","default_pricing_group_id":"lRnxHMMGPGfVN3","default_warehouse_id":"ILBTtiKrRcSSGA"}},"portal_off":{"summary":"Turn the Customer Portal off for a customer","value":{"customer_portal_enabled":false}}},"schema":{"additionalProperties":false,"properties":{"customer_portal_enabled":{"description":"`false` turns the Customer Portal off for this customer: its contacts can no longer open the portal, through existing links or signed-in sessions. `true` or null turns it back on. Its records and payment settings are kept.","type":["boolean","null"]},"customer_portal_payment_option":{"description":"Null goes back to the team setting.","enum":["ENABLED","DISABLED",null],"type":["string","null"]},"default_payment_term_id":{"description":"A payment term id, or null to clear it.","type":["string","null"]},"default_pricing_group_id":{"description":"A pricing group id, or null to clear it. New sales orders for this customer use it. Pricing groups are not listed on the public API: copy `pricing_group_id` from a sales order or quote that uses the group (Get a sales order or quote), or `default_pricing_group_id` from another customer that has it.","type":["string","null"]},"default_warehouse_id":{"description":"A current company location (store location) id, or null to clear it. New sales orders for this customer ship from it.","type":["string","null"]},"hide":{"description":"True archives the customer, false brings it back.","type":"boolean"},"internal_notes":{"description":"Notes for your team only.","type":"string"},"name":{"description":"The customer's name, usually the company.","type":"string"},"resale_number":{"description":"The customer's resale or tax certificate number.","type":"string"},"tax_exempt":{"description":"True when no sales tax applies to this customer.","type":"boolean"},"third_party_billing_default":{"description":"`default_carrier_account` starts the customer's shipping labels on its default carrier account; `none` starts them with no third-party billing.","enum":["none","default_carrier_account"],"type":"string"},"vat_number":{"description":"Tax number.","type":"string"},"website":{"description":"The website address.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_warning":null,"addresses":[{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":true},{"address1":"100 Example Street","address2":"Dock 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"swtHxyIfOvF62K","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Warehouse","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false}],"assigned_users":[{"avatar_url":"https://example.com/avatars/alex.png","id":"lOURnovd3hkIQI","name":"Alex Rivera"}],"contacts":[{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"}],"created_at":"2026-10-01T09:00:00+00:00","customer_portal_enabled":null,"customer_portal_id":"HWYGf6vzKsjwpS","customer_portal_id_override":null,"customer_portal_link":null,"customer_portal_payment_option":null,"customer_profiles":[{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"}],"default_payment_term_id":"bONlIEdEsNFoAl","default_pricing_group_id":"lRnxHMMGPGfVN3","default_warehouse_id":"ILBTtiKrRcSSGA","deposit_due_amount":0,"display_customer_portal_id":"HWYGf6vzKsjwpS","external_type":null,"has_customer_portal_id_override":false,"held_credit":0,"hide":false,"id":"V4keXwwxMQyXw7","internal_notes":null,"is_editable":true,"is_external":false,"is_system":false,"last_ordered_date":"2026-10-28T08:00:00+00:00","media":[{"collection":"tax_exemption","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"customer_id":"V4keXwwxMQyXw7","file_name":"resale-certificate.pdf","id":"4GR9C3ZTMYtda5","is_image":false,"mime_type":"application/pdf","name":"Resale certificate 2026.pdf","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/4GR9C3ZTMYtda5/download","view_url":"https://example.com/media/4GR9C3ZTMYtda5/view"}],"name":"Northwind Apparel","ordered_amount":125000,"overdue_amount":0,"pdf":{"invoice_statement":"https://example.com/pdf/customer_invoice_statement/V4keXwwxMQyXw7"},"quote_amount":0,"resale_number":null,"shopify_compliance_deletion":null,"system_type":null,"tags":[{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"}],"tax_exempt":false,"third_party_billing_default":"none","trashed":false,"unpaid_amount":25000,"updated_at":"2026-11-01T09:00:00+00:00","vat_number":null,"wallet_currency":{"default":true,"id":"icHZvqV1nkXRcA","iso":"USD","name":"US Dollar","symbol":"$","trashed":false},"wallet_fund":50000,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"account_warning":{"additionalProperties":false,"description":"Why YoPrint shows a warning next to the customer's name. Null when there is nothing to warn about.","properties":{"open_dispute":{"additionalProperties":false,"description":"The customer's payments under a dispute that is open or under review; null when there is none.","properties":{"count":{"description":"How many payments are disputed.","type":"integer"},"payment_amount":{"description":"The total of the disputed payments, each counted once. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]}},"required":["payment_amount","count"],"type":["object","null"]},"owed_amount":{"description":"What the customer owes back because `wallet_fund` is negative, as a positive amount; null when it is not negative. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]}},"required":["owed_amount","open_dispute"],"type":["object","null"]},"addresses":{"description":"Billing and shipping addresses that are not deleted, old copies replaced by an edit included (`is_current_source: false`).","items":{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},"type":"array"},"assigned_users":{"description":"The users assigned to the customer. Unlike List the users assigned to a customer, people who have left the team stay in this list.","items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","avatar_url","name"],"type":"object"},"type":"array"},"contacts":{"description":"Every contact, deleted ones included (`trashed`).","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"customer_portal_enabled":{"description":"Whether the customer's contacts can open the Customer Portal (Portal settings > Customer portal in YoPrint). `false`: the portal is off for this customer. `true`, or null (never set), means on.","type":["boolean","null"]},"customer_portal_id":{"description":"The id used in the customer's portal address. Null for Shopify customers.","type":["string","null"]},"customer_portal_id_override":{"type":["string","null"]},"customer_portal_link":{"description":"Always null: YoPrint no longer returns a portal sign-in link for the customer. The field stays for older integrations.","type":"null"},"customer_portal_payment_option":{"description":"Whether the customer can pay online in the portal. Null follows the team setting (and is always null for Shopify customers).","enum":["ENABLED","DISABLED",null],"type":["string","null"]},"customer_profiles":{"description":"Brand profiles.","items":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"type":"array"},"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"default_warehouse_id":{"type":["string","null"]},"deposit_due_amount":{"description":"Deposits still due. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"display_customer_portal_id":{"description":"The Customer Portal ID shown to people: the override when set, otherwise `customer_portal_id`. `-` for Shopify customers.","type":"string"},"external_type":{"description":"`shopify` for customers synced from Shopify.","type":["string","null"]},"has_customer_portal_id_override":{"type":"boolean"},"held_credit":{"description":"The part of `wallet_fund` held while a payment is under an open dispute or a provider review: it can't be applied to orders or taken out until the hold ends. Never more than `wallet_fund`; 0 when `wallet_fund` is 0 or negative. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"hide":{"description":"True when the customer is archived.","type":"boolean"},"id":{"description":"The customer id. Use it in paths and as `customer_id` on sales orders and quotes.","type":"string"},"internal_notes":{"type":["string","null"]},"is_editable":{"description":"False for Shopify and system customers: they can't be changed through this API.","type":"boolean"},"is_external":{"type":"boolean"},"is_system":{"type":"boolean"},"last_ordered_date":{"description":"The issue date of the customer's latest published sales order. Null when it has none.","format":"date-time","type":["string","null"]},"media":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"name":{"description":"Null for a customer created by upsert without a name.","type":["string","null"]},"ordered_amount":{"description":"Total of the customer's published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"overdue_amount":{"description":"Unpaid amounts past their payment due date. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"pdf":{"additionalProperties":false,"properties":{"invoice_statement":{"description":"A link that downloads the customer's invoice statement PDF. Its token opens only this customer's statement and stops working 9,000 hours (about a year) after the answer was made. Anyone with the link can download the statement: don't share it.","type":"string"}},"required":["invoice_statement"],"type":"object"},"quote_amount":{"description":"Total of open quotes. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"resale_number":{"type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"type":["object","null"]},"system_type":{"type":["string","null"]},"tags":{"items":{"additionalProperties":false,"properties":{"color_hex":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"tax_exempt":{"type":"boolean"},"third_party_billing_default":{"description":"How a shipping label for this customer is billed by default. `default_carrier_account`: YoPrint's label and rate dialogs start on the customer's default carrier account (third-party billing). `none`: they start with no third-party billing.","enum":["none","default_carrier_account"],"type":"string"},"trashed":{"description":"True when the customer is deleted.","type":"boolean"},"unpaid_amount":{"description":"What the customer still owes on published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"updated_at":{"format":"date-time","type":"string"},"vat_number":{"description":"The customer's tax number (shown as Tax number in YoPrint).","type":["string","null"]},"wallet_currency":{"additionalProperties":false,"description":"The team's default currency, the one `wallet_fund` is in. `iso` is its code.","properties":{"default":{"type":"boolean"},"id":{"type":"string"},"iso":{"description":"The ISO 4217 code, such as `USD`.","type":["string","null"]},"name":{"type":["string","null"]},"symbol":{"type":["string","null"]},"trashed":{"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"wallet_fund":{"description":"Customer credit balance. Negative when the customer owes credit back, for example after a refund of a payment whose credit was already spent. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"website":{"type":["string","null"]}},"required":["id","name","tax_exempt","trashed","hide","is_external","is_system","is_editable","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":null,"address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"4wlvetojbGb1qm","is_current_source":false,"is_default_warehouse":false,"is_external":false,"is_primary":false,"label":"Old warehouse","nexus":true,"note":null,"owner_id":"wJ4pqoTlhaVKLM","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":true},"message_code":"blocked_external_or_compliance","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_external_or_compliance","stale_base":null},"message":"blocked_external_or_compliance","success":false},"schema":{"additionalProperties":false,"properties":{"address_save_result":{"additionalProperties":true,"description":"What the save did.","properties":{"current_address":{"additionalProperties":true,"description":"On a refusal: the address to edit instead.","type":["object","null"]},"message_code":{"description":"The message code for what happened, identical to `save_mode`.","type":"string"},"operation_key":{"description":"The key you sent, or one YoPrint made.","type":["string","null"]},"previous_address":{"additionalProperties":true,"type":["object","null"]},"replacement_address":{"additionalProperties":true,"type":["object","null"]},"save_mode":{"enum":["updated_in_place_unused","created_replacement_address_used","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"stale_base":{"additionalProperties":true,"type":["object","null"]}},"required":["save_mode","message_code","operation_key"],"type":"object"},"message":{"description":"The `save_mode`.","enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"type":"object"}}},"description":"`default_warehouse_id` names a company location that is deleted, synced from another system or redacted (`blocked_external_or_compliance`; `current_address` is that location), or one replaced by an edit (`blocked_superseded_historical_address`; `current_address` is its replacement). Not the usual error envelope: `success: false`, `address_save_result` and `message` (the `save_mode`); no `status` or `error`."},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a customer","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Ask for Manage Customers \"Manage All\", or to be assigned to the customer.","status":403,"when":"Your role can't change this customer: it has no Manage Customers permission, or it manages only customers assigned to you and this one is not. This 403 has a short body, `{\"message\": \"No Permission to update Customer\"}`."},{"fix":"Use the id of a current company location from List company locations; check the field types.","status":422,"when":"`default_warehouse_id` is not a company location of the team (`error.code` `invalid_default_warehouse`), or a field has the wrong type (`validation_failed`)."},{"fix":"Copy `pricing_group_id` from a sales order that uses a live group, or turn the group on in Pricing groups.","status":422,"when":"`default_pricing_group_id` can't be used: not one of the team's published groups (`validation_error`, \"Choose one of your pricing groups.\" on `default_pricing_group_id` in `error.fields`), removed (`pricing_group_removed`, with `error.pricing_group`), or turned off (`pricing_group_disabled`, with `error.pricing_group` and `error.fields`)."},{"fix":"For `blocked_superseded_historical_address`, use `address_save_result.current_address.id`. For `blocked_external_or_compliance`, `current_address` is the same location: pick another current one from List company locations.","status":409,"when":"`default_warehouse_id` names a company location that was replaced by an edit (`address_save_result.save_mode` `blocked_superseded_historical_address`), or one that was deleted, is synced from another system or was redacted (`blocked_external_or_compliance`). Not the usual error envelope: the body has `success: false`, `address_save_result` and `message`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the id. Find deleted customers with the `trashed_only` filter and restore them first.","status":404,"when":"No live customer with this id in the team: deleted customers are not found here. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission: \"Manage All\" for any customer, or \"Manage Assigned to User\" for customers assigned to you.","related":["v1_public_customer_show","v1_public_customer_contact_update_patch","v1_public_customer_address_update","v1_public_location_index","v1_public_payment_term_index"],"rules":["`is_external` and `external_type` are ignored on customers and their contacts: sending them (for example a value you read back) is not refused and changes nothing. Only the Shopify sync sets them. Other fields not listed here are not part of the API.","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\").","`default_warehouse_id` must be a current company location of the team.","A new `default_pricing_group_id` must be one of the team's published pricing groups that is turned on. Sending the customer's current group again is fine even if it was turned off since.","`default_payment_term_id`, `default_pricing_group_id`, `default_warehouse_id`, `customer_portal_payment_option` and `customer_portal_enabled` can be cleared with `null`. Any other field sent as `null` is dropped; send an empty string to blank a text field.","Changing the defaults affects new sales orders only; existing ones keep theirs."],"side_effects":["Sends the `customer.updated` webhook.","Open Customer Portal pages of this customer are told to refresh."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/activity_summary":{"get":{"description":"Counts the customer's published sales orders, quotes and invoices, whatever their status (completed ones included), and lists its 10 newest sales orders and quotes.\n\n- `counts.orders`: published sales orders that are not deleted, in any status.\n- `counts.quotes`: published quotes that are not deleted, in any status.\n- `counts.invoices`: invoices that are not deleted, on those sales orders.\n- `recent_activity`: the same sales orders and quotes, newest created first, at most 10, each with `id`, `type` (`sales_order` or `quote`), `number`, `status_name`, `created_at` and `total`. With 10 or fewer, it has `counts.orders` + `counts.quotes` rows.\n\nDrafts are left out everywhere. For open work only, use the customer's totals instead (`unpaid_amount`, `quote_amount`).","operationId":"v1_public_customer_activity_summary","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers) or the customer's unique key.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"counts":{"invoices":2,"orders":2,"quotes":1},"customer_id":"V4keXwwxMQyXw7","recent_activity":[{"created_at":"2026-10-28T08:00:00+00:00","id":"hRPr0MCgpIHdWt","number":"SO1002","status_name":"In production","total":25000,"type":"sales_order"},{"created_at":"2026-10-20T08:00:00+00:00","id":"OdS9qORWGbh3dw","number":"SO1003","status_name":"Completed","total":40000,"type":"quote"},{"created_at":"2026-10-05T08:00:00+00:00","id":"Qh768LrMx87hmd","number":"SO1001","status_name":"Completed","total":100000,"type":"sales_order"}]},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"counts":{"properties":{"invoices":{"description":"Invoices on those sales orders that are not deleted.","type":"integer"},"orders":{"description":"Published sales orders, any status.","type":"integer"},"quotes":{"description":"Published quotes, any status.","type":"integer"}},"required":["orders","quotes","invoices"],"type":"object"},"customer_id":{"type":"string"},"recent_activity":{"items":{"properties":{"created_at":{"format":"date-time","type":["string","null"]},"id":{"type":"string"},"number":{"description":"The sales order or quote number people see, such as `SO1001`.","type":"string"},"status_name":{"type":["string","null"]},"total":{"description":"The order total. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"type":{"enum":["sales_order","quote",null],"type":["string","null"]}},"required":["id","type","number"],"type":"object"},"type":"array"}},"required":["customer_id","counts","recent_activity"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a customer's order counts and recent activity","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Check the id. Deleted customers have no summary.","status":404,"when":"No live, non-system customer with this id. `error.code` is null and `error.message` names the record type."},{"fix":"Ask for Manage Customers \"Manage All\", or to be assigned to the customer.","status":403,"when":"Your role has no Manage Customers permission, or it manages only customers assigned to you and this one is not. This 403 has a short body, `{\"message\": \"You do not have permission to view customer\"}`."}],"group":"Customers","permission":"Needs the Manage Customers permission. At \"Manage Assigned to User\" only customers assigned to you are allowed; other customers answer 403.","related":["v1_public_customer_show"]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/address":{"get":{"description":"Lists the customer's current billing and shipping addresses: the ones you can pick for new documents or edit. Not paged.\n\nSend `mode=history` to list every billing and shipping address instead: deleted ones, old copies replaced by an edit (`superseded_by_address_id`) and addresses synced from Shopify. Each row says `used_by_active_profile` when a brand profile uses it.","operationId":"v1_public_customer_address_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"`history` lists every billing and shipping address. Leave it out for current addresses only.","example":"history","in":"query","name":"mode","required":false,"schema":{"enum":["history"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":true},{"address1":"100 Example Street","address2":"Dock 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"swtHxyIfOvF62K","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Warehouse","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a customer's addresses","tags":["Customer addresses"],"x-yoprint-docs":{"group":"Customers","notes":["The current list leaves out addresses synced from Shopify. Use `mode=history` to see them."],"permission":"Any member of the team.","related":["v1_public_customer_address_store","v1_public_customer_address_update"]}},"post":{"description":"Adds a billing or shipping address and returns it.\n\nThe first address of each role becomes primary; later ones don't, whatever `is_primary` says. Use Set the primary address to change it.","operationId":"v1_public_customer_address_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"address1":"100 Example Street","address2":"Dock 9","city":"Springfield","country_code":"US","is_primary":false,"label":"Second warehouse","postcode":"62701","role":"shipping","state_code":"IL"},"schema":{"additionalProperties":false,"properties":{"address1":{"description":"Required. Street line 1.","type":"string"},"address2":{"description":"Street line 2, such as a suite or unit.","type":"string"},"city":{"description":"The city.","type":"string"},"country":{"description":"The country name. Shown as the country of `country_code` when blank.","type":"string"},"country_code":{"description":"Required. Two-letter country code, such as `US`.","type":"string"},"is_primary":{"description":"Required, but the first address of each role always becomes primary and later ones never do. Use the set-primary operation to change it.","type":"boolean"},"label":{"description":"Required. A name for the address, shown in pickers: \"Head office\".","type":"string"},"note":{"description":"A note kept with the address, such as delivery instructions.","type":"string"},"postcode":{"description":"The postal or ZIP code.","type":"string"},"role":{"description":"Required. What the address is for.","enum":["billing","shipping"],"type":"string"},"state":{"description":"The state or province name, such as \"Illinois\". For US and Canada addresses, send either `state` or `state_code` (or both matching): YoPrint resolves and stores both. For other countries, send the name in `state`. Sending `null` is ignored; omit the field to leave it unset.","type":"string"},"state_code":{"description":"The two-letter state or province code, such as `IL` or `ON`. Used for US and Canada addresses: send either `state_code` or `state`. Sending `null` is ignored; omit the field to leave it unset.","type":"string"}},"required":["label","address1","country_code","is_primary","role"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"address1":"100 Example Street","address2":"Dock 9","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"8mH5XMk0BBFeza","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":false,"label":"Second warehouse","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/CustomerAddressMutationValidationResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add an address to a customer","tags":["Customer addresses"],"x-yoprint-docs":{"errors":[{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"`role`, `label`, `address1`, `country_code` or `is_primary` is missing, or a US or Canadian state can't be matched. `error.code` is `validation_failed`."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the id.","status":404,"when":"No customer with this id in the team. Deleted customers are found here, so this also works on a deleted customer. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_address_primary","v1_public_customer_address_update"],"rules":["`state_code` and `country_code` are trimmed and upper-cased.","Works on a deleted customer too: the address is added to it.","For `US` and `CA`, `state` or `state_code` must name a real state or province; YoPrint stores the name and the code together.","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/address/{id}":{"delete":{"description":"Deletes a current address. Existing sales orders, quotes, invoices, shipments, and purchase orders that already use the address keep their saved copy of the address. It can be restored. Deleting the primary address does not make another one primary.","operationId":"v1_public_customer_address_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The address's id (`id` from List a customer's addresses). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Dock 4","address_family_id":"VmfG6friokY7BM","city":"Springfield","copied_from_address_id":"VmfG6friokY7BM","country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"MGnZ8qGMMGZM2k","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Back dock","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"message_code":"blocked_superseded_historical_address","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_superseded_historical_address","stale_base":null},"message":"blocked_superseded_historical_address","success":false},"schema":{"additionalProperties":false,"properties":{"address_save_result":{"additionalProperties":true,"description":"What the save did.","properties":{"current_address":{"additionalProperties":true,"description":"On a refusal: the address to edit instead.","type":["object","null"]},"message_code":{"description":"The message code for what happened, identical to `save_mode`.","type":"string"},"operation_key":{"description":"The key you sent, or one YoPrint made.","type":["string","null"]},"previous_address":{"additionalProperties":true,"type":["object","null"]},"replacement_address":{"additionalProperties":true,"type":["object","null"]},"save_mode":{"enum":["updated_in_place_unused","created_replacement_address_used","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"stale_base":{"additionalProperties":true,"type":["object","null"]}},"required":["save_mode","message_code","operation_key"],"type":"object"},"message":{"description":"The `save_mode`.","enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"type":"object"}}},"description":"The address is an old copy replaced by an edit (`blocked_superseded_historical_address`; `current_address` is the copy to use), or it is synced from another system or redacted (`blocked_external_or_compliance`; `current_address` is the same address). Not the usual error envelope: `success: false`, `address_save_result` and `message` (the `save_mode`); no `status` or `error`."},"422":{"$ref":"#/components/responses/CustomerAddressMutationValidationResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a customer address","tags":["Customer addresses"],"x-yoprint-docs":{"errors":[{"fix":"For a replaced address, use `address_save_result.current_address.id`. A synced or redacted address can't be changed.","status":409,"when":"The address is not current: replaced by an edit (`address_save_result.save_mode` `blocked_superseded_historical_address`), or synced from another system or redacted (`blocked_external_or_compliance`). Not the usual error envelope: the body has `success: false`, `address_save_result` and `message`."},{"fix":"Change it in Shopify.","status":422,"when":"The address is synced from Shopify (`validation_error`, \"Shopify-managed customer addresses are read-only. Manage changes from Shopify.\")."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the ids.","status":404,"when":"Already deleted, or not this customer's. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_address_restore","v1_public_customer_address_primary"],"rules":["Only a current address: an old copy, or an address synced from another system or redacted, is refused with 409.","Addresses synced from Shopify are read-only (422).","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."]}},"get":{"description":"Returns one of the customer's addresses, deleted and replaced ones included, with `used_by_active_profile`.","operationId":"v1_public_customer_address_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The address's id (`id` from List a customer's addresses). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":true},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a customer address","tags":["Customer addresses"],"x-yoprint-docs":{"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_address_update"]}},"put":{"description":"Saves changes to an address. Addresses already printed on a document are never changed in place: YoPrint keeps the old address for those documents and saves your changes as a new address.\n\n`address_save_result.save_mode` says what happened:\n\n- `updated_in_place_unused` (200): nothing used the address, so it was changed. Same id; `revision_number` went up by one.\n- `created_replacement_address_used` (200): a sales order, quote, invoice, shipment, package, purchase order or brand profile uses the address. `data` is a new address with a new id and your changes; it takes over as primary if the old one was. The old address stays on those documents and leaves the current list. Brand profiles keep pointing at the old address: update them to the new id yourself.\n- `no_address_fields_changed` (200): the values you sent are the ones saved. Nothing changed.\n- `stale_address` (409): you sent `base_revision_number` and someone saved the address since. Nothing changed; `current_address` and `stale_base` show the latest.\n- `blocked_superseded_historical_address` (409): the address was already replaced by an edit. Edit `current_address` instead.\n- `blocked_external_or_compliance` (409): the address is synced from another system or was redacted.\n\nThis answer has no `status` field: `success`, `address_save_result` and, on success, `data`; on a 409 also `message` (the mode).","operationId":"v1_public_customer_address_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The address's id (`id` from List a customer's addresses). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"address2":"Dock 5","base_revision_number":1,"operation_key":"address-edit-1001"},"schema":{"additionalProperties":false,"properties":{"address1":{"type":"string"},"address2":{"description":"Street line 2, such as a suite or unit.","type":"string"},"base_revision_number":{"description":"Protects against concurrent edits: send the `revision_number` you last read, and YoPrint refuses the save with 409 `stale_address` if someone changed the address since.","type":"integer"},"city":{"description":"The city.","type":"string"},"country":{"type":"string"},"country_code":{"description":"When you change `state` without `country_code`, the address's saved country is used to check it.","type":"string"},"label":{"type":"string"},"note":{"description":"A note kept with the address, such as delivery instructions.","type":"string"},"operation_key":{"description":"Your id for this save. Retrying with the same key and the same values returns the replacement the first try made instead of a 409.","type":"string"},"postcode":{"description":"The postal or ZIP code.","type":"string"},"state":{"description":"`null` is dropped before the request is read, so it can't clear the state: leave the field out to keep it.","type":"string"},"state_code":{"description":"As `state`: `null` is the same as leaving it out.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"address_save_result":{"current_address":null,"message_code":"updated_in_place_unused","operation_key":"address-edit-1001","previous_address":null,"replacement_address":null,"save_mode":"updated_in_place_unused","stale_base":null},"data":{"address1":"100 Example Street","address2":"Dock 5","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"swtHxyIfOvF62K","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Warehouse","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false},"success":true},"schema":{"properties":{"address_save_result":{"additionalProperties":true,"description":"What the save did.","properties":{"current_address":{"additionalProperties":true,"description":"On a refusal: the address to edit instead.","type":["object","null"]},"message_code":{"description":"The message code for what happened, identical to `save_mode`.","type":"string"},"operation_key":{"description":"The key you sent, or one YoPrint made.","type":["string","null"]},"previous_address":{"additionalProperties":true,"type":["object","null"]},"replacement_address":{"additionalProperties":true,"type":["object","null"]},"save_mode":{"enum":["updated_in_place_unused","created_replacement_address_used","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"stale_base":{"additionalProperties":true,"type":["object","null"]}},"required":["save_mode","message_code","operation_key"],"type":"object"},"data":{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","address_save_result","data"],"type":"object"}}},"description":"Saved, or nothing to save. `address_save_result.save_mode` says which; `data` is the address to use from now on."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Dock 6","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"swtHxyIfOvF62K","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Warehouse","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":3,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false},"message_code":"stale_address","operation_key":"address-edit-1001","previous_address":null,"replacement_address":null,"save_mode":"stale_address","stale_base":{"address_id":"swtHxyIfOvF62K","base_revision_number":1,"current_revision_number":3}},"message":"stale_address","success":false},"schema":{"properties":{"address_save_result":{"additionalProperties":true,"description":"What the save did.","properties":{"current_address":{"additionalProperties":true,"description":"On a refusal: the address to edit instead.","type":["object","null"]},"message_code":{"description":"The message code for what happened, identical to `save_mode`.","type":"string"},"operation_key":{"description":"The key you sent, or one YoPrint made.","type":["string","null"]},"previous_address":{"additionalProperties":true,"type":["object","null"]},"replacement_address":{"additionalProperties":true,"type":["object","null"]},"save_mode":{"enum":["updated_in_place_unused","created_replacement_address_used","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"stale_base":{"additionalProperties":true,"type":["object","null"]}},"required":["save_mode","message_code","operation_key"],"type":"object"},"message":{"description":"The `save_mode`.","type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"type":"object"}}},"description":"Nothing saved: the address changed since `base_revision_number`, was replaced by an edit, or is synced from another system or redacted."},"422":{"$ref":"#/components/responses/CustomerAddressMutationValidationResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a customer address","tags":["Customer addresses"],"x-yoprint-docs":{"errors":[{"fix":"Re-read `address_save_result.current_address`, then save against it. A `blocked_external_or_compliance` address can't be edited at all.","status":409,"when":"`address_save_result.save_mode` is `stale_address`, `blocked_superseded_historical_address` or `blocked_external_or_compliance`. Not the usual error envelope: the body has `success: false`, `address_save_result` and `message`."},{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"A field has the wrong type, or a US or Canadian state can't be matched. `error.code` is `validation_failed`."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the ids.","status":404,"when":"The address is deleted, or is not a billing or shipping address of this customer. `error.code` is null and `error.message` names the record type."}],"group":"Customers","notes":["Always use the id in `data` from the answer from now on: after a replacement it is a new id."],"permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_address_index","v1_public_customer_profile_update_patch"],"rules":["Only billing and shipping addresses of this customer can be updated here; deleted ones can't.","`is_primary` is not changed here: use Set the primary address.","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."],"side_effects":["May create a new address (`created_replacement_address_used`). Existing sales orders, quotes, invoices, shipments, and purchase orders keep their saved copy of the old address."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/address/{id}/primary":{"patch":{"description":"Makes this address the customer's primary address of its role (billing or shipping); the previous one stops being primary. Returns the address.","operationId":"v1_public_customer_address_primary","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The address's id (`id` from List a customer's addresses). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Dock 4","address_family_id":"VmfG6friokY7BM","city":"Springfield","copied_from_address_id":"VmfG6friokY7BM","country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"MGnZ8qGMMGZM2k","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Back dock","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"message_code":"blocked_superseded_historical_address","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_superseded_historical_address","stale_base":null},"message":"blocked_superseded_historical_address","success":false},"schema":{"additionalProperties":false,"properties":{"address_save_result":{"additionalProperties":true,"description":"What the save did.","properties":{"current_address":{"additionalProperties":true,"description":"On a refusal: the address to edit instead.","type":["object","null"]},"message_code":{"description":"The message code for what happened, identical to `save_mode`.","type":"string"},"operation_key":{"description":"The key you sent, or one YoPrint made.","type":["string","null"]},"previous_address":{"additionalProperties":true,"type":["object","null"]},"replacement_address":{"additionalProperties":true,"type":["object","null"]},"save_mode":{"enum":["updated_in_place_unused","created_replacement_address_used","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"stale_base":{"additionalProperties":true,"type":["object","null"]}},"required":["save_mode","message_code","operation_key"],"type":"object"},"message":{"description":"The `save_mode`.","enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"type":"object"}}},"description":"The address is an old copy replaced by an edit (`blocked_superseded_historical_address`; `current_address` is the copy to use), or it is synced from another system or redacted (`blocked_external_or_compliance`; `current_address` is the same address). Not the usual error envelope: `success: false`, `address_save_result` and `message` (the `save_mode`); no `status` or `error`."},"422":{"$ref":"#/components/responses/CustomerAddressMutationValidationResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set the primary address","tags":["Customer addresses"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"For a replaced address, use `address_save_result.current_address.id`. A synced or redacted address can't be changed.","status":409,"when":"The address is not current: replaced by an edit (`address_save_result.save_mode` `blocked_superseded_historical_address`), or synced from another system or redacted (`blocked_external_or_compliance`). Not the usual error envelope: the body has `success: false`, `address_save_result` and `message`."},{"fix":"Change it in Shopify.","status":422,"when":"The address is synced from Shopify (`validation_error`, \"Shopify-managed customer addresses are read-only. Manage changes from Shopify.\")."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Restore it first.","status":404,"when":"The address is deleted or not this customer's. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_address_index"],"rules":["Only a current address: one replaced by an edit, synced from another system or redacted is refused with 409 (`address_save_result.current_address` is the one to use).","Addresses synced from Shopify are read-only (422).","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/address/{id}/restore":{"patch":{"description":"Brings back a deleted address. Answers `success: true` with `data: null`. An old copy replaced by an edit, or an address synced from another system or redacted, can't be restored (409).","operationId":"v1_public_customer_address_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The address's id (`id` from List a customer's addresses). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Dock 4","address_family_id":"VmfG6friokY7BM","city":"Springfield","copied_from_address_id":"VmfG6friokY7BM","country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"MGnZ8qGMMGZM2k","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Back dock","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"message_code":"blocked_superseded_historical_address","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_superseded_historical_address","stale_base":null},"message":"blocked_superseded_historical_address","success":false},"schema":{"additionalProperties":false,"properties":{"address_save_result":{"additionalProperties":true,"description":"What the save did.","properties":{"current_address":{"additionalProperties":true,"description":"On a refusal: the address to edit instead.","type":["object","null"]},"message_code":{"description":"The message code for what happened, identical to `save_mode`.","type":"string"},"operation_key":{"description":"The key you sent, or one YoPrint made.","type":["string","null"]},"previous_address":{"additionalProperties":true,"type":["object","null"]},"replacement_address":{"additionalProperties":true,"type":["object","null"]},"save_mode":{"enum":["updated_in_place_unused","created_replacement_address_used","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"stale_base":{"additionalProperties":true,"type":["object","null"]}},"required":["save_mode","message_code","operation_key"],"type":"object"},"message":{"description":"The `save_mode`.","enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"type":"object"}}},"description":"The address is an old copy replaced by an edit (`blocked_superseded_historical_address`; `current_address` is the copy to use), or it is synced from another system or redacted (`blocked_external_or_compliance`; `current_address` is the same address). Not the usual error envelope: `success: false`, `address_save_result` and `message` (the `save_mode`); no `status` or `error`."},"422":{"$ref":"#/components/responses/CustomerAddressMutationValidationResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a deleted customer address","tags":["Customer addresses"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"For a replaced address, use `address_save_result.current_address.id`. A synced or redacted address can't be changed.","status":409,"when":"The address is not current: replaced by an edit (`address_save_result.save_mode` `blocked_superseded_historical_address`), or synced from another system or redacted (`blocked_external_or_compliance`). Not the usual error envelope: the body has `success: false`, `address_save_result` and `message`."},{"fix":"Change it in Shopify.","status":422,"when":"The address is synced from Shopify (`validation_error`, \"Shopify-managed customer addresses are read-only. Manage changes from Shopify.\")."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the ids.","status":404,"when":"Not this customer's address. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_address_destroy"],"rules":["Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\").","Addresses synced from Shopify are read-only (422).","A restored address keeps its old `is_primary`: check the primary address afterwards."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/contact":{"get":{"description":"Lists every contact of the customer, deleted ones included: check `trashed`. Not paged, in no set order. The primary contact has `is_primary: true`.\n\nWarning: YoPrint does not verify that the customer ID exists. Passing an unknown or deleted customer ID returns an empty list `[]` instead of a 404.","operationId":"v1_public_customer_contact_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a customer's contacts","tags":["Customer contacts"],"x-yoprint-docs":{"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_contact_store","v1_public_customer_contact_primary"]}},"post":{"description":"Adds a contact to the customer and returns it.\n\n`is_primary` is required in the request body, but its value is ignored: the new contact becomes primary only if the customer has no other live contacts. If the customer already has live contacts, the new contact is saved with `is_primary: false`. To make this contact primary, call Set the primary contact afterwards.","operationId":"v1_public_customer_contact_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"email":"jordan@example.com","first_name":"Jordan","is_primary":false,"last_name":"Lee","send_invoice":false},"schema":{"additionalProperties":false,"properties":{"default_receive_sms":{"description":"When this contact is set on a sales order, it receives text messages about the order by default. Saved as sent; defaults to false.","type":"boolean"},"email":{"description":"The contact's email. Messages you send to this contact go here.","format":"email","type":"string"},"fax":{"description":"Checked as a real number for `fax_country`.","type":"string"},"fax_country":{"description":"Two-letter country code of `fax`.","type":"string"},"first_name":{"description":"Required. The contact's first name.","type":"string"},"is_primary":{"description":"Required, but its value is ignored: the contact becomes primary only if the customer has no other live contacts. To make it primary, use Set the primary contact.","type":"boolean"},"last_name":{"description":"The contact's last name.","type":"string"},"phone":{"description":"Checked as a real number for `phone_country`. Send `phone_country` with it.","type":"string"},"phone_country":{"description":"Two-letter country code of `phone`, such as `US`. Required with `phone`.","example":"US","type":"string"},"send_invoice":{"description":"Required. Stored with the contact and returned as `send_invoice`.","type":"boolean"}},"required":["first_name","send_invoice","is_primary"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-03T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"jordan@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Jordan","id":"z00Q1u9fDyYcfw","is_external":false,"is_primary":false,"last_name":"Lee","phone":null,"phone_country":null,"send_invoice":false,"trashed":false,"updated_at":"2026-11-03T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add a contact to a customer","tags":["Customer contacts"],"x-yoprint-docs":{"errors":[{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"`first_name`, `send_invoice` or `is_primary` is missing, or the phone is not valid for `phone_country`. `error.code` is `validation_failed`."},{"fix":"Update the existing contact instead, or use another email.","status":409,"when":"Another live contact of this customer already has this email, ignoring case and surrounding spaces (`error.code` `customer_portal_duplicate_contact_email`, \"This customer already has a contact with that email. Edit the existing contact or use a different email.\")."},{"fix":"Send a valid email of at most 191 characters.","status":422,"when":"On a live customer, the email is longer than 191 characters or is not a valid address (`error.code` `customer_portal_email_invalid`, \"Enter a valid email address using supported characters.\")."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the id.","status":404,"when":"No customer with this id in the team. Deleted customers are found here, so this also works on a deleted customer. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_contact_upsert","v1_public_customer_contact_primary"],"rules":["`is_external` and `external_type` are ignored: sending them (for example a value you read back) is not refused and changes nothing. Only the Shopify sync sets them.","A phone needs `phone_country` and must be a valid number for it; the same goes for `fax` and `fax_country`.","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\").","On a live customer (not a system or Shopify customer) a contact's email is saved trimmed and in lower case, and two live contacts of the customer can't have the same email (compared the same way). Other customers may use the same email. Phones need not be unique.","Works on a deleted customer too: the contact is added to it, and its email is neither changed nor checked against the other contacts."],"side_effects":["Sends the `customer_contact.created` webhook.","When the contact's email already belongs to a Customer Portal account on your team that can't open this customer yet, saving the contact gives that account access to this customer (active when the account is set up with a verified email or a password, invited otherwise). No email is sent."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/contact/upsert":{"post":{"description":"Updates the customer's contact that has this `email` or `phone`, or adds a new contact.\n\nWith `perform_upsert: true` YoPrint looks among the customer's live contacts for one whose `email` equals yours or whose `phone` equals yours, and updates the first it finds with the fields you send. Otherwise, or with `perform_upsert: false`, it adds a new contact (primary only when the customer has no other live contact). Returns the contact.","operationId":"v1_public_customer_contact_upsert","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"email":"alex@example.com","first_name":"Alex","last_name":"Rivera","perform_upsert":true,"send_invoice":true},"schema":{"additionalProperties":false,"properties":{"default_receive_sms":{"type":"boolean"},"email":{"description":"Matched exactly.","format":"email","type":"string"},"fax":{"description":"Checked as a real number for `fax_country`.","type":"string"},"fax_country":{"type":"string"},"first_name":{"description":"Not required here, but send it when the contact may be new.","type":"string"},"is_primary":{"description":"Not used. Use Set the primary contact.","type":"boolean"},"last_name":{"description":"The contact's last name.","type":"string"},"perform_upsert":{"description":"True to match by `email` or `phone` first. False always adds.","type":"boolean"},"phone":{"description":"Matched exactly as stored. Send `phone_country` with it.","type":"string"},"phone_country":{"description":"Two-letter country code of `phone`, such as `US`. Required with `phone`.","type":"string"},"send_invoice":{"description":"Stored with the contact and returned as `send_invoice`.","type":"boolean"}},"required":["perform_upsert"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create or update a customer contact by email or phone","tags":["Customer contacts"],"x-yoprint-docs":{"errors":[{"fix":"Send `perform_upsert`, and `phone_country` with `phone`.","status":422,"when":"`perform_upsert` is missing, or a phone is not valid for its country. `error.code` is `validation_failed`."},{"fix":"Update the existing contact instead, or use another email.","status":409,"when":"Another live contact of this customer already has this email, ignoring case and surrounding spaces (`error.code` `customer_portal_duplicate_contact_email`, \"This customer already has a contact with that email. Edit the existing contact or use a different email.\")."},{"fix":"Send a valid email of at most 191 characters.","status":422,"when":"On a live customer, the email is longer than 191 characters or is not a valid address (`error.code` `customer_portal_email_invalid`, \"Enter a valid email address using supported characters.\")."},{"fix":"Change the email with Update a customer contact, sending `portal_email_scope` or `portal_reconnect_confirmed`.","status":409,"when":"The matched contact's new email needs a choice this operation can't send (`error.code` `customer_portal_email_scope_required` or `customer_portal_email_reconnect_required`), or the account on the new email is unavailable (`customer_portal_account_unavailable`)."},{"fix":"Ask a member who can update those customers, or send `portal_email_scope: this_customer`.","status":403,"when":"The change moves portal access on a customer your role can't update: you need Manage Customers \"Manage All\", or \"Manage Assigned to User\" and to be assigned to every customer the change covers. This 403 has a short body, `{\"message\": \"You need permission to update every linked customer.\"}`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the id.","status":404,"when":"No customer with this id in the team. Deleted customers are found here, so this also works on a deleted customer. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_contact_store","v1_public_customer_upsert"],"rules":["`is_external` and `external_type` are ignored: sending them (for example a value you read back) is not refused and changes nothing. Only the Shopify sync sets them.","With `perform_upsert: true`, send `email` or `phone`. With neither, the customer's first contact is updated.","A matched contact synced from Shopify is refused (422 \"Shopify-managed customer contacts are read-only. Manage changes from Shopify.\").","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\").","On a live customer (not a system or Shopify customer) a contact's email is saved trimmed and in lower case, and two live contacts of the customer can't have the same email (compared the same way). Other customers may use the same email.","This operation can't send `portal_email_scope` or `portal_reconnect_confirmed`. When it changes the email of a matched contact that gives someone Customer Portal access, and the change needs either, it answers 409: make the change with Update a customer contact."],"side_effects":["Sends `customer_contact.updated` for a match, or `customer_contact.created` for a new contact.","When the contact's email already belongs to a Customer Portal account on your team that can't open this customer yet, saving the contact gives that account access to this customer (active when the account is set up with a verified email or a password, invited otherwise). No email is sent.","A matched contact whose email changes moves its Customer Portal access as Update a customer contact describes, with `portal_email_scope` `all_customers`."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/contact/{id}":{"delete":{"description":"Deletes a contact. It can be restored. Documents that already name it keep it. The primary contact can't be deleted: make another contact primary first.","operationId":"v1_public_customer_contact_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The contact's id (`id` from List a customer's contacts, or from List a vendor's contacts). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a customer contact","tags":["Customer contacts"],"x-yoprint-docs":{"errors":[{"fix":"Set another contact as primary, then delete this one. Don't retry the same call: it fails the same way.","status":500,"when":"The contact is the primary contact. This route answers HTTP 500 with `error.code` `delete_fail` and `error.message` null; nothing is deleted."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the ids.","status":404,"when":"The contact is already deleted, or belongs to another customer. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_contact_restore","v1_public_customer_contact_primary"],"rules":["Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\").","Contacts synced from Shopify are read-only (422)."],"side_effects":["Sends the `customer_contact.deleted` webhook.","Removes the Customer Portal access the contact gave for this customer, and any access denial with it. When the portal account then has no active access to any customer, its signed-in sessions end. The account and its access to other customers stay."]}},"get":{"description":"Returns one live contact of the customer.","operationId":"v1_public_customer_contact_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The contact's id (`id` from List a customer's contacts, or from List a vendor's contacts). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a customer contact","tags":["Customer contacts"],"x-yoprint-docs":{"errors":[{"fix":"List the customer's contacts to find it.","status":404,"when":"The contact is deleted, or belongs to another customer. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_contact_update_patch"]}},"patch":{"description":"Changes the fields you send and returns the contact. `is_primary` is not changed here: use Set the primary contact.\n\nUse `PUT`: it checks the fields. `PATCH` takes the same body but checks nothing.\n\nA contact can give someone access to the Customer Portal (a portal account with the contact's email). Changing that contact's email moves the access: `portal_email_scope` says whether the account's sign-in email changes on every customer it can open (`all_customers`) or only this customer's access moves (`this_customer`), and `portal_reconnect_confirmed: true` confirms moving it to an account that already uses the new email.","operationId":"v1_public_customer_contact_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The contact's id (`id` from List a customer's contacts, or from List a vendor's contacts). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"phone":{"summary":"Change the phone","value":{"phone":"+1 201 555 0123","phone_country":"US"}},"portal_email":{"summary":"Change the email of a contact with Customer Portal access, on every customer","value":{"email":"alex@example.com","portal_email_scope":"all_customers"}}},"schema":{"additionalProperties":false,"properties":{"default_receive_sms":{"type":"boolean"},"email":{"description":"Saved trimmed and in lower case. `\"\"` clears it.","format":"email","type":"string"},"fax":{"description":"Checked as a real number for `fax_country`.","type":"string"},"fax_country":{"type":"string"},"first_name":{"description":"The contact's first name.","type":"string"},"last_name":{"description":"The contact's last name.","type":"string"},"phone":{"description":"Send `phone_country` with it.","type":"string"},"phone_country":{"description":"Two-letter country code of `phone`, such as `US`. Required with `phone`.","type":"string"},"portal_email_scope":{"description":"Read only when you change the email of a contact that gives someone Customer Portal access. `all_customers` (the default) changes that portal account's sign-in email, and the email of its contacts on every customer it can open. `this_customer` moves only this customer's access to the account for the new email. Required when the account can open more than one customer.","enum":["all_customers","this_customer"],"type":"string"},"portal_reconnect_confirmed":{"description":"Send `true` to confirm moving this contact's Customer Portal access to the account that already uses the new email. Defaults to false.","type":"boolean"},"send_invoice":{"description":"Stored with the contact and returned as `send_invoice`.","type":"boolean"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a customer contact (PATCH)","tags":["Customer contacts"],"x-yoprint-docs":{"errors":[{"fix":"Send the country code with the number.","status":422,"when":"A phone or fax is not valid for its country, a field has the wrong type, or `portal_email_scope` is not `all_customers` or `this_customer`. `error.code` is `validation_failed`."},{"fix":"Update the existing contact instead, or use another email.","status":409,"when":"Another live contact of this customer already has this email, ignoring case and surrounding spaces (`error.code` `customer_portal_duplicate_contact_email`, \"This customer already has a contact with that email. Edit the existing contact or use a different email.\")."},{"fix":"Send a valid email of at most 191 characters.","status":422,"when":"On a live customer, the email is longer than 191 characters or is not a valid address (`error.code` `customer_portal_email_invalid`, \"Enter a valid email address using supported characters.\")."},{"fix":"Send `portal_email_scope`: `all_customers` or `this_customer`.","status":409,"when":"The contact gives Customer Portal access to an account that can open several customers, and `portal_email_scope` was not sent (`error.code` `customer_portal_email_scope_required`)."},{"fix":"Send `portal_reconnect_confirmed: true` to move the access to that account, or use another email.","status":409,"when":"The new email already belongs to another Customer Portal account and `portal_reconnect_confirmed` is not `true` (`customer_portal_email_reconnect_required`), or that account is disabled or deleted (`customer_portal_account_unavailable`), or it already has another contact on this customer (`customer_portal_duplicate_contact_email`)."},{"fix":"Ask a member who can update those customers, or send `portal_email_scope: this_customer`.","status":403,"when":"The change moves portal access on a customer your role can't update: you need Manage Customers \"Manage All\", or \"Manage Assigned to User\" and to be assigned to every customer the change covers. This 403 has a short body, `{\"message\": \"You need permission to update every linked customer.\"}`."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Restore it first, or check the ids.","status":404,"when":"The contact is deleted, or belongs to another customer. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_contact_primary","v1_public_contact_update_patch"],"rules":["`is_external` and `external_type` are ignored: sending them (for example a value you read back) is not refused and changes nothing. Only the Shopify sync sets them.","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\").","Contacts synced from Shopify are read-only (422).","On a live customer (not a system or Shopify customer) a contact's email is saved trimmed and in lower case, and two live contacts of the customer can't have the same email (compared the same way). Other customers may use the same email.","Changing the email of a contact that gives someone Customer Portal access moves that access with it: see `portal_email_scope` and `portal_reconnect_confirmed`. Sending `email: \"\"` clears the email and removes the contact's portal access for this customer.","`PUT` checks that `portal_email_scope` is `all_customers` or `this_customer` and that `portal_reconnect_confirmed` is a boolean; `PATCH` doesn't.","To clear a text field, send an empty string; `null` is ignored (it is dropped before the request is read)."],"side_effects":["Sends the `customer_contact.updated` webhook.","Portal access moves with a changed email. With `all_customers` and no other account on the new email, the account's sign-in email changes, its password is cleared, its signed-in sessions end, its contacts on other customers get the same email (without webhooks), and the old address is emailed that the sign-in email changed. Otherwise the access (only this customer's with `this_customer`) moves to the account that uses the new email, which is created, invited, when there is none.","When the contact's email already belongs to a Customer Portal account on your team that can't open this customer yet, saving the contact gives that account access to this customer (active when the account is set up with a verified email or a password, invited otherwise). No email is sent."]}},"put":{"description":"Changes the fields you send and returns the contact. `is_primary` is not changed here: use Set the primary contact.\n\nUse `PUT`: it checks the fields. `PATCH` takes the same body but checks nothing.\n\nA contact can give someone access to the Customer Portal (a portal account with the contact's email). Changing that contact's email moves the access: `portal_email_scope` says whether the account's sign-in email changes on every customer it can open (`all_customers`) or only this customer's access moves (`this_customer`), and `portal_reconnect_confirmed: true` confirms moving it to an account that already uses the new email.","operationId":"v1_public_customer_contact_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The contact's id (`id` from List a customer's contacts, or from List a vendor's contacts). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"phone":{"summary":"Change the phone","value":{"phone":"+1 201 555 0123","phone_country":"US"}},"portal_email":{"summary":"Change the email of a contact with Customer Portal access, on every customer","value":{"email":"alex@example.com","portal_email_scope":"all_customers"}}},"schema":{"additionalProperties":false,"properties":{"default_receive_sms":{"type":"boolean"},"email":{"description":"Saved trimmed and in lower case. `\"\"` clears it.","format":"email","type":"string"},"fax":{"description":"Checked as a real number for `fax_country`.","type":"string"},"fax_country":{"type":"string"},"first_name":{"description":"The contact's first name.","type":"string"},"last_name":{"description":"The contact's last name.","type":"string"},"phone":{"description":"Send `phone_country` with it.","type":"string"},"phone_country":{"description":"Two-letter country code of `phone`, such as `US`. Required with `phone`.","type":"string"},"portal_email_scope":{"description":"Read only when you change the email of a contact that gives someone Customer Portal access. `all_customers` (the default) changes that portal account's sign-in email, and the email of its contacts on every customer it can open. `this_customer` moves only this customer's access to the account for the new email. Required when the account can open more than one customer.","enum":["all_customers","this_customer"],"type":"string"},"portal_reconnect_confirmed":{"description":"Send `true` to confirm moving this contact's Customer Portal access to the account that already uses the new email. Defaults to false.","type":"boolean"},"send_invoice":{"description":"Stored with the contact and returned as `send_invoice`.","type":"boolean"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a customer contact","tags":["Customer contacts"],"x-yoprint-docs":{"errors":[{"fix":"Send the country code with the number.","status":422,"when":"A phone or fax is not valid for its country, a field has the wrong type, or `portal_email_scope` is not `all_customers` or `this_customer`. `error.code` is `validation_failed`."},{"fix":"Update the existing contact instead, or use another email.","status":409,"when":"Another live contact of this customer already has this email, ignoring case and surrounding spaces (`error.code` `customer_portal_duplicate_contact_email`, \"This customer already has a contact with that email. Edit the existing contact or use a different email.\")."},{"fix":"Send a valid email of at most 191 characters.","status":422,"when":"On a live customer, the email is longer than 191 characters or is not a valid address (`error.code` `customer_portal_email_invalid`, \"Enter a valid email address using supported characters.\")."},{"fix":"Send `portal_email_scope`: `all_customers` or `this_customer`.","status":409,"when":"The contact gives Customer Portal access to an account that can open several customers, and `portal_email_scope` was not sent (`error.code` `customer_portal_email_scope_required`)."},{"fix":"Send `portal_reconnect_confirmed: true` to move the access to that account, or use another email.","status":409,"when":"The new email already belongs to another Customer Portal account and `portal_reconnect_confirmed` is not `true` (`customer_portal_email_reconnect_required`), or that account is disabled or deleted (`customer_portal_account_unavailable`), or it already has another contact on this customer (`customer_portal_duplicate_contact_email`)."},{"fix":"Ask a member who can update those customers, or send `portal_email_scope: this_customer`.","status":403,"when":"The change moves portal access on a customer your role can't update: you need Manage Customers \"Manage All\", or \"Manage Assigned to User\" and to be assigned to every customer the change covers. This 403 has a short body, `{\"message\": \"You need permission to update every linked customer.\"}`."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Restore it first, or check the ids.","status":404,"when":"The contact is deleted, or belongs to another customer. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_contact_primary","v1_public_contact_update_patch"],"rules":["`is_external` and `external_type` are ignored: sending them (for example a value you read back) is not refused and changes nothing. Only the Shopify sync sets them.","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\").","Contacts synced from Shopify are read-only (422).","On a live customer (not a system or Shopify customer) a contact's email is saved trimmed and in lower case, and two live contacts of the customer can't have the same email (compared the same way). Other customers may use the same email.","Changing the email of a contact that gives someone Customer Portal access moves that access with it: see `portal_email_scope` and `portal_reconnect_confirmed`. Sending `email: \"\"` clears the email and removes the contact's portal access for this customer.","`PUT` checks that `portal_email_scope` is `all_customers` or `this_customer` and that `portal_reconnect_confirmed` is a boolean; `PATCH` doesn't.","To clear a text field, send an empty string; `null` is ignored (it is dropped before the request is read)."],"side_effects":["Sends the `customer_contact.updated` webhook.","Portal access moves with a changed email. With `all_customers` and no other account on the new email, the account's sign-in email changes, its password is cleared, its signed-in sessions end, its contacts on other customers get the same email (without webhooks), and the old address is emailed that the sign-in email changed. Otherwise the access (only this customer's with `this_customer`) moves to the account that uses the new email, which is created, invited, when there is none.","When the contact's email already belongs to a Customer Portal account on your team that can't open this customer yet, saving the contact gives that account access to this customer (active when the account is set up with a verified email or a password, invited otherwise). No email is sent."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/contact/{id}/primary":{"patch":{"description":"Makes this contact the customer's primary contact; the previous primary contact stops being primary. Emails YoPrint sends to the customer itself go to the primary contact. Returns the contact.","operationId":"v1_public_customer_contact_primary","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The contact's id (`id` from List a customer's contacts, or from List a vendor's contacts). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set the primary contact","tags":["Customer contacts"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Restore it first.","status":404,"when":"The contact is deleted, or belongs to another customer. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_contact_index"],"rules":["Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\").","Contacts synced from Shopify are read-only (422)."],"side_effects":["Sends `customer_contact.updated` for the new primary contact and for the previous one.","When the contact's email already belongs to a Customer Portal account on your team that can't open this customer yet, saving the contact gives that account access to this customer (active when the account is set up with a verified email or a password, invited otherwise). No email is sent."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/contact/{id}/restore":{"patch":{"description":"Brings back a deleted contact. It comes back as it was; it does not become primary. Answers `success: true` with `data: null`.","operationId":"v1_public_customer_contact_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The contact's id (`id` from List a customer's contacts, or from List a vendor's contacts). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a deleted customer contact","tags":["Customer contacts"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Change or delete the other contact first, or keep this one deleted.","status":409,"when":"Another live contact of this customer already has this email, ignoring case and surrounding spaces (`error.code` `customer_portal_duplicate_contact_email`, \"This customer already has a contact with that email. Edit the existing contact or use a different email.\")."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the ids.","status":404,"when":"No contact with this id on the customer, deleted or not. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_contact_destroy"],"rules":["Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\").","Contacts synced from Shopify are read-only (422).","Works on a deleted customer too.","On a live customer, a contact can't come back while another live contact of the customer has the same email (409)."],"side_effects":["Sends the `customer_contact.updated` webhook.","When the contact's email already belongs to a Customer Portal account on your team that can't open this customer yet, saving the contact gives that account access to this customer (active when the account is set up with a verified email or a password, invited otherwise). No email is sent."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/credit":{"get":{"description":"Lists the customer's credit entries, newest first: credit added or taken out by hand, credit used to pay sales orders, sales order payments refunded to credit, Customer Portal payments received into credit and later changes to them, overpayments from online payments moved into credit or refunded from it, credit a refund took back, and credit given back when that refund failed (see `type`, `subtype` and `action`). Together they add up to the customer's `wallet_fund`. `credit_source` says where credit came from or went.\n\nThis list reads `per_page` (1 to 100; the team's page size when left out) as well as `page`.","operationId":"v1_public_customer_credit_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The page to return.","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}},{"description":"Entries per page, 1 to 100. Without it, the team's page size (`pagination_per_page` in team settings, 50 unless changed).","example":25,"in":"query","name":"per_page","required":false,"schema":{"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"action":"CUSTOMER_DEPOSIT","amount":50000,"credit_source":null,"customer_id":"V4keXwwxMQyXw7","date":"2026-11-01T09:00:00+00:00","direction":"INCREASE","id":"mJ3uYS5OJQ9VEq","is_deletable":true,"is_editable":false,"order_id":null,"payment_gateway":null,"payment_method_id":"6nz3Vu9sFR4dxM","reference_description":null,"reference_id":"CHQ-1001","refundable_amount":0,"related_transaction":null,"subtype":"TRANSFER","token":null,"type":"MANUAL","user_id":"lOURnovd3hkIQI","voided":false}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"action":{"description":"The specific action that created the entry:\n\nManual entries:\n- `CUSTOMER_DEPOSIT`: credit added by hand (created by this API).\n- `CUSTOMER_WITHDRAW`: credit taken out by hand (created by this API).\n- `CUSTOMER_CREDIT_WITHDRAW`: credit used to pay a sales order.\n- `CUSTOMER_CREDIT_DEPOSIT`: a sales order payment refunded to credit.\n\nSystem entries:\n- `CUSTOMER_CHECKOUT_FUNDING`: a Customer Portal payment received into credit.\n- `CUSTOMER_CHECKOUT_<KIND>`: an adjustment to a portal payment (such as `CUSTOMER_CHECKOUT_REFUND`).\n- `CUSTOMER_CREDIT_RECOVERY`: credit a refund took back.\n- `CUSTOMER_CREDIT_RESTORED`: credit restored after a failed refund.\n- Overpayment actions for `CUSTOMER_SPILLED_OVER_*` entries.","type":"string"},"amount":{"description":"Positive for credit added, negative for credit taken out. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"credit_source":{"additionalProperties":false,"description":"Where the credit came from or went: on credit issued from a payment, credit applied to a sales order, and credit a refund or a lost dispute took back or gave back. Null on other entries.","properties":{"customer_payment_funding_id":{"description":"The Customer Portal payment's key, when the credit came from one. Null otherwise.","type":["string","null"]},"kind":{"description":"`issued`: credit issued from a sales order payment. `returned`: Issue credit took back credit a Customer Portal payment had left on the order. `order_deleted_credit`: issued credit whose sales order was later deleted. `applied`: credit applied to a sales order. `refund`: credit the customer had already spent, owed back after a refund. `credit_used_for_refund` and `credit_taken_back`: credit a refund took back without making the balance negative; nothing is owed. `refund_failed`: that credit given back because the refund failed. `chargeback`: taken back by a lost dispute. `refund_and_chargeback`: taken back by a lost dispute after a refund during it. `order_deleted`: taken back for a deleted sales order.","enum":["issued","returned","order_deleted_credit","applied","refund","credit_used_for_refund","credit_taken_back","refund_failed","chargeback","refund_and_chargeback","order_deleted"],"type":"string"},"order_hash_id":{"description":"The sales order's id. Null when no single order is involved, or when the order of an `applied` entry was deleted.","type":["string","null"]},"order_reference":{"description":"That sales order's number, such as `SO1001`. Not an id.","type":["string","null"]},"payment_label":{"description":"The payment the credit came from, as YoPrint names it, such as \"Stripe payment\", \"Cash payment\" or \"Customer credit\".","type":"string"}},"required":["kind","payment_label","customer_payment_funding_id","order_hash_id","order_reference"],"type":["object","null"]},"credit_source_payment_id":{"description":"Those two kinds only: the id of the sales order payment the credit came from.","type":["string","null"]},"currency_iso":{"description":"Customer Portal payment entries only: the payment's currency, such as `USD`.","type":["string","null"]},"customer_id":{"type":["string","null"]},"customer_payment_application_id":{"type":["string","null"]},"customer_payment_checkout_id":{"description":"Customer Portal payment entries only: the key of the checkout the payment was made in, or null.","type":["string","null"]},"customer_payment_funding_id":{"description":"Customer Portal payment entries only (`CUSTOMER_CHECKOUT_*`, and credit applied from such a payment): the payment's key.","type":["string","null"]},"customer_payment_source_kind":{"description":"Customer Portal payment entries only: what the entry is, for example `funding` for the payment, the kind of change for an adjustment (such as `refund`), or `application` for credit applied from it.","type":["string","null"]},"customer_payment_sources":{"description":"Customer Portal payment entries only: the Customer Portal payments the entry draws on, when it lists them; empty otherwise.","items":{"additionalProperties":false,"properties":{"amount":{"description":"A decimal string, such as `\"25.00\"`; parse it as a decimal.","type":["string","null"]},"currency_iso":{"type":["string","null"]},"customer_payment_funding_id":{"type":["string","null"]},"funding_transaction_id":{"type":["string","null"]}},"type":"object"},"type":"array"},"date":{"description":"When the entry was made.","format":"date-time","type":"string"},"direction":{"description":"Whether the entry added credit or took it out.","enum":["INCREASE","DECREASE"],"type":"string"},"funding_payment_gateway":{"description":"Customer Portal payment entries only: the payment's provider, as in `payment_gateway`.","type":["string","null"]},"funding_transaction_id":{"description":"Customer Portal payment entries only: the id of the payment's `CUSTOMER_CHECKOUT_FUNDING` entry.","type":["string","null"]},"has_open_hold":{"description":"Customer Portal payment entries only: true while the payment is held, for example by an open dispute, or when YoPrint could not read the payment.","type":"boolean"},"id":{"type":"string"},"is_deletable":{"type":"boolean"},"is_editable":{"type":"boolean"},"is_external_cash_movement":{"description":"Customer Portal payment entries only: true when money moved through the provider (the payment and its adjustments), false for credit moved inside YoPrint.","type":"boolean"},"order_id":{"description":"Always null on customer credit entries, also for credit used on or refunded from a sales order. `credit_source` names the order where there is one.","type":"null"},"payment_gateway":{"description":"The payment provider for entries that moved money through one: for a Customer Portal payment, `STRIPE`, `PAYPAL`, `SQUARE_V2`, `AUTHORIZE_NET` or `CHARGE_IT_PRO`. Null otherwise.","type":["string","null"]},"payment_method_id":{"type":["string","null"]},"payment_notices":{"description":"Customer Portal payment entries only: why the payment needs attention, such as `dispute_open`, `dispute_under_review` or `payment_needs_attention`.","items":{"additionalProperties":true,"properties":{"code":{"type":"string"},"customer_payment_funding_id":{"type":["string","null"]},"next_action":{"type":["string","null"]}},"type":"object"},"type":"array"},"provider_refund_reference":{"description":"Only on a Customer Portal payment refund that has one: the provider's refund reference.","type":"string"},"recovery_kind":{"description":"`CUSTOMER_CREDIT_RECOVERY` and `CUSTOMER_CREDIT_RESTORED` entries only: `credit_consumed` when unspent credit was taken back, `negative_credit` when spent credit was taken back and the balance went below zero.","enum":["credit_consumed","negative_credit",null],"type":["string","null"]},"reference_description":{"type":["string","null"]},"reference_id":{"description":"Your reference; on a Customer Portal payment adjustment, the payment provider's reference.","type":["string","null"]},"refundable_amount":{"description":"How much of it can still be refunded; 0 for credit entries. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"related_transaction":{"description":"The entry this one belongs to: for a refund, the payment; for `CUSTOMER_CREDIT_RECOVERY` and `CUSTOMER_CREDIT_RESTORED`, the refund; for a Customer Portal payment adjustment, its `CUSTOMER_CHECKOUT_FUNDING` entry. Null otherwise.","type":["string","null"]},"restores_transaction_id":{"description":"`CUSTOMER_CREDIT_RESTORED` only: the `CUSTOMER_CREDIT_RECOVERY` entry it gives back.","type":["string","null"]},"reversal_transaction_id":{"description":"`CUSTOMER_CREDIT_RESTORED` only: the entry that recorded the failed refund.","type":["string","null"]},"subtype":{"description":"The category of the credit entry:\n\n- `TRANSFER`: all `MANUAL` entries.\n- `CUSTOMER_CHECKOUT_FUNDING`: a Customer Portal payment received into customer credit.\n- `CUSTOMER_CHECKOUT_FUNDING_ADJUSTMENT`: a later change to a portal payment, such as a refund or lost dispute.\n- `CUSTOMER_SPILLED_OVER_GATEWAY_PAYMENT`: an online payment overpayment moved into credit.\n- `CUSTOMER_SPILLED_OVER_GATEWAY_PAYMENT_REFUND`: a refund of an overpayment.\n- `CUSTOMER_SPILLED_OVER_GATEWAY_REFUND`: an online refund overpayment moved into credit.\n- `CUSTOMER_CREDIT_RECOVERY`: credit a refund took back.\n- `CUSTOMER_CREDIT_RESTORED`: credit given back because that refund failed.","enum":["TRANSFER","CUSTOMER_CHECKOUT_FUNDING","CUSTOMER_CHECKOUT_FUNDING_ADJUSTMENT","CUSTOMER_SPILLED_OVER_GATEWAY_PAYMENT","CUSTOMER_SPILLED_OVER_GATEWAY_PAYMENT_REFUND","CUSTOMER_SPILLED_OVER_GATEWAY_REFUND","CUSTOMER_CREDIT_RECOVERY","CUSTOMER_CREDIT_RESTORED"],"type":"string"},"token":{"type":["string","null"]},"type":{"description":"Whether the entry was made by a person or by YoPrint:\n\n- `MANUAL`: credit added or taken out by hand, credit used to pay a sales order, and sales order payments refunded to credit.\n- `SYSTEM`: entries YoPrint creates automatically, including Customer Portal payments received into credit and their adjustments (such as refunds), online overpayments, and credit recovered or restored.","enum":["MANUAL","SYSTEM"],"type":"string"},"user_id":{"description":"Who made it.","type":["string","null"]},"voided":{"type":"boolean"}},"required":["id","direction","type","subtype","action","amount","date","credit_source"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a customer's credit history","tags":["Customer credit"],"x-yoprint-docs":{"errors":[{"fix":"Send `per_page` 1 to 100 and `page` 1 or more.","status":422,"when":"`per_page` is over 100 or below 1, or `page` is below 1. `error.code` is `validation_failed`."},{"fix":"Check the id.","status":404,"when":"No live customer with this id: deleted customers are not found here. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_credit_store","v1_public_customer_credit_show"]}},"post":{"description":"Adds credit to the customer's balance (`action: deposit`) or takes it out (`action: withdraw`), and returns the entry. This is Issue Customer Credit in YoPrint. Credit can then pay the customer's sales orders.\n\nSend a whole number of thousandths for `amount`: `50000` is 50.00. The sign is ignored; `action` decides the direction.","operationId":"v1_public_customer_credit_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"deposit":{"summary":"Add 50.00 of credit","value":{"action":"deposit","amount":50000,"payment_method_id":"6nz3Vu9sFR4dxM","reference_id":"CHQ-1001"}},"withdraw":{"summary":"Take out 20.00","value":{"action":"withdraw","amount":20000}}},"schema":{"additionalProperties":false,"properties":{"action":{"enum":["deposit","withdraw"],"type":"string"},"amount":{"description":"Send a whole number of thousandths: `50000` is 50.00. A number with decimals is refused with 422.","type":"integer"},"payment_method_id":{"description":"One of your team's payment methods: how the money came in or went out.","type":"string"},"reference_id":{"description":"Your reference, such as a cheque or transfer number.","type":"string"}},"required":["action","amount"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"action":"CUSTOMER_DEPOSIT","amount":50000,"credit_source":null,"customer_id":"V4keXwwxMQyXw7","date":"2026-11-01T09:00:00+00:00","direction":"INCREASE","id":"mJ3uYS5OJQ9VEq","is_deletable":true,"is_editable":false,"order_id":null,"payment_gateway":null,"payment_method_id":"6nz3Vu9sFR4dxM","reference_description":null,"reference_id":"CHQ-1001","refundable_amount":0,"related_transaction":null,"subtype":"TRANSFER","token":null,"type":"MANUAL","user_id":"lOURnovd3hkIQI","voided":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"action":{"description":"The specific action that created the entry:\n\nManual entries:\n- `CUSTOMER_DEPOSIT`: credit added by hand (created by this API).\n- `CUSTOMER_WITHDRAW`: credit taken out by hand (created by this API).\n- `CUSTOMER_CREDIT_WITHDRAW`: credit used to pay a sales order.\n- `CUSTOMER_CREDIT_DEPOSIT`: a sales order payment refunded to credit.\n\nSystem entries:\n- `CUSTOMER_CHECKOUT_FUNDING`: a Customer Portal payment received into credit.\n- `CUSTOMER_CHECKOUT_<KIND>`: an adjustment to a portal payment (such as `CUSTOMER_CHECKOUT_REFUND`).\n- `CUSTOMER_CREDIT_RECOVERY`: credit a refund took back.\n- `CUSTOMER_CREDIT_RESTORED`: credit restored after a failed refund.\n- Overpayment actions for `CUSTOMER_SPILLED_OVER_*` entries.","type":"string"},"amount":{"description":"Positive for credit added, negative for credit taken out. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"credit_source":{"additionalProperties":false,"description":"Where the credit came from or went: on credit issued from a payment, credit applied to a sales order, and credit a refund or a lost dispute took back or gave back. Null on other entries.","properties":{"customer_payment_funding_id":{"description":"The Customer Portal payment's key, when the credit came from one. Null otherwise.","type":["string","null"]},"kind":{"description":"`issued`: credit issued from a sales order payment. `returned`: Issue credit took back credit a Customer Portal payment had left on the order. `order_deleted_credit`: issued credit whose sales order was later deleted. `applied`: credit applied to a sales order. `refund`: credit the customer had already spent, owed back after a refund. `credit_used_for_refund` and `credit_taken_back`: credit a refund took back without making the balance negative; nothing is owed. `refund_failed`: that credit given back because the refund failed. `chargeback`: taken back by a lost dispute. `refund_and_chargeback`: taken back by a lost dispute after a refund during it. `order_deleted`: taken back for a deleted sales order.","enum":["issued","returned","order_deleted_credit","applied","refund","credit_used_for_refund","credit_taken_back","refund_failed","chargeback","refund_and_chargeback","order_deleted"],"type":"string"},"order_hash_id":{"description":"The sales order's id. Null when no single order is involved, or when the order of an `applied` entry was deleted.","type":["string","null"]},"order_reference":{"description":"That sales order's number, such as `SO1001`. Not an id.","type":["string","null"]},"payment_label":{"description":"The payment the credit came from, as YoPrint names it, such as \"Stripe payment\", \"Cash payment\" or \"Customer credit\".","type":"string"}},"required":["kind","payment_label","customer_payment_funding_id","order_hash_id","order_reference"],"type":["object","null"]},"credit_source_payment_id":{"description":"Those two kinds only: the id of the sales order payment the credit came from.","type":["string","null"]},"currency_iso":{"description":"Customer Portal payment entries only: the payment's currency, such as `USD`.","type":["string","null"]},"customer_id":{"type":["string","null"]},"customer_payment_application_id":{"type":["string","null"]},"customer_payment_checkout_id":{"description":"Customer Portal payment entries only: the key of the checkout the payment was made in, or null.","type":["string","null"]},"customer_payment_funding_id":{"description":"Customer Portal payment entries only (`CUSTOMER_CHECKOUT_*`, and credit applied from such a payment): the payment's key.","type":["string","null"]},"customer_payment_source_kind":{"description":"Customer Portal payment entries only: what the entry is, for example `funding` for the payment, the kind of change for an adjustment (such as `refund`), or `application` for credit applied from it.","type":["string","null"]},"customer_payment_sources":{"description":"Customer Portal payment entries only: the Customer Portal payments the entry draws on, when it lists them; empty otherwise.","items":{"additionalProperties":false,"properties":{"amount":{"description":"A decimal string, such as `\"25.00\"`; parse it as a decimal.","type":["string","null"]},"currency_iso":{"type":["string","null"]},"customer_payment_funding_id":{"type":["string","null"]},"funding_transaction_id":{"type":["string","null"]}},"type":"object"},"type":"array"},"date":{"description":"When the entry was made.","format":"date-time","type":"string"},"direction":{"description":"Whether the entry added credit or took it out.","enum":["INCREASE","DECREASE"],"type":"string"},"funding_payment_gateway":{"description":"Customer Portal payment entries only: the payment's provider, as in `payment_gateway`.","type":["string","null"]},"funding_transaction_id":{"description":"Customer Portal payment entries only: the id of the payment's `CUSTOMER_CHECKOUT_FUNDING` entry.","type":["string","null"]},"has_open_hold":{"description":"Customer Portal payment entries only: true while the payment is held, for example by an open dispute, or when YoPrint could not read the payment.","type":"boolean"},"id":{"type":"string"},"is_deletable":{"type":"boolean"},"is_editable":{"type":"boolean"},"is_external_cash_movement":{"description":"Customer Portal payment entries only: true when money moved through the provider (the payment and its adjustments), false for credit moved inside YoPrint.","type":"boolean"},"order_id":{"description":"Always null on customer credit entries, also for credit used on or refunded from a sales order. `credit_source` names the order where there is one.","type":"null"},"payment_gateway":{"description":"The payment provider for entries that moved money through one: for a Customer Portal payment, `STRIPE`, `PAYPAL`, `SQUARE_V2`, `AUTHORIZE_NET` or `CHARGE_IT_PRO`. Null otherwise.","type":["string","null"]},"payment_method_id":{"type":["string","null"]},"payment_notices":{"description":"Customer Portal payment entries only: why the payment needs attention, such as `dispute_open`, `dispute_under_review` or `payment_needs_attention`.","items":{"additionalProperties":true,"properties":{"code":{"type":"string"},"customer_payment_funding_id":{"type":["string","null"]},"next_action":{"type":["string","null"]}},"type":"object"},"type":"array"},"provider_refund_reference":{"description":"Only on a Customer Portal payment refund that has one: the provider's refund reference.","type":"string"},"recovery_kind":{"description":"`CUSTOMER_CREDIT_RECOVERY` and `CUSTOMER_CREDIT_RESTORED` entries only: `credit_consumed` when unspent credit was taken back, `negative_credit` when spent credit was taken back and the balance went below zero.","enum":["credit_consumed","negative_credit",null],"type":["string","null"]},"reference_description":{"type":["string","null"]},"reference_id":{"description":"Your reference; on a Customer Portal payment adjustment, the payment provider's reference.","type":["string","null"]},"refundable_amount":{"description":"How much of it can still be refunded; 0 for credit entries. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"related_transaction":{"description":"The entry this one belongs to: for a refund, the payment; for `CUSTOMER_CREDIT_RECOVERY` and `CUSTOMER_CREDIT_RESTORED`, the refund; for a Customer Portal payment adjustment, its `CUSTOMER_CHECKOUT_FUNDING` entry. Null otherwise.","type":["string","null"]},"restores_transaction_id":{"description":"`CUSTOMER_CREDIT_RESTORED` only: the `CUSTOMER_CREDIT_RECOVERY` entry it gives back.","type":["string","null"]},"reversal_transaction_id":{"description":"`CUSTOMER_CREDIT_RESTORED` only: the entry that recorded the failed refund.","type":["string","null"]},"subtype":{"description":"The category of the credit entry:\n\n- `TRANSFER`: all `MANUAL` entries.\n- `CUSTOMER_CHECKOUT_FUNDING`: a Customer Portal payment received into customer credit.\n- `CUSTOMER_CHECKOUT_FUNDING_ADJUSTMENT`: a later change to a portal payment, such as a refund or lost dispute.\n- `CUSTOMER_SPILLED_OVER_GATEWAY_PAYMENT`: an online payment overpayment moved into credit.\n- `CUSTOMER_SPILLED_OVER_GATEWAY_PAYMENT_REFUND`: a refund of an overpayment.\n- `CUSTOMER_SPILLED_OVER_GATEWAY_REFUND`: an online refund overpayment moved into credit.\n- `CUSTOMER_CREDIT_RECOVERY`: credit a refund took back.\n- `CUSTOMER_CREDIT_RESTORED`: credit given back because that refund failed.","enum":["TRANSFER","CUSTOMER_CHECKOUT_FUNDING","CUSTOMER_CHECKOUT_FUNDING_ADJUSTMENT","CUSTOMER_SPILLED_OVER_GATEWAY_PAYMENT","CUSTOMER_SPILLED_OVER_GATEWAY_PAYMENT_REFUND","CUSTOMER_SPILLED_OVER_GATEWAY_REFUND","CUSTOMER_CREDIT_RECOVERY","CUSTOMER_CREDIT_RESTORED"],"type":"string"},"token":{"type":["string","null"]},"type":{"description":"Whether the entry was made by a person or by YoPrint:\n\n- `MANUAL`: credit added or taken out by hand, credit used to pay a sales order, and sales order payments refunded to credit.\n- `SYSTEM`: entries YoPrint creates automatically, including Customer Portal payments received into credit and their adjustments (such as refunds), online overpayments, and credit recovered or restored.","enum":["MANUAL","SYSTEM"],"type":"string"},"user_id":{"description":"Who made it.","type":["string","null"]},"voided":{"type":"boolean"}},"required":["id","direction","type","subtype","action","amount","date","credit_source"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add or take out customer credit","tags":["Customer credit"],"x-yoprint-docs":{"errors":[{"fix":"Read the customer's `wallet_fund` and `held_credit` first.","status":422,"when":"Not enough available credit for the withdrawal (`error.code` `validation_error`, \"Insufficient Customer Balance to perform such action\")."},{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"`action` or `amount` is missing, `amount` is not a whole number of thousandths (such as `50000.5`; `error.fields.amount` says \"The amount must be a whole number of thousandths of the currency unit, such as 12500 for 12.50.\"), or `payment_method_id` is not a payment method of the team. `error.code` is `validation_failed`."},{"fix":"Restore a deleted customer first.","status":404,"when":"The customer is deleted, or not the team's. `error.code` is null and `error.message` names the record type."},{"fix":"Ask for Manage Customers \"Manage All\", or to be assigned to the customer.","status":403,"when":"Your role can't change this customer: it has no Manage Customers permission, or it manages only customers assigned to you and this one is not. This 403 has a short body, `{\"message\": \"No Permission to update Customer\"}`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."}],"group":"Customers","notes":["Not idempotent: each call adds a new entry. Do not retry blindly after a timeout; list the credit history first."],"permission":"Needs the Manage Customers permission: \"Manage All\" for any customer, or \"Manage Assigned to User\" for customers assigned to you.","related":["v1_public_customer_credit_index","v2_public_sales_order_credit_pay_with_customer_credit","v1_public_payment_method_index"],"rules":["A withdrawal can't be more than the credit available now: `wallet_fund` less credit from Customer Portal payments that is held (for example by a dispute, see `held_credit`) or set aside for a payment or refund in progress. None is allowed while the balance is negative (422 \"Insufficient Customer Balance to perform such action\").","A deleted customer is not found (404). Restore it first.","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."],"side_effects":["Changes the customer's credit balance (`wallet_fund`) at once.","Sends `customer_credit.deposited` or `customer_credit.withdrew`.","Open Customer Portal pages of the customer are told to refresh."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/credit/{id}":{"get":{"description":"Returns one credit entry of the customer.","operationId":"v1_public_customer_credit_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The credit entry's id (`id` from List a customer's credit history). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"action":"CUSTOMER_DEPOSIT","amount":50000,"credit_source":null,"customer_id":"V4keXwwxMQyXw7","date":"2026-11-01T09:00:00+00:00","direction":"INCREASE","id":"mJ3uYS5OJQ9VEq","is_deletable":true,"is_editable":false,"order_id":null,"payment_gateway":null,"payment_method_id":"6nz3Vu9sFR4dxM","reference_description":null,"reference_id":"CHQ-1001","refundable_amount":0,"related_transaction":null,"subtype":"TRANSFER","token":null,"type":"MANUAL","user_id":"lOURnovd3hkIQI","voided":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"action":{"description":"The specific action that created the entry:\n\nManual entries:\n- `CUSTOMER_DEPOSIT`: credit added by hand (created by this API).\n- `CUSTOMER_WITHDRAW`: credit taken out by hand (created by this API).\n- `CUSTOMER_CREDIT_WITHDRAW`: credit used to pay a sales order.\n- `CUSTOMER_CREDIT_DEPOSIT`: a sales order payment refunded to credit.\n\nSystem entries:\n- `CUSTOMER_CHECKOUT_FUNDING`: a Customer Portal payment received into credit.\n- `CUSTOMER_CHECKOUT_<KIND>`: an adjustment to a portal payment (such as `CUSTOMER_CHECKOUT_REFUND`).\n- `CUSTOMER_CREDIT_RECOVERY`: credit a refund took back.\n- `CUSTOMER_CREDIT_RESTORED`: credit restored after a failed refund.\n- Overpayment actions for `CUSTOMER_SPILLED_OVER_*` entries.","type":"string"},"amount":{"description":"Positive for credit added, negative for credit taken out. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"credit_source":{"additionalProperties":false,"description":"Where the credit came from or went: on credit issued from a payment, credit applied to a sales order, and credit a refund or a lost dispute took back or gave back. Null on other entries.","properties":{"customer_payment_funding_id":{"description":"The Customer Portal payment's key, when the credit came from one. Null otherwise.","type":["string","null"]},"kind":{"description":"`issued`: credit issued from a sales order payment. `returned`: Issue credit took back credit a Customer Portal payment had left on the order. `order_deleted_credit`: issued credit whose sales order was later deleted. `applied`: credit applied to a sales order. `refund`: credit the customer had already spent, owed back after a refund. `credit_used_for_refund` and `credit_taken_back`: credit a refund took back without making the balance negative; nothing is owed. `refund_failed`: that credit given back because the refund failed. `chargeback`: taken back by a lost dispute. `refund_and_chargeback`: taken back by a lost dispute after a refund during it. `order_deleted`: taken back for a deleted sales order.","enum":["issued","returned","order_deleted_credit","applied","refund","credit_used_for_refund","credit_taken_back","refund_failed","chargeback","refund_and_chargeback","order_deleted"],"type":"string"},"order_hash_id":{"description":"The sales order's id. Null when no single order is involved, or when the order of an `applied` entry was deleted.","type":["string","null"]},"order_reference":{"description":"That sales order's number, such as `SO1001`. Not an id.","type":["string","null"]},"payment_label":{"description":"The payment the credit came from, as YoPrint names it, such as \"Stripe payment\", \"Cash payment\" or \"Customer credit\".","type":"string"}},"required":["kind","payment_label","customer_payment_funding_id","order_hash_id","order_reference"],"type":["object","null"]},"credit_source_payment_id":{"description":"Those two kinds only: the id of the sales order payment the credit came from.","type":["string","null"]},"currency_iso":{"description":"Customer Portal payment entries only: the payment's currency, such as `USD`.","type":["string","null"]},"customer_id":{"type":["string","null"]},"customer_payment_application_id":{"type":["string","null"]},"customer_payment_checkout_id":{"description":"Customer Portal payment entries only: the key of the checkout the payment was made in, or null.","type":["string","null"]},"customer_payment_funding_id":{"description":"Customer Portal payment entries only (`CUSTOMER_CHECKOUT_*`, and credit applied from such a payment): the payment's key.","type":["string","null"]},"customer_payment_source_kind":{"description":"Customer Portal payment entries only: what the entry is, for example `funding` for the payment, the kind of change for an adjustment (such as `refund`), or `application` for credit applied from it.","type":["string","null"]},"customer_payment_sources":{"description":"Customer Portal payment entries only: the Customer Portal payments the entry draws on, when it lists them; empty otherwise.","items":{"additionalProperties":false,"properties":{"amount":{"description":"A decimal string, such as `\"25.00\"`; parse it as a decimal.","type":["string","null"]},"currency_iso":{"type":["string","null"]},"customer_payment_funding_id":{"type":["string","null"]},"funding_transaction_id":{"type":["string","null"]}},"type":"object"},"type":"array"},"date":{"description":"When the entry was made.","format":"date-time","type":"string"},"direction":{"description":"Whether the entry added credit or took it out.","enum":["INCREASE","DECREASE"],"type":"string"},"funding_payment_gateway":{"description":"Customer Portal payment entries only: the payment's provider, as in `payment_gateway`.","type":["string","null"]},"funding_transaction_id":{"description":"Customer Portal payment entries only: the id of the payment's `CUSTOMER_CHECKOUT_FUNDING` entry.","type":["string","null"]},"has_open_hold":{"description":"Customer Portal payment entries only: true while the payment is held, for example by an open dispute, or when YoPrint could not read the payment.","type":"boolean"},"id":{"type":"string"},"is_deletable":{"type":"boolean"},"is_editable":{"type":"boolean"},"is_external_cash_movement":{"description":"Customer Portal payment entries only: true when money moved through the provider (the payment and its adjustments), false for credit moved inside YoPrint.","type":"boolean"},"order_id":{"description":"Always null on customer credit entries, also for credit used on or refunded from a sales order. `credit_source` names the order where there is one.","type":"null"},"payment_gateway":{"description":"The payment provider for entries that moved money through one: for a Customer Portal payment, `STRIPE`, `PAYPAL`, `SQUARE_V2`, `AUTHORIZE_NET` or `CHARGE_IT_PRO`. Null otherwise.","type":["string","null"]},"payment_method_id":{"type":["string","null"]},"payment_notices":{"description":"Customer Portal payment entries only: why the payment needs attention, such as `dispute_open`, `dispute_under_review` or `payment_needs_attention`.","items":{"additionalProperties":true,"properties":{"code":{"type":"string"},"customer_payment_funding_id":{"type":["string","null"]},"next_action":{"type":["string","null"]}},"type":"object"},"type":"array"},"provider_refund_reference":{"description":"Only on a Customer Portal payment refund that has one: the provider's refund reference.","type":"string"},"recovery_kind":{"description":"`CUSTOMER_CREDIT_RECOVERY` and `CUSTOMER_CREDIT_RESTORED` entries only: `credit_consumed` when unspent credit was taken back, `negative_credit` when spent credit was taken back and the balance went below zero.","enum":["credit_consumed","negative_credit",null],"type":["string","null"]},"reference_description":{"type":["string","null"]},"reference_id":{"description":"Your reference; on a Customer Portal payment adjustment, the payment provider's reference.","type":["string","null"]},"refundable_amount":{"description":"How much of it can still be refunded; 0 for credit entries. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"related_transaction":{"description":"The entry this one belongs to: for a refund, the payment; for `CUSTOMER_CREDIT_RECOVERY` and `CUSTOMER_CREDIT_RESTORED`, the refund; for a Customer Portal payment adjustment, its `CUSTOMER_CHECKOUT_FUNDING` entry. Null otherwise.","type":["string","null"]},"restores_transaction_id":{"description":"`CUSTOMER_CREDIT_RESTORED` only: the `CUSTOMER_CREDIT_RECOVERY` entry it gives back.","type":["string","null"]},"reversal_transaction_id":{"description":"`CUSTOMER_CREDIT_RESTORED` only: the entry that recorded the failed refund.","type":["string","null"]},"subtype":{"description":"The category of the credit entry:\n\n- `TRANSFER`: all `MANUAL` entries.\n- `CUSTOMER_CHECKOUT_FUNDING`: a Customer Portal payment received into customer credit.\n- `CUSTOMER_CHECKOUT_FUNDING_ADJUSTMENT`: a later change to a portal payment, such as a refund or lost dispute.\n- `CUSTOMER_SPILLED_OVER_GATEWAY_PAYMENT`: an online payment overpayment moved into credit.\n- `CUSTOMER_SPILLED_OVER_GATEWAY_PAYMENT_REFUND`: a refund of an overpayment.\n- `CUSTOMER_SPILLED_OVER_GATEWAY_REFUND`: an online refund overpayment moved into credit.\n- `CUSTOMER_CREDIT_RECOVERY`: credit a refund took back.\n- `CUSTOMER_CREDIT_RESTORED`: credit given back because that refund failed.","enum":["TRANSFER","CUSTOMER_CHECKOUT_FUNDING","CUSTOMER_CHECKOUT_FUNDING_ADJUSTMENT","CUSTOMER_SPILLED_OVER_GATEWAY_PAYMENT","CUSTOMER_SPILLED_OVER_GATEWAY_PAYMENT_REFUND","CUSTOMER_SPILLED_OVER_GATEWAY_REFUND","CUSTOMER_CREDIT_RECOVERY","CUSTOMER_CREDIT_RESTORED"],"type":"string"},"token":{"type":["string","null"]},"type":{"description":"Whether the entry was made by a person or by YoPrint:\n\n- `MANUAL`: credit added or taken out by hand, credit used to pay a sales order, and sales order payments refunded to credit.\n- `SYSTEM`: entries YoPrint creates automatically, including Customer Portal payments received into credit and their adjustments (such as refunds), online overpayments, and credit recovered or restored.","enum":["MANUAL","SYSTEM"],"type":"string"},"user_id":{"description":"Who made it.","type":["string","null"]},"voided":{"type":"boolean"}},"required":["id","direction","type","subtype","action","amount","date","credit_source"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a customer credit entry","tags":["Customer credit"],"x-yoprint-docs":{"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_credit_index"]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/customer_portal_token_override":{"delete":{"description":"Clears the custom Customer Portal ID, so the generated one is shown again, and returns the customer with `contacts`.","operationId":"v1_public_customer_customer_portal_token_override_delete","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_warning":null,"addresses":[{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":true},{"address1":"100 Example Street","address2":"Dock 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"swtHxyIfOvF62K","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Warehouse","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false}],"assigned_users":[{"avatar_url":"https://example.com/avatars/alex.png","id":"lOURnovd3hkIQI","name":"Alex Rivera"}],"contacts":[{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"}],"created_at":"2026-10-01T09:00:00+00:00","customer_portal_enabled":null,"customer_portal_id":"HWYGf6vzKsjwpS","customer_portal_id_override":null,"customer_portal_link":null,"customer_portal_payment_option":null,"customer_profiles":[{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"}],"default_payment_term_id":null,"default_pricing_group_id":null,"default_warehouse_id":null,"deposit_due_amount":0,"display_customer_portal_id":"HWYGf6vzKsjwpS","external_type":null,"has_customer_portal_id_override":false,"held_credit":0,"hide":false,"id":"V4keXwwxMQyXw7","internal_notes":null,"is_editable":true,"is_external":false,"is_system":false,"last_ordered_date":"2026-10-28T08:00:00+00:00","media":[{"collection":"tax_exemption","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"customer_id":"V4keXwwxMQyXw7","file_name":"resale-certificate.pdf","id":"4GR9C3ZTMYtda5","is_image":false,"mime_type":"application/pdf","name":"Resale certificate 2026.pdf","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/4GR9C3ZTMYtda5/download","view_url":"https://example.com/media/4GR9C3ZTMYtda5/view"}],"name":"Northwind Apparel","ordered_amount":125000,"overdue_amount":0,"pdf":{"invoice_statement":"https://example.com/pdf/customer_invoice_statement/V4keXwwxMQyXw7"},"quote_amount":0,"resale_number":null,"shopify_compliance_deletion":null,"system_type":null,"tags":[{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"}],"tax_exempt":false,"third_party_billing_default":"none","trashed":false,"unpaid_amount":25000,"updated_at":"2026-11-01T09:00:00+00:00","vat_number":null,"wallet_currency":{"default":true,"id":"icHZvqV1nkXRcA","iso":"USD","name":"US Dollar","symbol":"$","trashed":false},"wallet_fund":50000,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"account_warning":{"additionalProperties":false,"description":"Why YoPrint shows a warning next to the customer's name. Null when there is nothing to warn about.","properties":{"open_dispute":{"additionalProperties":false,"description":"The customer's payments under a dispute that is open or under review; null when there is none.","properties":{"count":{"description":"How many payments are disputed.","type":"integer"},"payment_amount":{"description":"The total of the disputed payments, each counted once. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]}},"required":["payment_amount","count"],"type":["object","null"]},"owed_amount":{"description":"What the customer owes back because `wallet_fund` is negative, as a positive amount; null when it is not negative. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]}},"required":["owed_amount","open_dispute"],"type":["object","null"]},"addresses":{"description":"Billing and shipping addresses that are not deleted, old copies replaced by an edit included (`is_current_source: false`).","items":{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},"type":"array"},"assigned_users":{"description":"The users assigned to the customer. Unlike List the users assigned to a customer, people who have left the team stay in this list.","items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","avatar_url","name"],"type":"object"},"type":"array"},"contacts":{"description":"Every contact, deleted ones included (`trashed`).","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"customer_portal_enabled":{"description":"Whether the customer's contacts can open the Customer Portal (Portal settings > Customer portal in YoPrint). `false`: the portal is off for this customer. `true`, or null (never set), means on.","type":["boolean","null"]},"customer_portal_id":{"description":"The id used in the customer's portal address. Null for Shopify customers.","type":["string","null"]},"customer_portal_id_override":{"type":["string","null"]},"customer_portal_link":{"description":"Always null: YoPrint no longer returns a portal sign-in link for the customer. The field stays for older integrations.","type":"null"},"customer_portal_payment_option":{"description":"Whether the customer can pay online in the portal. Null follows the team setting (and is always null for Shopify customers).","enum":["ENABLED","DISABLED",null],"type":["string","null"]},"customer_profiles":{"description":"Brand profiles.","items":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"type":"array"},"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"default_warehouse_id":{"type":["string","null"]},"deposit_due_amount":{"description":"Deposits still due. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"display_customer_portal_id":{"description":"The Customer Portal ID shown to people: the override when set, otherwise `customer_portal_id`. `-` for Shopify customers.","type":"string"},"external_type":{"description":"`shopify` for customers synced from Shopify.","type":["string","null"]},"has_customer_portal_id_override":{"type":"boolean"},"held_credit":{"description":"The part of `wallet_fund` held while a payment is under an open dispute or a provider review: it can't be applied to orders or taken out until the hold ends. Never more than `wallet_fund`; 0 when `wallet_fund` is 0 or negative. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"hide":{"description":"True when the customer is archived.","type":"boolean"},"id":{"description":"The customer id. Use it in paths and as `customer_id` on sales orders and quotes.","type":"string"},"internal_notes":{"type":["string","null"]},"is_editable":{"description":"False for Shopify and system customers: they can't be changed through this API.","type":"boolean"},"is_external":{"type":"boolean"},"is_system":{"type":"boolean"},"last_ordered_date":{"description":"The issue date of the customer's latest published sales order. Null when it has none.","format":"date-time","type":["string","null"]},"media":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"name":{"description":"Null for a customer created by upsert without a name.","type":["string","null"]},"ordered_amount":{"description":"Total of the customer's published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"overdue_amount":{"description":"Unpaid amounts past their payment due date. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"pdf":{"additionalProperties":false,"properties":{"invoice_statement":{"description":"A link that downloads the customer's invoice statement PDF. Its token opens only this customer's statement and stops working 9,000 hours (about a year) after the answer was made. Anyone with the link can download the statement: don't share it.","type":"string"}},"required":["invoice_statement"],"type":"object"},"quote_amount":{"description":"Total of open quotes. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"resale_number":{"type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"type":["object","null"]},"system_type":{"type":["string","null"]},"tags":{"items":{"additionalProperties":false,"properties":{"color_hex":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"tax_exempt":{"type":"boolean"},"third_party_billing_default":{"description":"How a shipping label for this customer is billed by default. `default_carrier_account`: YoPrint's label and rate dialogs start on the customer's default carrier account (third-party billing). `none`: they start with no third-party billing.","enum":["none","default_carrier_account"],"type":"string"},"trashed":{"description":"True when the customer is deleted.","type":"boolean"},"unpaid_amount":{"description":"What the customer still owes on published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"updated_at":{"format":"date-time","type":"string"},"vat_number":{"description":"The customer's tax number (shown as Tax number in YoPrint).","type":["string","null"]},"wallet_currency":{"additionalProperties":false,"description":"The team's default currency, the one `wallet_fund` is in. `iso` is its code.","properties":{"default":{"type":"boolean"},"id":{"type":"string"},"iso":{"description":"The ISO 4217 code, such as `USD`.","type":["string","null"]},"name":{"type":["string","null"]},"symbol":{"type":["string","null"]},"trashed":{"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"wallet_fund":{"description":"Customer credit balance. Negative when the customer owes credit back, for example after a refund of a payment whose credit was already spent. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"website":{"type":["string","null"]}},"required":["id","name","tax_exempt","trashed","hide","is_external","is_system","is_editable","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove a custom Customer Portal ID","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the id. Find deleted customers with the `trashed_only` filter and restore them first.","status":404,"when":"No live customer with this id in the team: deleted customers are not found here. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_customer_portal_token_override_update"],"rules":["Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."]}},"patch":{"description":"Sets the Customer Portal ID shown for this customer (`display_customer_portal_id`) to a value you choose, and returns the customer with `contacts`. The id YoPrint generated keeps working in portal links.","operationId":"v1_public_customer_customer_portal_token_override_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"customer_portal_token_override":"NORTHWIND"},"schema":{"additionalProperties":false,"properties":{"customer_portal_token_override":{"description":"The new Customer Portal ID. Unique in the team.","type":"string"}},"required":["customer_portal_token_override"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_warning":null,"addresses":[{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":true},{"address1":"100 Example Street","address2":"Dock 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"swtHxyIfOvF62K","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Warehouse","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false}],"assigned_users":[{"avatar_url":"https://example.com/avatars/alex.png","id":"lOURnovd3hkIQI","name":"Alex Rivera"}],"contacts":[{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"}],"created_at":"2026-10-01T09:00:00+00:00","customer_portal_enabled":null,"customer_portal_id":"HWYGf6vzKsjwpS","customer_portal_id_override":"NORTHWIND","customer_portal_link":null,"customer_portal_payment_option":null,"customer_profiles":[{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"}],"default_payment_term_id":null,"default_pricing_group_id":null,"default_warehouse_id":null,"deposit_due_amount":0,"display_customer_portal_id":"NORTHWIND","external_type":null,"has_customer_portal_id_override":true,"held_credit":0,"hide":false,"id":"V4keXwwxMQyXw7","internal_notes":null,"is_editable":true,"is_external":false,"is_system":false,"last_ordered_date":"2026-10-28T08:00:00+00:00","media":[{"collection":"tax_exemption","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"customer_id":"V4keXwwxMQyXw7","file_name":"resale-certificate.pdf","id":"4GR9C3ZTMYtda5","is_image":false,"mime_type":"application/pdf","name":"Resale certificate 2026.pdf","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/4GR9C3ZTMYtda5/download","view_url":"https://example.com/media/4GR9C3ZTMYtda5/view"}],"name":"Northwind Apparel","ordered_amount":125000,"overdue_amount":0,"pdf":{"invoice_statement":"https://example.com/pdf/customer_invoice_statement/V4keXwwxMQyXw7"},"quote_amount":0,"resale_number":null,"shopify_compliance_deletion":null,"system_type":null,"tags":[{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"}],"tax_exempt":false,"third_party_billing_default":"none","trashed":false,"unpaid_amount":25000,"updated_at":"2026-11-01T09:00:00+00:00","vat_number":null,"wallet_currency":{"default":true,"id":"icHZvqV1nkXRcA","iso":"USD","name":"US Dollar","symbol":"$","trashed":false},"wallet_fund":50000,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"account_warning":{"additionalProperties":false,"description":"Why YoPrint shows a warning next to the customer's name. Null when there is nothing to warn about.","properties":{"open_dispute":{"additionalProperties":false,"description":"The customer's payments under a dispute that is open or under review; null when there is none.","properties":{"count":{"description":"How many payments are disputed.","type":"integer"},"payment_amount":{"description":"The total of the disputed payments, each counted once. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]}},"required":["payment_amount","count"],"type":["object","null"]},"owed_amount":{"description":"What the customer owes back because `wallet_fund` is negative, as a positive amount; null when it is not negative. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]}},"required":["owed_amount","open_dispute"],"type":["object","null"]},"addresses":{"description":"Billing and shipping addresses that are not deleted, old copies replaced by an edit included (`is_current_source: false`).","items":{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},"type":"array"},"assigned_users":{"description":"The users assigned to the customer. Unlike List the users assigned to a customer, people who have left the team stay in this list.","items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","avatar_url","name"],"type":"object"},"type":"array"},"contacts":{"description":"Every contact, deleted ones included (`trashed`).","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"customer_portal_enabled":{"description":"Whether the customer's contacts can open the Customer Portal (Portal settings > Customer portal in YoPrint). `false`: the portal is off for this customer. `true`, or null (never set), means on.","type":["boolean","null"]},"customer_portal_id":{"description":"The id used in the customer's portal address. Null for Shopify customers.","type":["string","null"]},"customer_portal_id_override":{"type":["string","null"]},"customer_portal_link":{"description":"Always null: YoPrint no longer returns a portal sign-in link for the customer. The field stays for older integrations.","type":"null"},"customer_portal_payment_option":{"description":"Whether the customer can pay online in the portal. Null follows the team setting (and is always null for Shopify customers).","enum":["ENABLED","DISABLED",null],"type":["string","null"]},"customer_profiles":{"description":"Brand profiles.","items":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"type":"array"},"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"default_warehouse_id":{"type":["string","null"]},"deposit_due_amount":{"description":"Deposits still due. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"display_customer_portal_id":{"description":"The Customer Portal ID shown to people: the override when set, otherwise `customer_portal_id`. `-` for Shopify customers.","type":"string"},"external_type":{"description":"`shopify` for customers synced from Shopify.","type":["string","null"]},"has_customer_portal_id_override":{"type":"boolean"},"held_credit":{"description":"The part of `wallet_fund` held while a payment is under an open dispute or a provider review: it can't be applied to orders or taken out until the hold ends. Never more than `wallet_fund`; 0 when `wallet_fund` is 0 or negative. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"hide":{"description":"True when the customer is archived.","type":"boolean"},"id":{"description":"The customer id. Use it in paths and as `customer_id` on sales orders and quotes.","type":"string"},"internal_notes":{"type":["string","null"]},"is_editable":{"description":"False for Shopify and system customers: they can't be changed through this API.","type":"boolean"},"is_external":{"type":"boolean"},"is_system":{"type":"boolean"},"last_ordered_date":{"description":"The issue date of the customer's latest published sales order. Null when it has none.","format":"date-time","type":["string","null"]},"media":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"name":{"description":"Null for a customer created by upsert without a name.","type":["string","null"]},"ordered_amount":{"description":"Total of the customer's published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"overdue_amount":{"description":"Unpaid amounts past their payment due date. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"pdf":{"additionalProperties":false,"properties":{"invoice_statement":{"description":"A link that downloads the customer's invoice statement PDF. Its token opens only this customer's statement and stops working 9,000 hours (about a year) after the answer was made. Anyone with the link can download the statement: don't share it.","type":"string"}},"required":["invoice_statement"],"type":"object"},"quote_amount":{"description":"Total of open quotes. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"resale_number":{"type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"type":["object","null"]},"system_type":{"type":["string","null"]},"tags":{"items":{"additionalProperties":false,"properties":{"color_hex":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"tax_exempt":{"type":"boolean"},"third_party_billing_default":{"description":"How a shipping label for this customer is billed by default. `default_carrier_account`: YoPrint's label and rate dialogs start on the customer's default carrier account (third-party billing). `none`: they start with no third-party billing.","enum":["none","default_carrier_account"],"type":"string"},"trashed":{"description":"True when the customer is deleted.","type":"boolean"},"unpaid_amount":{"description":"What the customer still owes on published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"updated_at":{"format":"date-time","type":"string"},"vat_number":{"description":"The customer's tax number (shown as Tax number in YoPrint).","type":["string","null"]},"wallet_currency":{"additionalProperties":false,"description":"The team's default currency, the one `wallet_fund` is in. `iso` is its code.","properties":{"default":{"type":"boolean"},"id":{"type":"string"},"iso":{"description":"The ISO 4217 code, such as `USD`.","type":["string","null"]},"name":{"type":["string","null"]},"symbol":{"type":["string","null"]},"trashed":{"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"wallet_fund":{"description":"Customer credit balance. Negative when the customer owes credit back, for example after a refund of a payment whose credit was already spent. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"website":{"type":["string","null"]}},"required":["id","name","tax_exempt","trashed","hide","is_external","is_system","is_editable","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set a custom Customer Portal ID","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Pick another value.","status":422,"when":"Another customer of the team already uses this ID (`error.code` `unique_token_failed`, \"ID is already in use\")."},{"fix":"Send the new ID as a string.","status":422,"when":"`customer_portal_token_override` is missing or not a string. `error.code` is `validation_failed`."},{"fix":"Pick a value of your own, such as the company name.","status":422,"when":"The value looks like a generated ID (`error.code` `default_token_failed`, \"System reserved ID is not allowed\")."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the id. Find deleted customers with the `trashed_only` filter and restore them first.","status":404,"when":"No live customer with this id in the team: deleted customers are not found here. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_customer_portal_token_override_delete"],"rules":["Must be unique among the team's live customers (a deleted customer's ID can be reused).","Must not be a value YoPrint itself could generate as a Customer Portal ID (it is refused when it decodes as one).","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/external_id/{id}":{"delete":{"description":"Removes the link between this customer and its QuickBooks Online customer for the connection `{id}`. Nothing changes in QuickBooks. Answers `success: true` with `data: null`, also when nothing was linked or `{id}` is no integration of the team.","operationId":"v1_public_customer_external_id_delete","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The QuickBooks Online connection's id (`id` from List integrations), not the QuickBooks record's Id. A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Unlink a customer from QuickBooks","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"None needed: such customers are never linked.","status":422,"when":"The customer is synced from Shopify and `{id}` is a QuickBooks connection (`validation_error`)."},{"fix":"Check the id.","status":404,"when":"No customer with this id. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_external_id_update"]}},"get":{"description":"Reads the QuickBooks Online customer linked to this YoPrint customer, for the QuickBooks connection `{id}`. Returns `id` and `name` (its QuickBooks Id and DisplayName), `override` (the override lock), `attached_by_user` and `customer_id`, or an empty `data` when nothing is linked.\n\nThis calls QuickBooks Online each time. `{id}` is the QuickBooks connection's id from List integrations.","operationId":"v1_public_customer_external_id_get","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The QuickBooks Online connection's id (`id` from List integrations), not the QuickBooks record's Id. A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"attached_by_user":true,"customer_id":"V4keXwwxMQyXw7","id":"58","name":"Northwind Apparel","override":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"description":"The linked QuickBooks record, or an empty list `[]` when nothing is linked.","properties":{"attached_by_user":{"description":"True when someone linked it by hand.","type":"boolean"},"customer_id":{"type":"string"},"id":{"description":"The QuickBooks Id.","type":"string"},"name":{"description":"Its DisplayName in QuickBooks.","type":["string","null"]},"override":{"description":"The override lock: true means YoPrint never overwrites it. Returned exactly as `override_lock` was sent when linking (a JSON boolean when you sent one), and false when it was never set.","type":["boolean","integer","string"]}},"type":["object","array"]},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get the QuickBooks customer linked to a customer","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Use the id of the QuickBooks connection from List integrations.","status":422,"when":"`{id}` is not a QuickBooks Online connection of the team (`error.code` `external_integration_not_found`, `error.message` null)."},{"fix":"None: Shopify customers are not linked to QuickBooks.","status":422,"when":"The customer is synced from Shopify (`validation_error`, \"Shopify customers cannot be mapped to QuickBooks.\")."},{"fix":"Reconnect QuickBooks Online under Apps, or retry later.","status":422,"when":"The QuickBooks Online connection can't be used: it is waiting to be reconnected (`error.code` `auth_error`), or its sign-in expired, QuickBooks refused it or QuickBooks could not be reached (`bootstrap_error`, with the reason in `error.message`)."}],"group":"Customers","notes":["Deleted customers can be read too.","A link whose QuickBooks customer no longer exists also answers an empty `data`."],"permission":"Any member of the team.","related":["v1_public_customer_external_id_update","v1_public_customer_external_id_delete","v1_public_external_integration_index"],"rules":["Customers synced from Shopify can't be linked to QuickBooks (422 \"Shopify customers cannot be mapped to QuickBooks.\")."],"side_effects":["Calls the QuickBooks Online API with the team's connection."]}},"put":{"description":"Links this YoPrint customer to an existing QuickBooks Online customer, so YoPrint syncs it to that QuickBooks customer. YoPrint first looks the QuickBooks customer up, so it must exist. Answers `success: true` with `data: null`.\n\nWith `override_lock: true`, later syncs leave the QuickBooks customer's details alone instead of updating them from YoPrint.","operationId":"v1_public_customer_external_id_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The QuickBooks Online connection's id (`id` from List integrations), not the QuickBooks record's Id. A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"external_id":"58","override_lock":false},"schema":{"additionalProperties":false,"properties":{"external_id":{"description":"The QuickBooks Online customer Id.","type":"string"},"override_lock":{"description":"True: never overwrite this QuickBooks customer from YoPrint. Defaults to false. Send a JSON boolean: it is stored as sent and read back as `override`.","type":"boolean"}},"required":["external_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Link a customer to a QuickBooks customer","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Send `external_id`.","status":422,"when":"`external_id` is missing, or `override_lock` is not a boolean. `error.code` is `validation_failed`."},{"fix":"Use the QuickBooks connection's id.","status":422,"when":"`{id}` is an integration but not QuickBooks Online (`error.code` `unable_save_external_id`), or the customer is synced from Shopify (`validation_error`)."},{"fix":"Check the QuickBooks customer Id.","status":422,"when":"QuickBooks has no customer with this Id (`error.code` `validation_error`, \"Cannot find corresponding  QuickBook Online resource :Customer\")."},{"fix":"Reconnect QuickBooks Online under Apps, or retry later.","status":422,"when":"The QuickBooks Online connection can't be used: it is waiting to be reconnected (`error.code` `auth_error`), or its sign-in expired, QuickBooks refused it or QuickBooks could not be reached (`bootstrap_error`, with the reason in `error.message`)."},{"fix":"Check both ids.","status":404,"when":"No customer, or no integration, with these ids. `error.code` is null and `error.message` names the record type."}],"group":"Customers","notes":["Deleted customers can be linked too."],"permission":"Any member of the team.","related":["v1_public_customer_external_id_get","v1_public_customer_external_id_delete"],"rules":["The QuickBooks connection must be connected (not waiting to be reconnected).","Customers synced from Shopify can't be linked to QuickBooks (422)."],"side_effects":["Calls the QuickBooks Online API to read the customer, then saves the link."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/media":{"get":{"description":"Lists every file on the customer, in all collections. The list is paged: `pagination` gives `total`, `count`, `perPage`, `currentPage` and `totalPages`. Ask for the next page with `page`; the page size is the team's setting (50 unless changed), and `per_page` is ignored.","operationId":"v1_public_customer_media_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The page to return. Pages hold the team's page size (`pagination_per_page` in team settings: 50 unless changed, 5 to 100). `per_page` is not read here.","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"collection":"tax_exemption","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"customer_id":"V4keXwwxMQyXw7","file_name":"resale-certificate.pdf","id":"4GR9C3ZTMYtda5","is_image":false,"mime_type":"application/pdf","name":"Resale certificate 2026.pdf","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/4GR9C3ZTMYtda5/download","view_url":"https://example.com/media/4GR9C3ZTMYtda5/view"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a customer's files","tags":["Customer files"],"x-yoprint-docs":{"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_media_get_media_by_collection","v1_public_customer_upload_multiple_files"]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/media/attach":{"post":{"description":"Attaches files you already uploaded to the customer, and returns them.\n\nUpload each file first with Upload a file; then send its id here with the collection it belongs in. A file can be attached once: after that it belongs to the customer.","operationId":"v1_public_customer_upload_multiple_files","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"attachment":[{"collection":"tax_exemption","file_name":"Resale certificate 2026.pdf","id":"4GR9C3ZTMYtda5"}]},"schema":{"additionalProperties":false,"properties":{"attachment":{"items":{"additionalProperties":false,"properties":{"collection":{"description":"Where the file goes. Defaults to `external_file`, which the customer can see.","enum":["tax_exemption","internal_file","external_file",null],"type":["string","null"]},"file_name":{"description":"A display name. Defaults to the uploaded file name.","maxLength":255,"type":["string","null"]},"id":{"description":"The uploaded file's id.","type":"string"}},"required":["id"],"type":"object"},"minItems":1,"type":"array"}},"required":["attachment"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"collection":"tax_exemption","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"customer_id":"V4keXwwxMQyXw7","file_name":"resale-certificate.pdf","id":"4GR9C3ZTMYtda5","is_image":false,"mime_type":"application/pdf","name":"Resale certificate 2026.pdf","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/4GR9C3ZTMYtda5/download","view_url":"https://example.com/media/4GR9C3ZTMYtda5/view"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Attach uploaded files to a customer","tags":["Customer files"],"x-yoprint-docs":{"errors":[{"fix":"Send at least one file and a valid collection.","status":422,"when":"`attachment` is empty, an `id` is missing or not a valid id, a `collection` is not allowed, or a `file_name` is over 255 characters. `error.code` is `validation_failed`."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Upload the file first, or check the customer id.","status":404,"when":"An upload id does not exist, or no live customer has this id. `error.code` is null and `error.message` names the record type."},{"fix":"Upload the file again and send the new id.","status":500,"when":"An upload is already attached to something else. Nothing is attached."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."}],"group":"Customers","permission":"Needs the Manage Customers permission (either level). Whether the customer is assigned to you is not checked.","related":["v1_public_async_upload_store","v1_public_customer_media_index"],"rules":["Each id must be a file uploaded with Upload a file and not attached to anything yet; an attached file fails the whole request.","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."],"side_effects":["Moves each upload onto the customer and builds its previews."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/media/collection/{collection}":{"get":{"description":"Lists the customer's files in one collection:\n\n- `tax_exemption`: tax exemption certificates. The customer sees these in the customer portal.\n- `external_file`: files shared with the customer. Also shown in the portal.\n- `internal_file`: files for your team only.\n\nThe list is paged: `pagination` gives `total`, `count`, `perPage`, `currentPage` and `totalPages`. Ask for the next page with `page`; the page size is the team's setting (50 unless changed), and `per_page` is ignored.","operationId":"v1_public_customer_media_get_media_by_collection","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"Which files: `tax_exemption` (tax exemption certificates), `external_file` (files the customer can see in the portal) or `internal_file` (your team only).","example":"tax_exemption","in":"path","name":"collection","required":true,"schema":{"enum":["tax_exemption","external_file","internal_file"],"type":"string"}},{"description":"The page to return. Pages hold the team's page size (`pagination_per_page` in team settings: 50 unless changed, 5 to 100). `per_page` is not read here.","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"collection":"tax_exemption","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"customer_id":"V4keXwwxMQyXw7","file_name":"resale-certificate.pdf","id":"4GR9C3ZTMYtda5","is_image":false,"mime_type":"application/pdf","name":"Resale certificate 2026.pdf","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/4GR9C3ZTMYtda5/download","view_url":"https://example.com/media/4GR9C3ZTMYtda5/view"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a customer's files in one collection","tags":["Customer files"],"x-yoprint-docs":{"errors":[{"fix":"Use `tax_exemption`, `external_file` or `internal_file`.","status":422,"when":"The collection is not one of the three (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the id. Find deleted customers with the `trashed_only` filter and restore them first.","status":404,"when":"No live customer with this id in the team: deleted customers are not found here. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_upload_multiple_files"]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/media/{id}":{"delete":{"description":"Deletes one file from the customer.","operationId":"v1_public_customer_media_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The file's id (`id` from the list of the customer's or vendor's files). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a customer file","tags":["Customer files"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the ids.","status":404,"when":"Not a file of this customer, or no live customer has this id. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (either level). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_media_index"],"rules":["Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."]}},"get":{"description":"Returns one file of the customer.","operationId":"v1_public_customer_media_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The file's id (`id` from the list of the customer's or vendor's files). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"collection":"tax_exemption","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"customer_id":"V4keXwwxMQyXw7","file_name":"resale-certificate.pdf","id":"4GR9C3ZTMYtda5","is_image":false,"mime_type":"application/pdf","name":"Resale certificate 2026.pdf","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/4GR9C3ZTMYtda5/download","view_url":"https://example.com/media/4GR9C3ZTMYtda5/view"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a customer file","tags":["Customer files"],"x-yoprint-docs":{"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_media_index"]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/profile":{"get":{"description":"Lists the customer's brand profiles, deleted ones included (`trashed`). Each has `company_name`, `website`, `phone`, `email`, `use_custom_logo`, `address_id` and `address` (its Ship From address), `logo`, `is_primary` and `customer_id`. Not paged.\n\nWarning: YoPrint does not verify that the customer ID exists. Passing an unknown or deleted customer ID returns an empty list `[]` instead of a 404.","operationId":"v1_public_customer_profile_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a customer's brand profiles","tags":["Customer brand profiles"],"x-yoprint-docs":{"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_profile_store"]}},"post":{"description":"Creates a brand profile for the customer and returns it. The first profile becomes primary. New sales orders and quotes for the customer use the primary profile.\n\nThe Ship From address (`address_id`) must be a current billing address of this customer, or a current company location of your team.","operationId":"v1_public_customer_profile_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","email":"alex@example.com","phone":"+1 201 555 0123","use_custom_logo":false,"website":"https://example.com"},"schema":{"additionalProperties":false,"properties":{"address_id":{"description":"The Ship From address: a billing address of this customer, or a company location.","type":"string"},"company_name":{"description":"The name printed on documents.","type":"string"},"email":{"description":"The brand profile's email address, printed on documents.","type":"string"},"media_id":{"description":"Required when `use_custom_logo` is true: the id of a file you uploaded with Upload a file. A file already attached to something else is silently not used.","type":"string"},"phone":{"description":"The brand profile's phone number, printed on documents.","type":"string"},"use_custom_logo":{"description":"True to print `media_id` as the logo.","type":"boolean"},"website":{"description":"The website address.","type":"string"}},"required":["address_id","company_name","use_custom_logo"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":"wiZMcKAjsniFSE","city":"Springfield","copied_from_address_id":"wiZMcKAjsniFSE","country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"ozf36EpTUF1pLm","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Sales office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"message_code":"blocked_superseded_historical_address","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_superseded_historical_address","stale_base":null},"message":"blocked_superseded_historical_address","success":false},"schema":{"additionalProperties":false,"properties":{"address_save_result":{"additionalProperties":true,"description":"What the save did.","properties":{"current_address":{"additionalProperties":true,"description":"On a refusal: the address to edit instead.","type":["object","null"]},"message_code":{"description":"The message code for what happened, identical to `save_mode`.","type":"string"},"operation_key":{"description":"The key you sent, or one YoPrint made.","type":["string","null"]},"previous_address":{"additionalProperties":true,"type":["object","null"]},"replacement_address":{"additionalProperties":true,"type":["object","null"]},"save_mode":{"enum":["updated_in_place_unused","created_replacement_address_used","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"stale_base":{"additionalProperties":true,"type":["object","null"]}},"required":["save_mode","message_code","operation_key"],"type":"object"},"message":{"description":"The `save_mode`.","enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"type":"object"}}},"description":"The Ship From address is an old copy replaced by an edit (`blocked_superseded_historical_address`; `current_address` is the copy to use), or it is deleted, synced or redacted (`blocked_external_or_compliance`; `current_address` is the same address, or null when the profile has none). Not the usual error envelope: `success: false`, `address_save_result` and `message` (the `save_mode`); no `status` or `error`."},"422":{"$ref":"#/components/responses/MediaUploadValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a brand profile","tags":["Customer brand profiles"],"x-yoprint-docs":{"errors":[{"fix":"Pick a current billing address of the customer or a company location.","status":422,"when":"The address is not this customer's billing address or a company location (`error.code` `invalid_profile_address`)."},{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"`address_id`, `company_name` or `use_custom_logo` is missing, `media_id` is missing while `use_custom_logo` is true, or an id is not the team's. `error.code` is `validation_failed`."},{"fix":"For a replaced address, use `address_save_result.current_address.id`. A synced or redacted address can't be changed.","status":409,"when":"The address is not current: replaced by an edit (`address_save_result.save_mode` `blocked_superseded_historical_address`), or synced from another system or redacted (`blocked_external_or_compliance`). Not the usual error envelope: the body has `success: false`, `address_save_result` and `message`."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the id.","status":404,"when":"No customer with this id in the team. Deleted customers are found here, so this also works on a deleted customer. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_profile_primary","v1_public_async_upload_store","v1_public_customer_address_index"],"rules":["The Ship From address must be current: a deleted, replaced, synced or redacted address is refused with 409 (`address_save_result`).","It must be this customer's billing address or one of your company locations: anything else is refused with 422 `invalid_profile_address`.","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\").","Works on a deleted customer too."],"side_effects":["Attaches the uploaded logo file to the profile."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/profile/{id}":{"delete":{"description":"Deletes a brand profile. Deleting the primary profile does not make another one primary. There is no restore operation on the public API.","operationId":"v1_public_customer_profile_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The brand profile's id (`id` from List a customer's brand profiles). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a brand profile","tags":["Customer brand profiles"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the ids.","status":404,"when":"Not a live profile of this customer. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_profile_store"],"rules":["Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."]}},"get":{"description":"Returns one live brand profile of the customer.","operationId":"v1_public_customer_profile_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The brand profile's id (`id` from List a customer's brand profiles). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a brand profile","tags":["Customer brand profiles"],"x-yoprint-docs":{"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_profile_update_patch"]}},"patch":{"description":"Changes the fields you send and returns the profile. Documents that use the profile show the change. The profile's Ship From address is checked on every update, whether you send `address_id` or not: if it is no longer current, or the profile has none, send a current one.\n\n`PUT` and `PATCH` check the same fields.","operationId":"v1_public_customer_profile_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The brand profile's id (`id` from List a customer's brand profiles). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel"},"schema":{"additionalProperties":false,"properties":{"address_id":{"description":"A new Ship From address. Same rules as on create.","type":"string"},"company_name":{"type":"string"},"email":{"description":"The brand profile's email address, printed on documents.","type":"string"},"media_id":{"description":"Required when `use_custom_logo` is true. An uploaded file not attached to anything yet; an attached one is silently not used.","type":"string"},"phone":{"description":"The brand profile's phone number, printed on documents.","type":"string"},"use_custom_logo":{"type":"boolean"},"website":{"description":"The website address.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":"wiZMcKAjsniFSE","city":"Springfield","copied_from_address_id":"wiZMcKAjsniFSE","country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"ozf36EpTUF1pLm","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Sales office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"message_code":"blocked_superseded_historical_address","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_superseded_historical_address","stale_base":null},"message":"blocked_superseded_historical_address","success":false},"schema":{"additionalProperties":false,"properties":{"address_save_result":{"additionalProperties":true,"description":"What the save did.","properties":{"current_address":{"additionalProperties":true,"description":"On a refusal: the address to edit instead.","type":["object","null"]},"message_code":{"description":"The message code for what happened, identical to `save_mode`.","type":"string"},"operation_key":{"description":"The key you sent, or one YoPrint made.","type":["string","null"]},"previous_address":{"additionalProperties":true,"type":["object","null"]},"replacement_address":{"additionalProperties":true,"type":["object","null"]},"save_mode":{"enum":["updated_in_place_unused","created_replacement_address_used","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"stale_base":{"additionalProperties":true,"type":["object","null"]}},"required":["save_mode","message_code","operation_key"],"type":"object"},"message":{"description":"The `save_mode`.","enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"type":"object"}}},"description":"The Ship From address is an old copy replaced by an edit (`blocked_superseded_historical_address`; `current_address` is the copy to use), or it is deleted, synced or redacted (`blocked_external_or_compliance`; `current_address` is the same address, or null when the profile has none). Not the usual error envelope: `success: false`, `address_save_result` and `message` (the `save_mode`); no `status` or `error`."},"422":{"$ref":"#/components/responses/MediaUploadValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a brand profile (same as PUT)","tags":["Customer brand profiles"],"x-yoprint-docs":{"errors":[{"fix":"Send `address_id` with a current address.","status":409,"when":"The Ship From address, sent or saved, is deleted, replaced, synced or redacted, or the profile has none and you sent no `address_id` (`blocked_external_or_compliance` with `current_address: null`). Not the usual error envelope: `success: false`, `address_save_result`, `message`."},{"fix":"Pick a valid Ship From address.","status":422,"when":"The address is not this customer's billing address or a company location (`error.code` `invalid_profile_address`)."},{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"A field has the wrong type, `media_id` is missing while `use_custom_logo` is true, or an id is not the team's. `error.code` is `validation_failed`."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the ids.","status":404,"when":"No live brand profile with this id on the customer, or no customer with this id. `error.code` is null and `error.message` names the record type."}],"group":"Customers","notes":["A new logo (`media_id`) is added to the profile's files; the newest one is the `logo`."],"patch":"same_as_put","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_address_update"],"rules":["After a customer address used here is edited, it is replaced by a new address (see Update a customer address) and this check refuses the old one with 409. Send the new `address_id`.","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."]}},"put":{"description":"Changes the fields you send and returns the profile. Documents that use the profile show the change. The profile's Ship From address is checked on every update, whether you send `address_id` or not: if it is no longer current, or the profile has none, send a current one.\n\n`PUT` and `PATCH` check the same fields.","operationId":"v1_public_customer_profile_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The brand profile's id (`id` from List a customer's brand profiles). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel"},"schema":{"additionalProperties":false,"properties":{"address_id":{"description":"A new Ship From address. Same rules as on create.","type":"string"},"company_name":{"type":"string"},"email":{"description":"The brand profile's email address, printed on documents.","type":"string"},"media_id":{"description":"Required when `use_custom_logo` is true. An uploaded file not attached to anything yet; an attached one is silently not used.","type":"string"},"phone":{"description":"The brand profile's phone number, printed on documents.","type":"string"},"use_custom_logo":{"type":"boolean"},"website":{"description":"The website address.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":"wiZMcKAjsniFSE","city":"Springfield","copied_from_address_id":"wiZMcKAjsniFSE","country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"ozf36EpTUF1pLm","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Sales office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"message_code":"blocked_superseded_historical_address","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_superseded_historical_address","stale_base":null},"message":"blocked_superseded_historical_address","success":false},"schema":{"additionalProperties":false,"properties":{"address_save_result":{"additionalProperties":true,"description":"What the save did.","properties":{"current_address":{"additionalProperties":true,"description":"On a refusal: the address to edit instead.","type":["object","null"]},"message_code":{"description":"The message code for what happened, identical to `save_mode`.","type":"string"},"operation_key":{"description":"The key you sent, or one YoPrint made.","type":["string","null"]},"previous_address":{"additionalProperties":true,"type":["object","null"]},"replacement_address":{"additionalProperties":true,"type":["object","null"]},"save_mode":{"enum":["updated_in_place_unused","created_replacement_address_used","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"stale_base":{"additionalProperties":true,"type":["object","null"]}},"required":["save_mode","message_code","operation_key"],"type":"object"},"message":{"description":"The `save_mode`.","enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"type":"object"}}},"description":"The Ship From address is an old copy replaced by an edit (`blocked_superseded_historical_address`; `current_address` is the copy to use), or it is deleted, synced or redacted (`blocked_external_or_compliance`; `current_address` is the same address, or null when the profile has none). Not the usual error envelope: `success: false`, `address_save_result` and `message` (the `save_mode`); no `status` or `error`."},"422":{"$ref":"#/components/responses/MediaUploadValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a brand profile","tags":["Customer brand profiles"],"x-yoprint-docs":{"errors":[{"fix":"Send `address_id` with a current address.","status":409,"when":"The Ship From address, sent or saved, is deleted, replaced, synced or redacted, or the profile has none and you sent no `address_id` (`blocked_external_or_compliance` with `current_address: null`). Not the usual error envelope: `success: false`, `address_save_result`, `message`."},{"fix":"Pick a valid Ship From address.","status":422,"when":"The address is not this customer's billing address or a company location (`error.code` `invalid_profile_address`)."},{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"A field has the wrong type, `media_id` is missing while `use_custom_logo` is true, or an id is not the team's. `error.code` is `validation_failed`."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the ids.","status":404,"when":"No live brand profile with this id on the customer, or no customer with this id. `error.code` is null and `error.message` names the record type."}],"group":"Customers","notes":["A new logo (`media_id`) is added to the profile's files; the newest one is the `logo`."],"patch":"same_as_put","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_address_update"],"rules":["After a customer address used here is edited, it is replaced by a new address (see Update a customer address) and this check refuses the old one with 409. Send the new `address_id`.","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/profile/{id}/primary":{"patch":{"description":"Makes this profile the customer's primary brand profile, the one new sales orders and quotes use. Returns the profile.","operationId":"v1_public_customer_profile_primary","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The brand profile's id (`id` from List a customer's brand profiles). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":"wiZMcKAjsniFSE","city":"Springfield","copied_from_address_id":"wiZMcKAjsniFSE","country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"ozf36EpTUF1pLm","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Sales office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"message_code":"blocked_superseded_historical_address","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_superseded_historical_address","stale_base":null},"message":"blocked_superseded_historical_address","success":false},"schema":{"additionalProperties":false,"properties":{"address_save_result":{"additionalProperties":true,"description":"What the save did.","properties":{"current_address":{"additionalProperties":true,"description":"On a refusal: the address to edit instead.","type":["object","null"]},"message_code":{"description":"The message code for what happened, identical to `save_mode`.","type":"string"},"operation_key":{"description":"The key you sent, or one YoPrint made.","type":["string","null"]},"previous_address":{"additionalProperties":true,"type":["object","null"]},"replacement_address":{"additionalProperties":true,"type":["object","null"]},"save_mode":{"enum":["updated_in_place_unused","created_replacement_address_used","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"stale_base":{"additionalProperties":true,"type":["object","null"]}},"required":["save_mode","message_code","operation_key"],"type":"object"},"message":{"description":"The `save_mode`.","enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"type":"object"}}},"description":"The Ship From address is an old copy replaced by an edit (`blocked_superseded_historical_address`; `current_address` is the copy to use), or it is deleted, synced or redacted (`blocked_external_or_compliance`; `current_address` is the same address, or null when the profile has none). Not the usual error envelope: `success: false`, `address_save_result` and `message` (the `save_mode`); no `status` or `error`."},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set the primary brand profile","tags":["Customer brand profiles"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Update the profile with a current `address_id`.","status":409,"when":"The Ship From address is deleted, replaced, synced or redacted. Not the usual error envelope: `success: false`, `address_save_result`, `message`."},{"fix":"Update the profile with a valid `address_id`.","status":422,"when":"The profile has no Ship From address, or its address is not allowed for brand profiles (`error.code` `invalid_profile_address`)."},{"fix":"Ask a team owner to give your role Manage Customers.","status":403,"when":"Your role has no Manage Customers permission. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the ids.","status":404,"when":"No live brand profile with this id on the customer. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission (\"Manage All\" or \"Manage Assigned to User\"). Whether the customer is assigned to you is not checked.","related":["v1_public_customer_profile_index"],"rules":["The profile's Ship From address must be current and valid for brand profiles (409 or 422 otherwise). Update the profile first if it is not.","Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/recount":{"patch":{"description":"Recalculates the customer's `last_ordered_date`, `ordered_amount`, `unpaid_amount`, `deposit_due_amount`, `overdue_amount` and `quote_amount` from its orders now, and returns the customer. YoPrint keeps these up to date as orders change; use this when a total looks out of date.","operationId":"v1_public_customer_recount","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_warning":null,"addresses":[{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":true},{"address1":"100 Example Street","address2":"Dock 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"swtHxyIfOvF62K","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Warehouse","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"shipping","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false}],"assigned_users":[{"avatar_url":"https://example.com/avatars/alex.png","id":"lOURnovd3hkIQI","name":"Alex Rivera"}],"contacts":[{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"V4keXwwxMQyXw7","default_receive_sms":false,"email":"alex@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Alex","id":"cBoKHftCid2dDD","is_external":false,"is_primary":true,"last_name":"Rivera","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"}],"created_at":"2026-10-01T09:00:00+00:00","customer_portal_enabled":null,"customer_portal_id":"HWYGf6vzKsjwpS","customer_portal_id_override":null,"customer_portal_link":null,"customer_portal_payment_option":null,"customer_profiles":[{"address":{"address1":"100 Example Street","address2":"Suite 200","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","customer_id":"V4keXwwxMQyXw7","external_type":null,"hold_stock":false,"id":"KKhhlVobndGXEj","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":true,"label":"Head office","nexus":false,"note":null,"owner_id":"V4keXwwxMQyXw7","owner_type":"customer","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"billing","source":"customer","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"address_id":"KKhhlVobndGXEj","company_name":"Northwind Apparel","customer_id":"V4keXwwxMQyXw7","email":"alex@example.com","id":"Sd836BkLvOWpuP","is_primary":true,"logo":null,"phone":"+1 201 555 0123","trashed":false,"use_custom_logo":false,"website":"https://example.com"}],"default_payment_term_id":null,"default_pricing_group_id":null,"default_warehouse_id":null,"deposit_due_amount":0,"display_customer_portal_id":"HWYGf6vzKsjwpS","external_type":null,"has_customer_portal_id_override":false,"held_credit":0,"hide":false,"id":"V4keXwwxMQyXw7","internal_notes":null,"is_editable":true,"is_external":false,"is_system":false,"last_ordered_date":"2026-10-28T08:00:00+00:00","media":[{"collection":"tax_exemption","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"customer_id":"V4keXwwxMQyXw7","file_name":"resale-certificate.pdf","id":"4GR9C3ZTMYtda5","is_image":false,"mime_type":"application/pdf","name":"Resale certificate 2026.pdf","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/4GR9C3ZTMYtda5/download","view_url":"https://example.com/media/4GR9C3ZTMYtda5/view"}],"name":"Northwind Apparel","ordered_amount":125000,"overdue_amount":0,"pdf":{"invoice_statement":"https://example.com/pdf/customer_invoice_statement/V4keXwwxMQyXw7"},"quote_amount":0,"resale_number":null,"shopify_compliance_deletion":null,"system_type":null,"tags":[{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"}],"tax_exempt":false,"third_party_billing_default":"none","trashed":false,"unpaid_amount":25000,"updated_at":"2026-11-01T09:00:00+00:00","vat_number":null,"wallet_currency":{"default":true,"id":"icHZvqV1nkXRcA","iso":"USD","name":"US Dollar","symbol":"$","trashed":false},"wallet_fund":50000,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"account_warning":{"additionalProperties":false,"description":"Why YoPrint shows a warning next to the customer's name. Null when there is nothing to warn about.","properties":{"open_dispute":{"additionalProperties":false,"description":"The customer's payments under a dispute that is open or under review; null when there is none.","properties":{"count":{"description":"How many payments are disputed.","type":"integer"},"payment_amount":{"description":"The total of the disputed payments, each counted once. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]}},"required":["payment_amount","count"],"type":["object","null"]},"owed_amount":{"description":"What the customer owes back because `wallet_fund` is negative, as a positive amount; null when it is not negative. Thousandths, an older encoding: `125000` is 125.00. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]}},"required":["owed_amount","open_dispute"],"type":["object","null"]},"addresses":{"description":"Billing and shipping addresses that are not deleted, old copies replaced by an edit included (`is_current_source: false`).","items":{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},"type":"array"},"assigned_users":{"description":"The users assigned to the customer. Unlike List the users assigned to a customer, people who have left the team stay in this list.","items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","avatar_url","name"],"type":"object"},"type":"array"},"contacts":{"description":"Every contact, deleted ones included (`trashed`).","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"customer_portal_enabled":{"description":"Whether the customer's contacts can open the Customer Portal (Portal settings > Customer portal in YoPrint). `false`: the portal is off for this customer. `true`, or null (never set), means on.","type":["boolean","null"]},"customer_portal_id":{"description":"The id used in the customer's portal address. Null for Shopify customers.","type":["string","null"]},"customer_portal_id_override":{"type":["string","null"]},"customer_portal_link":{"description":"Always null: YoPrint no longer returns a portal sign-in link for the customer. The field stays for older integrations.","type":"null"},"customer_portal_payment_option":{"description":"Whether the customer can pay online in the portal. Null follows the team setting (and is always null for Shopify customers).","enum":["ENABLED","DISABLED",null],"type":["string","null"]},"customer_profiles":{"description":"Brand profiles.","items":{"additionalProperties":true,"properties":{"address":{"anyOf":[{"additionalProperties":true,"properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":"object"},{"type":"null"}],"description":"The Ship From address (an address, as in Customer addresses, without `used_by_active_profile`), or null."},"address_id":{"description":"The Ship From address, or null for a profile that has none.","type":["string","null"]},"company_name":{"type":["string","null"]},"customer_id":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"string"},"is_primary":{"description":"New sales orders and quotes for the customer use the primary profile.","type":"boolean"},"logo":{"anyOf":[{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},{"type":"null"}],"description":"The newest logo file (a file, as in Customer files), or null."},"phone":{"type":["string","null"]},"trashed":{"type":"boolean"},"use_custom_logo":{"type":"boolean"},"website":{"type":["string","null"]}},"required":["id","customer_id","address_id","company_name","use_custom_logo","is_primary","trashed"],"type":"object"},"type":"array"},"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"default_warehouse_id":{"type":["string","null"]},"deposit_due_amount":{"description":"Deposits still due. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"display_customer_portal_id":{"description":"The Customer Portal ID shown to people: the override when set, otherwise `customer_portal_id`. `-` for Shopify customers.","type":"string"},"external_type":{"description":"`shopify` for customers synced from Shopify.","type":["string","null"]},"has_customer_portal_id_override":{"type":"boolean"},"held_credit":{"description":"The part of `wallet_fund` held while a payment is under an open dispute or a provider review: it can't be applied to orders or taken out until the hold ends. Never more than `wallet_fund`; 0 when `wallet_fund` is 0 or negative. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"hide":{"description":"True when the customer is archived.","type":"boolean"},"id":{"description":"The customer id. Use it in paths and as `customer_id` on sales orders and quotes.","type":"string"},"internal_notes":{"type":["string","null"]},"is_editable":{"description":"False for Shopify and system customers: they can't be changed through this API.","type":"boolean"},"is_external":{"type":"boolean"},"is_system":{"type":"boolean"},"last_ordered_date":{"description":"The issue date of the customer's latest published sales order. Null when it has none.","format":"date-time","type":["string","null"]},"media":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"name":{"description":"Null for a customer created by upsert without a name.","type":["string","null"]},"ordered_amount":{"description":"Total of the customer's published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"overdue_amount":{"description":"Unpaid amounts past their payment due date. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"pdf":{"additionalProperties":false,"properties":{"invoice_statement":{"description":"A link that downloads the customer's invoice statement PDF. Its token opens only this customer's statement and stops working 9,000 hours (about a year) after the answer was made. Anyone with the link can download the statement: don't share it.","type":"string"}},"required":["invoice_statement"],"type":"object"},"quote_amount":{"description":"Total of open quotes. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"resale_number":{"type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"type":["object","null"]},"system_type":{"type":["string","null"]},"tags":{"items":{"additionalProperties":false,"properties":{"color_hex":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"tax_exempt":{"type":"boolean"},"third_party_billing_default":{"description":"How a shipping label for this customer is billed by default. `default_carrier_account`: YoPrint's label and rate dialogs start on the customer's default carrier account (third-party billing). `none`: they start with no third-party billing.","enum":["none","default_carrier_account"],"type":"string"},"trashed":{"description":"True when the customer is deleted.","type":"boolean"},"unpaid_amount":{"description":"What the customer still owes on published sales orders. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"updated_at":{"format":"date-time","type":"string"},"vat_number":{"description":"The customer's tax number (shown as Tax number in YoPrint).","type":["string","null"]},"wallet_currency":{"additionalProperties":false,"description":"The team's default currency, the one `wallet_fund` is in. `iso` is its code.","properties":{"default":{"type":"boolean"},"id":{"type":"string"},"iso":{"description":"The ISO 4217 code, such as `USD`.","type":["string","null"]},"name":{"type":["string","null"]},"symbol":{"type":["string","null"]},"trashed":{"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"wallet_fund":{"description":"Customer credit balance. Negative when the customer owes credit back, for example after a refund of a payment whose credit was already spent. Thousandths, an older encoding: `125000` is 125.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"website":{"type":["string","null"]}},"required":["id","name","tax_exempt","trashed","hide","is_external","is_system","is_editable","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Recalculate a customer's totals","tags":["Customers"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Ask for Manage Customers \"Manage All\", or to be assigned to the customer.","status":403,"when":"Your role can't change this customer: it has no Manage Customers permission, or it manages only customers assigned to you and this one is not. This 403 has a short body, `{\"message\": \"No Permission to update Customer\"}`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the id. Find deleted customers with the `trashed_only` filter and restore them first.","status":404,"when":"No live customer with this id in the team: deleted customers are not found here. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission: \"Manage All\" for any customer, or \"Manage Assigned to User\" for customers assigned to you.","related":["v1_public_customer_show"],"rules":["Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/restore":{"patch":{"description":"Brings back a deleted customer. Answers `success: true` with `data: null`; read the customer to see it. Restoring a customer that is not deleted also succeeds and changes nothing.","operationId":"v1_public_customer_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a deleted customer","tags":["Customers"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Ask for Manage Customers \"Manage All\", or to be assigned to the customer.","status":403,"when":"Your role can't change this customer: it has no Manage Customers permission, or it manages only customers assigned to you and this one is not. This 403 has a short body, `{\"message\": \"No Permission to update Customer\"}`."},{"fix":"Change Shopify customers in Shopify. System customers cannot be changed.","status":422,"when":"The customer comes from Shopify, or is a system customer (`error.code` `validation_error`, with the reason in `error.message`)."},{"fix":"Check the id.","status":404,"when":"No customer with this id in the team, deleted or not. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission: \"Manage All\" for any customer, or \"Manage Assigned to User\" for customers assigned to you.","related":["v1_public_customer_destroy","v1_public_customer_show"],"rules":["Customers synced from Shopify are read-only here: changes are refused with 422 `validation_error` \"External customers are read-only. Manage changes from Shopify.\" System customers (`is_system: true`) are refused the same way (\"System customer cannot be modified or deleted.\")."]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/tag":{"get":{"description":"Lists the tags on the customer, each with `id`, `name` and `color_hex`.","operationId":"v1_public_customer_tag_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"color_hex":{"description":"Such as `#2563EB`. Null for a tag saved without a color.","type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a customer's tags","tags":["Customers"],"x-yoprint-docs":{"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_tag_attach","v1_public_tag_index"]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/tag/attach":{"put":{"description":"Puts one of your team's tags on the customer and returns the customer's tags. Tagging a customer twice with the same tag changes nothing. Create tags with Create a tag.","operationId":"v1_public_customer_tag_attach","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"id":"zzVW0sylTIm6oo"},"schema":{"additionalProperties":false,"properties":{"id":{"description":"The tag id.","type":"string"}},"required":["id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"Every tag on the customer after the change.","items":{"additionalProperties":false,"properties":{"color_hex":{"description":"Such as `#2563EB`. Null for a tag saved without a color.","type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Tag a customer","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"List tags to find the id.","status":404,"when":"No tag, or no live customer, with this id in the team, or `id` is missing. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_tag_detach","v1_public_tag_store"]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/tag/detach":{"put":{"description":"Takes one tag off the customer and returns the customer's tags. The tag itself stays.","operationId":"v1_public_customer_tag_detach","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"id":"zzVW0sylTIm6oo"},"schema":{"additionalProperties":false,"properties":{"id":{"description":"The tag id.","type":"string"}},"required":["id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[],"status":200,"success":true},"schema":{"properties":{"data":{"description":"Every tag left on the customer.","items":{"additionalProperties":false,"properties":{"color_hex":{"description":"Such as `#2563EB`. Null for a tag saved without a color.","type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove a tag from a customer","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Check the ids.","status":404,"when":"No tag, or no live customer, with this id in the team. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_tag_detach_all"]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/tag/detach_all":{"patch":{"description":"Takes all tags off the customer and answers with an empty list. The tags themselves stay.","operationId":"v1_public_customer_tag_detach_all","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[],"status":200,"success":true},"schema":{"properties":{"data":{"description":"Always an empty list.","items":{"additionalProperties":false,"properties":{"color_hex":{"description":"Such as `#2563EB`. Null for a tag saved without a color.","type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"maxItems":0,"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove every tag from a customer","tags":["Customers"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Check the id. Find deleted customers with the `trashed_only` filter and restore them first.","status":404,"when":"No live customer with this id in the team: deleted customers are not found here. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_tag_attach"]}}},"/v1/api/store/{team_slug}/customer/{hash_id}/token_exchange":{"patch":{"description":"**Internal.** Built for YoPrint's own apps, not for integrations. Don't build on it.\n\nThis is a credential: don't log or share it. Returns `auth_token`, a sign-in token that opens the Customer Portal as this customer. Built for YoPrint's web app (\"view as customer\").","operationId":"v1_public_customer_token_exchange","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"auth_token":"CUSTOMER_PORTAL_TOKEN"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"auth_token":{"description":"This is a credential: don't log or share it. A sign-in token for the Customer Portal.","type":"string"}},"required":["auth_token"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a customer portal sign-in token","tags":["Customers"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Check the id.","status":500,"when":"No live customer with this id in the team; a deleted customer answers the same. This route answers HTTP 500 with `error.code` `invalid` and `error.message` \"Invalid Token.\"."},{"fix":"Ask for Manage Customers \"Manage All\", or to be assigned to the customer.","status":403,"when":"Your role has no Manage Customers permission, or it manages only customers assigned to you and this one is not. This 403 has a short body, `{\"message\": \"You do not have permission to view customer\"}`."}],"group":"Customers","notes":["The token opens the portal even while the Customer Portal is off for the customer (`customer_portal_enabled: false`)."],"permission":"Needs the Manage Customers permission. At \"Manage Assigned to User\" only customers assigned to you are allowed; other customers answer 403.","related":["v1_public_customer_show"],"status":"internal"},"x-internal":true}},"/v1/api/store/{team_slug}/customer/{id}/assign":{"get":{"description":"Lists the team members assigned to the customer. People who have left the team are left out. Members whose role has Manage Customers at \"Manage Assigned to User\" list and change only the customers they are assigned to.","operationId":"v1_public_customer_assign_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"avatar_url":"https://example.com/avatars/alex.png","id":"lOURnovd3hkIQI","name":"Alex Rivera"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"id":{"description":"The user id.","type":"string"},"name":{"type":["string","null"]}},"required":["id","name"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the users assigned to a customer","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Check the id. Find deleted customers with the `trashed_only` filter and restore them first.","status":404,"when":"No live customer with this id in the team: deleted customers are not found here. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Any member of the team.","related":["v1_public_customer_assign_update"]}},"put":{"description":"Adds a team member to the customer's assigned users (`action: assign`) or removes one (`action: unassign`), and returns the assigned users. Assigning someone already assigned changes nothing.","operationId":"v1_public_customer_assign_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The customer's id (`id` from List customers or Create a customer). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"action":"assign","user_id":"lOURnovd3hkIQI"},"schema":{"additionalProperties":false,"properties":{"action":{"enum":["assign","unassign"],"type":"string"},"user_id":{"description":"The user's id. For `assign` it must be a member of your team. For `unassign`, someone who is not assigned (or an id that matches nobody) changes nothing.","type":"string"}},"required":["action","user_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"avatar_url":"https://example.com/avatars/alex.png","id":"lOURnovd3hkIQI","name":"Alex Rivera"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"id":{"description":"The user id.","type":"string"},"name":{"type":["string","null"]}},"required":["id","name"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Assign or unassign a user on a customer","tags":["Customers"],"x-yoprint-docs":{"errors":[{"fix":"Send both fields.","status":422,"when":"`action` is not `assign` or `unassign`, or `user_id` is missing or not a valid id. `error.code` is `validation_failed`."},{"fix":"Use an id from List users.","status":422,"when":"`action` is `assign` and `user_id` is not a member of the team (`error.fields.user_id`: \"The user must be a member of this team. Use an id from the team's user list.\")."},{"fix":"Ask for Manage Customers \"Manage All\", or to be assigned to the customer.","status":403,"when":"Your role can't change this customer: it has no Manage Customers permission, or it manages only customers assigned to you and this one is not. This 403 has a short body, `{\"message\": \"No Permission to update Customer\"}`."},{"fix":"Check the id. Find deleted customers with the `trashed_only` filter and restore them first.","status":404,"when":"No live customer with this id in the team: deleted customers are not found here. `error.code` is null and `error.message` names the record type."}],"group":"Customers","permission":"Needs the Manage Customers permission: \"Manage All\" for any customer, or \"Manage Assigned to User\" for customers assigned to you.","related":["v1_public_customer_assign_index","v1_public_user_index"],"rules":["System customers can't be changed (422).","`assign` needs a member of the team. `unassign` for someone who is not assigned changes nothing and still answers 200 with the list."]}}},"/v1/api/store/{team_slug}/data_export":{"get":{"description":"Lists your team's exports, newest first, 15 per page: everyone's, of every type and status, including exports whose file has expired. This is the Download Center's history.\n\nUse `page` to read further. The page size is fixed, and there are no filters.","operationId":"v1_public_data_export_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The page to read, from 1. Each page holds 15 exports.","in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"config":{"date_field":"issue_date","end_date":"2026-10-31T23:59:59.999Z","start_date":"2026-10-01T00:00:00Z"},"created_at":"2026-11-03T09:30:00+00:00","created_by":1001,"creator":{"email":"alex@example.com","id":1001,"name":"Alex Rivera"},"error_code":null,"expires_at":"2026-11-06T09:30:40+00:00","file_size":482113,"id":"G59hl28azOL22k","progress":{"completed":1250,"total":1250},"status":"ready","type":"sales_order_list","updated_at":"2026-11-03T09:30:40+00:00"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":15,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"config":{"description":"What you asked for: the dates (and `date_field`) as you sent them, and the `columns` you chose, without repeats, with `schema_version`. Null for customer and product exports sent without `columns`.","properties":{"columns":{"description":"Only when you chose columns.","items":{"type":"string"},"type":"array"},"date_field":{"description":"Sales order exports only.","type":"string"},"end_date":{"type":"string"},"schema_version":{"description":"Only when you chose columns.","type":"integer"},"start_date":{"type":"string"}},"type":["object","null"]},"created_at":{"format":"date-time","type":"string"},"created_by":{"description":"A plain number for the person who created it. It is not a hash id and no operation takes it; show `creator.name` instead.","type":["integer","null"]},"creator":{"additionalProperties":true,"description":"The person who created it; null if their account was deleted. More of their account fields may appear; rely only on these.","properties":{"email":{"type":"string"},"id":{"description":"The same plain number as `created_by`, not a hash id.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]},"error_code":{"description":"Why it failed. `export_generation_failed`: the file could not be built; create a new export. `export_attempt_expired`: it did not finish in time. `export_queue_failed`: it could not be queued. Null unless `status` is `failed`.","enum":["export_generation_failed","export_attempt_expired","export_queue_failed",null],"type":["string","null"]},"expires_at":{"description":"When the download stops working: 3 days after the export became ready. The file is then deleted; the export stays in the list but can't be downloaded.","format":"date-time","type":["string","null"]},"file_size":{"description":"File size in bytes, once ready.","type":["integer","null"]},"id":{"description":"The export id. Use it to poll and to download.","type":"string"},"progress":{"properties":{"completed":{"description":"Rows written so far, not counting the header row. Updated every 500 rows; product exports update only at the end.","type":"integer"},"total":{"description":"Rows in the file, not counting the header row. Null until the export is ready: there is no total to show a percentage against while it runs.","type":["integer","null"]}},"required":["completed","total"],"type":"object"},"status":{"description":"`pending`: queued. `generating`: running. `ready`: the file can be downloaded. `failed`: see `error_code`.","enum":["pending","generating","ready","failed"],"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","config","status","created_at","updated_at","created_by","creator","progress","file_size","expires_at","error_code"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List data exports","tags":["Data exports"],"x-yoprint-docs":{"group":"Imports and exports","notes":["To wait for one export, poll `GET /v1/api/store/{team_slug}/data_export/{id}` instead of the list."],"permission":"Any member of the team.","related":["v1_public_data_export_show","v1_public_data_export_download"]}}},"/v1/api/store/{team_slug}/data_export/definitions":{"get":{"description":"Returns every export type with the columns you can ask for. Use the column `id`s in `columns` when you create an export or a preset.\n\nThe answer is an object keyed by export type. `date_range` says whether the type needs `start_date` and `end_date`. `date_fields` lists the values of `date_field`, which only the sales order export accepts; for other types it always says `issue_date` and can be ignored. It is the same for every team.","operationId":"v1_public_data_export_definitions","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"sales_order_list":{"columns":[{"id":"name","label":"Name"},{"id":"order_id","label":"Order Id"},{"id":"total","label":"Total"}],"date_fields":["issue_date","deposit_due","due_date","ship_due_date","cust_due_date","start_date"],"date_range":true,"schema_version":1},"simple_product_list":{"columns":[{"id":"title","label":"Title"},{"id":"brand","label":"Brand"},{"id":"price","label":"Price"},{"id":"status","label":"Sales Status"}],"date_fields":["issue_date"],"date_range":false,"schema_version":1}},"status":200,"success":true},"schema":{"properties":{"data":{"description":"One entry per export type, keyed by type.","properties":{"customer_list":{"properties":{"columns":{"description":"In the default order of the file.","items":{"properties":{"id":{"description":"Send this in `columns`.","type":"string"},"label":{"description":"The column's name in the web app.","type":"string"}},"required":["id","label"],"type":"object"},"type":"array"},"date_fields":{"description":"The values of `date_field`. Only the sales order export reads it; ignore it for the others.","items":{"type":"string"},"type":"array"},"date_range":{"description":"True when the export needs `start_date` and `end_date`.","type":"boolean"},"schema_version":{"description":"Version of the column list (1).","type":"integer"}},"required":["schema_version","date_range","date_fields","columns"],"type":"object"},"invoice_item_list":{"properties":{"columns":{"description":"In the default order of the file.","items":{"properties":{"id":{"description":"Send this in `columns`.","type":"string"},"label":{"description":"The column's name in the web app.","type":"string"}},"required":["id","label"],"type":"object"},"type":"array"},"date_fields":{"description":"The values of `date_field`. Only the sales order export reads it; ignore it for the others.","items":{"type":"string"},"type":"array"},"date_range":{"description":"True when the export needs `start_date` and `end_date`.","type":"boolean"},"schema_version":{"description":"Version of the column list (1).","type":"integer"}},"required":["schema_version","date_range","date_fields","columns"],"type":"object"},"invoice_list":{"properties":{"columns":{"description":"In the default order of the file.","items":{"properties":{"id":{"description":"Send this in `columns`.","type":"string"},"label":{"description":"The column's name in the web app.","type":"string"}},"required":["id","label"],"type":"object"},"type":"array"},"date_fields":{"description":"The values of `date_field`. Only the sales order export reads it; ignore it for the others.","items":{"type":"string"},"type":"array"},"date_range":{"description":"True when the export needs `start_date` and `end_date`.","type":"boolean"},"schema_version":{"description":"Version of the column list (1).","type":"integer"}},"required":["schema_version","date_range","date_fields","columns"],"type":"object"},"payment_list":{"properties":{"columns":{"description":"In the default order of the file.","items":{"properties":{"id":{"description":"Send this in `columns`.","type":"string"},"label":{"description":"The column's name in the web app.","type":"string"}},"required":["id","label"],"type":"object"},"type":"array"},"date_fields":{"description":"The values of `date_field`. Only the sales order export reads it; ignore it for the others.","items":{"type":"string"},"type":"array"},"date_range":{"description":"True when the export needs `start_date` and `end_date`.","type":"boolean"},"schema_version":{"description":"Version of the column list (1).","type":"integer"}},"required":["schema_version","date_range","date_fields","columns"],"type":"object"},"purchase_order_list":{"properties":{"columns":{"description":"In the default order of the file.","items":{"properties":{"id":{"description":"Send this in `columns`.","type":"string"},"label":{"description":"The column's name in the web app.","type":"string"}},"required":["id","label"],"type":"object"},"type":"array"},"date_fields":{"description":"The values of `date_field`. Only the sales order export reads it; ignore it for the others.","items":{"type":"string"},"type":"array"},"date_range":{"description":"True when the export needs `start_date` and `end_date`.","type":"boolean"},"schema_version":{"description":"Version of the column list (1).","type":"integer"}},"required":["schema_version","date_range","date_fields","columns"],"type":"object"},"sales_order_list":{"properties":{"columns":{"description":"In the default order of the file.","items":{"properties":{"id":{"description":"Send this in `columns`.","type":"string"},"label":{"description":"The column's name in the web app.","type":"string"}},"required":["id","label"],"type":"object"},"type":"array"},"date_fields":{"description":"The values of `date_field`. Only the sales order export reads it; ignore it for the others.","items":{"type":"string"},"type":"array"},"date_range":{"description":"True when the export needs `start_date` and `end_date`.","type":"boolean"},"schema_version":{"description":"Version of the column list (1).","type":"integer"}},"required":["schema_version","date_range","date_fields","columns"],"type":"object"},"simple_product_list":{"properties":{"columns":{"description":"In the default order of the file.","items":{"properties":{"id":{"description":"Send this in `columns`.","type":"string"},"label":{"description":"The column's name in the web app.","type":"string"}},"required":["id","label"],"type":"object"},"type":"array"},"date_fields":{"description":"The values of `date_field`. Only the sales order export reads it; ignore it for the others.","items":{"type":"string"},"type":"array"},"date_range":{"description":"True when the export needs `start_date` and `end_date`.","type":"boolean"},"schema_version":{"description":"Version of the column list (1).","type":"integer"}},"required":["schema_version","date_range","date_fields","columns"],"type":"object"},"tax_list":{"properties":{"columns":{"description":"In the default order of the file.","items":{"properties":{"id":{"description":"Send this in `columns`.","type":"string"},"label":{"description":"The column's name in the web app.","type":"string"}},"required":["id","label"],"type":"object"},"type":"array"},"date_fields":{"description":"The values of `date_field`. Only the sales order export reads it; ignore it for the others.","items":{"type":"string"},"type":"array"},"date_range":{"description":"True when the export needs `start_date` and `end_date`.","type":"boolean"},"schema_version":{"description":"Version of the column list (1).","type":"integer"}},"required":["schema_version","date_range","date_fields","columns"],"type":"object"},"variant_product_list":{"properties":{"columns":{"description":"In the default order of the file.","items":{"properties":{"id":{"description":"Send this in `columns`.","type":"string"},"label":{"description":"The column's name in the web app.","type":"string"}},"required":["id","label"],"type":"object"},"type":"array"},"date_fields":{"description":"The values of `date_field`. Only the sales order export reads it; ignore it for the others.","items":{"type":"string"},"type":"array"},"date_range":{"description":"True when the export needs `start_date` and `end_date`.","type":"boolean"},"schema_version":{"description":"Version of the column list (1).","type":"integer"}},"required":["schema_version","date_range","date_fields","columns"],"type":"object"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List export types and their columns","tags":["Data exports"],"x-yoprint-docs":{"group":"Imports and exports","notes":["The example is shortened; the real answer lists all nine types and every column."],"permission":"Any member of the team.","related":["v1_public_data_export_presets_store","v1_public_data_export_export_sales_order"]}}},"/v1/api/store/{team_slug}/data_export/export_customer":{"post":{"description":"Starts a CSV export of every customer on your team (deleted customers are left out). It runs in the background: the response is the new export with `status` `pending`.\n\nA customer with several addresses or contacts takes several rows: row 1 holds the first shipping address, first billing address and first contact, row 2 the second of each, and so on; every row repeats the customer's own columns. `id` is the customer's `id` (a hash id). `assigned_users` and `tags` are names separated by commas. `tax_exempt` and the `*_is_primary` columns are `TRUE` or `FALSE`. `last_ordered_date` is the issue date of the customer's latest order, as `YYYY-MM-DD` in UTC, not in your team's time zone. Deleted contacts are left out.\n\nSend no body for every column, or `columns` to choose them.","operationId":"v1_public_data_export_export_customer","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"columns":["id","name","contact_email","billing_city","tags"],"idempotency_key":"export-customer-list-1"},"schema":{"properties":{"columns":{"description":"The columns to include, in the order you want them in the file. Omit it for every column in the default order. Repeats are dropped.","items":{"enum":["id","name","website","internal_notes","tax_exempt","resale_number","tax_id","last_ordered_date","assigned_users","tags","shipping_label","shipping_address_1","shipping_address_2","shipping_city","shipping_state","shipping_state_code","shipping_postal_code","shipping_country","shipping_country_code","shipping_note","shipping_is_primary","billing_label","billing_address_1","billing_address_2","billing_city","billing_state","billing_state_code","billing_postal_code","billing_country","billing_country_code","billing_note","billing_is_primary","contact_label","contact_first_name","contact_last_name","contact_email","contact_phone","contact_fax","contact_is_primary"],"type":"string"},"minItems":1,"type":"array","uniqueItems":true},"idempotency_key":{"description":"Optional, a string of up to 100 characters. Send the same key to retry the same request safely: you get the export it created, and nothing new starts while that export is `pending`, `generating`, `ready`, or failed with `export_generation_failed`. If it failed with `export_queue_failed` or `export_attempt_expired`, the same key queues it again. Keys are shared by the whole team.","maxLength":100,"type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":{"config":{"columns":["id","name","contact_email","billing_city","tags"],"schema_version":1},"created_at":"2026-11-03T09:30:00+00:00","created_by":1001,"creator":{"email":"alex@example.com","id":1001,"name":"Alex Rivera"},"error_code":null,"expires_at":null,"file_size":null,"id":"G59hl28azOL22k","progress":{"completed":0,"total":null},"status":"pending","type":"customer_list","updated_at":"2026-11-03T09:30:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"config":{"description":"What you asked for: the dates (and `date_field`) as you sent them, and the `columns` you chose, without repeats, with `schema_version`. Null for customer and product exports sent without `columns`.","properties":{"columns":{"description":"Only when you chose columns.","items":{"type":"string"},"type":"array"},"date_field":{"description":"Sales order exports only.","type":"string"},"end_date":{"type":"string"},"schema_version":{"description":"Only when you chose columns.","type":"integer"},"start_date":{"type":"string"}},"type":["object","null"]},"created_at":{"format":"date-time","type":"string"},"created_by":{"description":"A plain number for the person who created it. It is not a hash id and no operation takes it; show `creator.name` instead.","type":["integer","null"]},"creator":{"additionalProperties":true,"description":"The person who created it; null if their account was deleted. More of their account fields may appear; rely only on these.","properties":{"email":{"type":"string"},"id":{"description":"The same plain number as `created_by`, not a hash id.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]},"error_code":{"description":"Why it failed. `export_generation_failed`: the file could not be built; create a new export. `export_attempt_expired`: it did not finish in time. `export_queue_failed`: it could not be queued. Null unless `status` is `failed`.","enum":["export_generation_failed","export_attempt_expired","export_queue_failed",null],"type":["string","null"]},"expires_at":{"description":"When the download stops working: 3 days after the export became ready. The file is then deleted; the export stays in the list but can't be downloaded.","format":"date-time","type":["string","null"]},"file_size":{"description":"File size in bytes, once ready.","type":["integer","null"]},"id":{"description":"The export id. Use it to poll and to download.","type":"string"},"progress":{"properties":{"completed":{"description":"Rows written so far, not counting the header row. Updated every 500 rows; product exports update only at the end.","type":"integer"},"total":{"description":"Rows in the file, not counting the header row. Null until the export is ready: there is no total to show a percentage against while it runs.","type":["integer","null"]}},"required":["completed","total"],"type":"object"},"status":{"description":"`pending`: queued. `generating`: running. `ready`: the file can be downloaded. `failed`: see `error_code`.","enum":["pending","generating","ready","failed"],"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","config","status","created_at","updated_at","created_by","creator","progress","file_size","expires_at","error_code"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"429":{"content":{"application/json":{"example":{"error":{"code":"export_capacity","message":"Your team already has several exports in progress. Please try again when one has finished."},"status":429,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Your team already has 3 exports pending or generating."},"503":{"content":{"application/json":{"example":{"error":{"code":"export_creation_paused","message":"Exports are paused for a few minutes while we update YoPrint. Try again shortly."},"status":503,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Exports are paused for a few minutes during a YoPrint update, or the export could not be queued (`export_queue_failed`, \"The export could not be queued. Try again.\").","headers":{"Retry-After":{"description":"Seconds to wait (120) when exports are paused.","schema":{"type":"integer"}}}}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Export all customers to CSV","tags":["Data exports"],"x-yoprint-docs":{"errors":[{"fix":"Use ids from the definitions operation, or omit `columns`.","status":422,"when":"A column id is unknown, `columns` is not a list, or it is empty (`invalid_export_request`, \"The selected export columns are invalid.\" or \"Select at least one export column.\")."},{"fix":"Send a string of up to 100 characters, or leave it out.","status":422,"when":"`idempotency_key` is not a string or is longer than 100 characters (`invalid_export_request`, \"The export request key is invalid.\")."},{"fix":"Poll the running export and download it instead, or wait until it finishes.","status":422,"when":"An export of this type is already pending or generating for your team (`duplicate_report`, \"There is already a report being generated. Please wait until the report is fully generated\")."},{"fix":"Use a new key for a new export.","status":422,"when":"The `idempotency_key` was used for a different export, or by another member (`invalid_export_request`, \"This request key was already used for a different export.\")."},{"fix":"Wait for one to finish, then try again.","status":429,"when":"Three exports are already pending or generating (`export_capacity`)."},{"fix":"When paused, wait the `Retry-After` seconds and send the request again. After a queue failure, send it again with the same `idempotency_key` to queue the same export.","status":503,"when":"Exports are paused during an update (`export_creation_paused`, with `Retry-After: 120`), even for a retry with the same key; or the export could not be queued (`export_queue_failed`, no `Retry-After`)."}],"group":"Imports and exports","notes":["The full flow: create the export, poll `GET /v1/api/store/{team_slug}/data_export/{id}` every few seconds until `status` is `ready` (or `failed`), then download the file with `GET /v1/api/store/{team_slug}/data_export/{id}/download` within 3 days.","Retrying with the same `idempotency_key` returns the same export and starts nothing new while it is `pending`, `generating`, `ready`, or failed with `export_generation_failed` (send a new key to try that one again). After `export_queue_failed` or `export_attempt_expired`, the same key queues the same export again, and the one-per-type (422 `duplicate_report`) and three-per-team (429 `export_capacity`) limits apply.","The file is CSV, UTF-8 with a byte order mark. Its first row holds the column ids, such as `order_id` (not the labels), in the order of `columns` or, without it, the default order. An export with no matching records has only that row."],"permission":"Any member of the team. Exports do not check the role: every member can export every type, including sales orders, invoices, payments and tax, even a member whose role can't see them in the web app.","related":["v1_public_data_export_show","v1_public_data_export_download","v1_public_data_export_definitions"],"rules":["One export of each type at a time for the whole team: while one is `pending` or `generating`, creating another of the same type is a 422 (`duplicate_report`).","At most 3 exports pending or generating per team, of any type. A fourth is a 429 (`export_capacity`).","`columns`, when sent, must be a non-empty list of column ids for this type. `GET /v1/api/store/{team_slug}/data_export/definitions` lists them with their labels.","`idempotency_key`, when sent, must be a string of at most 100 characters. Reusing a key with a different type, different settings or another person is a 422."],"side_effects":["Queues the export and returns it at once with `status` `pending`. The file is built in the background.","People with the Download Center open see it appear and update live. No email is sent.","The file is kept for 3 days after it is ready, then deleted. The export stays in the list as history."]}}},"/v1/api/store/{team_slug}/data_export/export_invoice":{"post":{"description":"Starts a CSV export of invoices, one row per invoice, with the order, customer, shipping address, totals and payments. It runs in the background: the response is the new export with `status` `pending`.\n\nThe range applies to the **order's issue date**, not the invoice's. Deleted invoices and draft or deleted orders are left out.","operationId":"v1_public_data_export_export_invoice","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-10-31T23:59:59.999Z","idempotency_key":"export-invoice-list-2026-10","start_date":"2026-10-01T00:00:00Z"},"schema":{"properties":{"columns":{"description":"The columns to include, in the order you want them in the file. Omit it for every column in the default order. Repeats are dropped.","items":{"enum":["order_id","order_name","order_status","order_issue_date","issue_date","order_creator","order_customer_in_hand_date","invoice_id","customer_email","customer_contact_name","customer_name","customer_tax_exempt","order_warehouse","shipping_label","shipping_address1","shipping_address2","shipping_city","shipping_state","shipping_state_code","shipping_country","shipping_country_code","shipping_postcode","jobs","discount","subtotal","total","delivery","tax","tax_percentage","paid_amount","balance_due","paid","last_payment_date"],"type":"string"},"minItems":1,"type":"array","uniqueItems":true},"end_date":{"description":"End of the range, inclusive, on or after `start_date`. A date alone means midnight UTC at its start, which leaves that day out, so send the last moment of the day: `2026-10-31T23:59:59.999Z`.","format":"date-time","type":"string"},"idempotency_key":{"description":"Optional, a string of up to 100 characters. Send the same key to retry the same request safely: you get the export it created, and nothing new starts while that export is `pending`, `generating`, `ready`, or failed with `export_generation_failed`. If it failed with `export_queue_failed` or `export_attempt_expired`, the same key queues it again. Keys are shared by the whole team.","maxLength":100,"type":"string"},"start_date":{"description":"Start of the range, inclusive: a date and time in UTC, such as `2026-10-01T00:00:00Z`. An offset (`2026-10-01T00:00:00-07:00`) is accepted and converted to UTC; a value with neither is read as UTC.","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"config":{"end_date":"2026-10-31T23:59:59.999Z","start_date":"2026-10-01T00:00:00Z"},"created_at":"2026-11-03T09:30:00+00:00","created_by":1001,"creator":{"email":"alex@example.com","id":1001,"name":"Alex Rivera"},"error_code":null,"expires_at":null,"file_size":null,"id":"G59hl28azOL22k","progress":{"completed":0,"total":null},"status":"pending","type":"invoice_list","updated_at":"2026-11-03T09:30:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"config":{"description":"What you asked for: the dates (and `date_field`) as you sent them, and the `columns` you chose, without repeats, with `schema_version`. Null for customer and product exports sent without `columns`.","properties":{"columns":{"description":"Only when you chose columns.","items":{"type":"string"},"type":"array"},"date_field":{"description":"Sales order exports only.","type":"string"},"end_date":{"type":"string"},"schema_version":{"description":"Only when you chose columns.","type":"integer"},"start_date":{"type":"string"}},"type":["object","null"]},"created_at":{"format":"date-time","type":"string"},"created_by":{"description":"A plain number for the person who created it. It is not a hash id and no operation takes it; show `creator.name` instead.","type":["integer","null"]},"creator":{"additionalProperties":true,"description":"The person who created it; null if their account was deleted. More of their account fields may appear; rely only on these.","properties":{"email":{"type":"string"},"id":{"description":"The same plain number as `created_by`, not a hash id.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]},"error_code":{"description":"Why it failed. `export_generation_failed`: the file could not be built; create a new export. `export_attempt_expired`: it did not finish in time. `export_queue_failed`: it could not be queued. Null unless `status` is `failed`.","enum":["export_generation_failed","export_attempt_expired","export_queue_failed",null],"type":["string","null"]},"expires_at":{"description":"When the download stops working: 3 days after the export became ready. The file is then deleted; the export stays in the list but can't be downloaded.","format":"date-time","type":["string","null"]},"file_size":{"description":"File size in bytes, once ready.","type":["integer","null"]},"id":{"description":"The export id. Use it to poll and to download.","type":"string"},"progress":{"properties":{"completed":{"description":"Rows written so far, not counting the header row. Updated every 500 rows; product exports update only at the end.","type":"integer"},"total":{"description":"Rows in the file, not counting the header row. Null until the export is ready: there is no total to show a percentage against while it runs.","type":["integer","null"]}},"required":["completed","total"],"type":"object"},"status":{"description":"`pending`: queued. `generating`: running. `ready`: the file can be downloaded. `failed`: see `error_code`.","enum":["pending","generating","ready","failed"],"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","config","status","created_at","updated_at","created_by","creator","progress","file_size","expires_at","error_code"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"429":{"content":{"application/json":{"example":{"error":{"code":"export_capacity","message":"Your team already has several exports in progress. Please try again when one has finished."},"status":429,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Your team already has 3 exports pending or generating."},"503":{"content":{"application/json":{"example":{"error":{"code":"export_creation_paused","message":"Exports are paused for a few minutes while we update YoPrint. Try again shortly."},"status":503,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Exports are paused for a few minutes during a YoPrint update, or the export could not be queued (`export_queue_failed`, \"The export could not be queued. Try again.\").","headers":{"Retry-After":{"description":"Seconds to wait (120) when exports are paused.","schema":{"type":"integer"}}}}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Export invoices in a date range to CSV","tags":["Data exports"],"x-yoprint-docs":{"errors":[{"fix":"Send both dates, with `end_date` on or after `start_date`, and for sales orders a `date_field` from the list.","status":422,"when":"Dates are missing, not dates, or out of order, or, for sales orders, `date_field` is missing or not one of the six (`invalid_export_request`, \"Choose valid, ordered export dates and a supported date field.\")."},{"fix":"Use ids from the definitions operation, or omit `columns`.","status":422,"when":"A column id is unknown, `columns` is not a list, or it is empty (`invalid_export_request`, \"The selected export columns are invalid.\" or \"Select at least one export column.\")."},{"fix":"Send a string of up to 100 characters, or leave it out.","status":422,"when":"`idempotency_key` is not a string or is longer than 100 characters (`invalid_export_request`, \"The export request key is invalid.\")."},{"fix":"Poll the running export and download it instead, or wait until it finishes.","status":422,"when":"An export of this type is already pending or generating for your team (`duplicate_report`, \"There is already a report being generated. Please wait until the report is fully generated\")."},{"fix":"Use a new key for a new export.","status":422,"when":"The `idempotency_key` was used for a different export, or by another member (`invalid_export_request`, \"This request key was already used for a different export.\")."},{"fix":"Wait for one to finish, then try again.","status":429,"when":"Three exports are already pending or generating (`export_capacity`)."},{"fix":"When paused, wait the `Retry-After` seconds and send the request again. After a queue failure, send it again with the same `idempotency_key` to queue the same export.","status":503,"when":"Exports are paused during an update (`export_creation_paused`, with `Retry-After: 120`), even for a retry with the same key; or the export could not be queued (`export_queue_failed`, no `Retry-After`)."}],"group":"Imports and exports","notes":["The range is inclusive at both ends and is compared in UTC, with times. To cover whole days in your team's time zone, convert its midnights to UTC, or send the offset: `2026-10-01T00:00:00-07:00` to `2026-10-31T23:59:59.999-07:00`. There is no maximum range.","Amounts in the file are decimal strings with 2 decimal places and no currency symbol, such as `125.00`. In invoice and tax exports (`invoice_list`, `tax_list`), `tax_percentage` is a percentage as a decimal string (`8.25`, `0`), empty when the invoice has no single tax rate (for example a fixed tax amount). In sales order, invoice, and tax exports (`sales_order_list`, `invoice_list`, `tax_list`), the `paid` column is `TRUE` or `FALSE`.","Dates in the file are `YYYY-MM-DD`, in your team's time zone.","The full flow: create the export, poll `GET /v1/api/store/{team_slug}/data_export/{id}` every few seconds until `status` is `ready` (or `failed`), then download the file with `GET /v1/api/store/{team_slug}/data_export/{id}/download` within 3 days.","Retrying with the same `idempotency_key` returns the same export and starts nothing new while it is `pending`, `generating`, `ready`, or failed with `export_generation_failed` (send a new key to try that one again). After `export_queue_failed` or `export_attempt_expired`, the same key queues the same export again, and the one-per-type (422 `duplicate_report`) and three-per-team (429 `export_capacity`) limits apply.","The file is CSV, UTF-8 with a byte order mark. Its first row holds the column ids, such as `order_id` (not the labels), in the order of `columns` or, without it, the default order. An export with no matching records has only that row."],"permission":"Any member of the team. Exports do not check the role: every member can export every type, including sales orders, invoices, payments and tax, even a member whose role can't see them in the web app.","related":["v1_public_data_export_show","v1_public_data_export_download","v1_public_data_export_definitions","v1_public_data_export_export_invoice_item","v1_public_data_export_export_tax"],"rules":["`start_date` and `end_date` are required, and `end_date` can't be before `start_date`. There is no maximum range. There is no `date_field`: the range is always the order's issue date.","One export of each type at a time for the whole team: while one is `pending` or `generating`, creating another of the same type is a 422 (`duplicate_report`).","At most 3 exports pending or generating per team, of any type. A fourth is a 429 (`export_capacity`).","`columns`, when sent, must be a non-empty list of column ids for this type. `GET /v1/api/store/{team_slug}/data_export/definitions` lists them with their labels.","`idempotency_key`, when sent, must be a string of at most 100 characters. Reusing a key with a different type, different settings or another person is a 422."],"side_effects":["Queues the export and returns it at once with `status` `pending`. The file is built in the background.","People with the Download Center open see it appear and update live. No email is sent.","The file is kept for 3 days after it is ready, then deleted. The export stays in the list as history."]}}},"/v1/api/store/{team_slug}/data_export/export_invoice_item":{"post":{"description":"Starts a CSV export with one row per invoice line item: the order, invoice, job, product, services, quantity and totals. It runs in the background: the response is the new export with `status` `pending`.\n\nAs with the invoice export, the range applies to the **order's issue date**, and deleted invoices and draft or deleted orders are left out. `product_cost`, `product_total`, and `service_total` have 3 decimal places. `subtotal` and `total` have 2 decimal places, and `total` always matches `subtotal` because line items do not include tax or discounts. `quantity` is a plain number such as `24`. `status` repeats `order_status`.","operationId":"v1_public_data_export_export_invoice_item","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-10-31T23:59:59.999Z","idempotency_key":"export-invoice-item-list-2026-10","start_date":"2026-10-01T00:00:00Z"},"schema":{"properties":{"columns":{"description":"The columns to include, in the order you want them in the file. Omit it for every column in the default order. Repeats are dropped.","items":{"enum":["order_id","order_name","order_status","order_date","order_creator","order_warehouse","invoice_id","status","job_name","services","product_type","product_name","product_cost","product_total","service_total","quantity","subtotal","total"],"type":"string"},"minItems":1,"type":"array","uniqueItems":true},"end_date":{"description":"End of the range, inclusive, on or after `start_date`. A date alone means midnight UTC at its start, which leaves that day out, so send the last moment of the day: `2026-10-31T23:59:59.999Z`.","format":"date-time","type":"string"},"idempotency_key":{"description":"Optional, a string of up to 100 characters. Send the same key to retry the same request safely: you get the export it created, and nothing new starts while that export is `pending`, `generating`, `ready`, or failed with `export_generation_failed`. If it failed with `export_queue_failed` or `export_attempt_expired`, the same key queues it again. Keys are shared by the whole team.","maxLength":100,"type":"string"},"start_date":{"description":"Start of the range, inclusive: a date and time in UTC, such as `2026-10-01T00:00:00Z`. An offset (`2026-10-01T00:00:00-07:00`) is accepted and converted to UTC; a value with neither is read as UTC.","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"config":{"end_date":"2026-10-31T23:59:59.999Z","start_date":"2026-10-01T00:00:00Z"},"created_at":"2026-11-03T09:30:00+00:00","created_by":1001,"creator":{"email":"alex@example.com","id":1001,"name":"Alex Rivera"},"error_code":null,"expires_at":null,"file_size":null,"id":"G59hl28azOL22k","progress":{"completed":0,"total":null},"status":"pending","type":"invoice_item_list","updated_at":"2026-11-03T09:30:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"config":{"description":"What you asked for: the dates (and `date_field`) as you sent them, and the `columns` you chose, without repeats, with `schema_version`. Null for customer and product exports sent without `columns`.","properties":{"columns":{"description":"Only when you chose columns.","items":{"type":"string"},"type":"array"},"date_field":{"description":"Sales order exports only.","type":"string"},"end_date":{"type":"string"},"schema_version":{"description":"Only when you chose columns.","type":"integer"},"start_date":{"type":"string"}},"type":["object","null"]},"created_at":{"format":"date-time","type":"string"},"created_by":{"description":"A plain number for the person who created it. It is not a hash id and no operation takes it; show `creator.name` instead.","type":["integer","null"]},"creator":{"additionalProperties":true,"description":"The person who created it; null if their account was deleted. More of their account fields may appear; rely only on these.","properties":{"email":{"type":"string"},"id":{"description":"The same plain number as `created_by`, not a hash id.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]},"error_code":{"description":"Why it failed. `export_generation_failed`: the file could not be built; create a new export. `export_attempt_expired`: it did not finish in time. `export_queue_failed`: it could not be queued. Null unless `status` is `failed`.","enum":["export_generation_failed","export_attempt_expired","export_queue_failed",null],"type":["string","null"]},"expires_at":{"description":"When the download stops working: 3 days after the export became ready. The file is then deleted; the export stays in the list but can't be downloaded.","format":"date-time","type":["string","null"]},"file_size":{"description":"File size in bytes, once ready.","type":["integer","null"]},"id":{"description":"The export id. Use it to poll and to download.","type":"string"},"progress":{"properties":{"completed":{"description":"Rows written so far, not counting the header row. Updated every 500 rows; product exports update only at the end.","type":"integer"},"total":{"description":"Rows in the file, not counting the header row. Null until the export is ready: there is no total to show a percentage against while it runs.","type":["integer","null"]}},"required":["completed","total"],"type":"object"},"status":{"description":"`pending`: queued. `generating`: running. `ready`: the file can be downloaded. `failed`: see `error_code`.","enum":["pending","generating","ready","failed"],"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","config","status","created_at","updated_at","created_by","creator","progress","file_size","expires_at","error_code"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"429":{"content":{"application/json":{"example":{"error":{"code":"export_capacity","message":"Your team already has several exports in progress. Please try again when one has finished."},"status":429,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Your team already has 3 exports pending or generating."},"503":{"content":{"application/json":{"example":{"error":{"code":"export_creation_paused","message":"Exports are paused for a few minutes while we update YoPrint. Try again shortly."},"status":503,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Exports are paused for a few minutes during a YoPrint update, or the export could not be queued (`export_queue_failed`, \"The export could not be queued. Try again.\").","headers":{"Retry-After":{"description":"Seconds to wait (120) when exports are paused.","schema":{"type":"integer"}}}}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Export invoice line items in a date range to CSV","tags":["Data exports"],"x-yoprint-docs":{"errors":[{"fix":"Send both dates, with `end_date` on or after `start_date`, and for sales orders a `date_field` from the list.","status":422,"when":"Dates are missing, not dates, or out of order, or, for sales orders, `date_field` is missing or not one of the six (`invalid_export_request`, \"Choose valid, ordered export dates and a supported date field.\")."},{"fix":"Use ids from the definitions operation, or omit `columns`.","status":422,"when":"A column id is unknown, `columns` is not a list, or it is empty (`invalid_export_request`, \"The selected export columns are invalid.\" or \"Select at least one export column.\")."},{"fix":"Send a string of up to 100 characters, or leave it out.","status":422,"when":"`idempotency_key` is not a string or is longer than 100 characters (`invalid_export_request`, \"The export request key is invalid.\")."},{"fix":"Poll the running export and download it instead, or wait until it finishes.","status":422,"when":"An export of this type is already pending or generating for your team (`duplicate_report`, \"There is already a report being generated. Please wait until the report is fully generated\")."},{"fix":"Use a new key for a new export.","status":422,"when":"The `idempotency_key` was used for a different export, or by another member (`invalid_export_request`, \"This request key was already used for a different export.\")."},{"fix":"Wait for one to finish, then try again.","status":429,"when":"Three exports are already pending or generating (`export_capacity`)."},{"fix":"When paused, wait the `Retry-After` seconds and send the request again. After a queue failure, send it again with the same `idempotency_key` to queue the same export.","status":503,"when":"Exports are paused during an update (`export_creation_paused`, with `Retry-After: 120`), even for a retry with the same key; or the export could not be queued (`export_queue_failed`, no `Retry-After`)."}],"group":"Imports and exports","notes":["The range is inclusive at both ends and is compared in UTC, with times. To cover whole days in your team's time zone, convert its midnights to UTC, or send the offset: `2026-10-01T00:00:00-07:00` to `2026-10-31T23:59:59.999-07:00`. There is no maximum range.","Amounts in the file are decimal strings with no currency symbol: `product_cost`, `product_total`, and `service_total` have 3 decimal places (such as `5.125`); `subtotal` and `total` have 2 decimal places (such as `125.00`).","Dates in the file are `YYYY-MM-DD`, in your team's time zone.","The full flow: create the export, poll `GET /v1/api/store/{team_slug}/data_export/{id}` every few seconds until `status` is `ready` (or `failed`), then download the file with `GET /v1/api/store/{team_slug}/data_export/{id}/download` within 3 days.","Retrying with the same `idempotency_key` returns the same export and starts nothing new while it is `pending`, `generating`, `ready`, or failed with `export_generation_failed` (send a new key to try that one again). After `export_queue_failed` or `export_attempt_expired`, the same key queues the same export again, and the one-per-type (422 `duplicate_report`) and three-per-team (429 `export_capacity`) limits apply.","The file is CSV, UTF-8 with a byte order mark. Its first row holds the column ids, such as `order_id` (not the labels), in the order of `columns` or, without it, the default order. An export with no matching records has only that row."],"permission":"Any member of the team. Exports do not check the role: every member can export every type, including sales orders, invoices, payments and tax, even a member whose role can't see them in the web app.","related":["v1_public_data_export_show","v1_public_data_export_download","v1_public_data_export_definitions","v1_public_data_export_export_invoice"],"rules":["`start_date` and `end_date` are required, and `end_date` can't be before `start_date`. There is no maximum range. There is no `date_field`: the range is always the order's issue date.","One export of each type at a time for the whole team: while one is `pending` or `generating`, creating another of the same type is a 422 (`duplicate_report`).","At most 3 exports pending or generating per team, of any type. A fourth is a 429 (`export_capacity`).","`columns`, when sent, must be a non-empty list of column ids for this type. `GET /v1/api/store/{team_slug}/data_export/definitions` lists them with their labels.","`idempotency_key`, when sent, must be a string of at most 100 characters. Reusing a key with a different type, different settings or another person is a 422."],"side_effects":["Queues the export and returns it at once with `status` `pending`. The file is built in the background.","People with the Download Center open see it appear and update live. No email is sent.","The file is kept for 3 days after it is ready, then deleted. The export stays in the list as history."]}}},"/v1/api/store/{team_slug}/data_export/export_payment_list":{"post":{"description":"Starts a CSV export of payments and refunds recorded on your team's orders, one row per payment or refund, with its amount, method and reference. Refunds have a negative `amount`, such as `-25.00`. Payments on deleted orders are left out, and so are customer-credit payments (customer credit applied to an order). It runs in the background: the response is the new export with `status` `pending`.\n\nCustomer Portal payments are in it too, with the provider (such as `STRIPE`) as `payment_method`. A payment for one order is an ordinary row. A payment that went through the customer's credit (for example one for several invoices at once) has one row for the payment and one for each later change to it, such as a refund: each lists every order the payment paid in `order_id` and their invoices in `invoices`, and leaves `order_label`, `warehouse` and `created_by` empty.\n\nThe range applies to when the payment or refund was recorded.","operationId":"v1_public_data_export_export_payment_list","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-10-31T23:59:59.999Z","idempotency_key":"export-payment-list-2026-10","start_date":"2026-10-01T00:00:00Z"},"schema":{"properties":{"columns":{"description":"The columns to include, in the order you want them in the file. Omit it for every column in the default order. Repeats are dropped.","items":{"enum":["order_id","order_label","invoices","customer_name","date","amount","payment_method","reference_id","reference_description","warehouse","created_by"],"type":"string"},"minItems":1,"type":"array","uniqueItems":true},"end_date":{"description":"End of the range, inclusive, on or after `start_date`. A date alone means midnight UTC at its start, which leaves that day out, so send the last moment of the day: `2026-10-31T23:59:59.999Z`.","format":"date-time","type":"string"},"idempotency_key":{"description":"Optional, a string of up to 100 characters. Send the same key to retry the same request safely: you get the export it created, and nothing new starts while that export is `pending`, `generating`, `ready`, or failed with `export_generation_failed`. If it failed with `export_queue_failed` or `export_attempt_expired`, the same key queues it again. Keys are shared by the whole team.","maxLength":100,"type":"string"},"start_date":{"description":"Start of the range, inclusive: a date and time in UTC, such as `2026-10-01T00:00:00Z`. An offset (`2026-10-01T00:00:00-07:00`) is accepted and converted to UTC; a value with neither is read as UTC.","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"config":{"end_date":"2026-10-31T23:59:59.999Z","start_date":"2026-10-01T00:00:00Z"},"created_at":"2026-11-03T09:30:00+00:00","created_by":1001,"creator":{"email":"alex@example.com","id":1001,"name":"Alex Rivera"},"error_code":null,"expires_at":null,"file_size":null,"id":"G59hl28azOL22k","progress":{"completed":0,"total":null},"status":"pending","type":"payment_list","updated_at":"2026-11-03T09:30:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"config":{"description":"What you asked for: the dates (and `date_field`) as you sent them, and the `columns` you chose, without repeats, with `schema_version`. Null for customer and product exports sent without `columns`.","properties":{"columns":{"description":"Only when you chose columns.","items":{"type":"string"},"type":"array"},"date_field":{"description":"Sales order exports only.","type":"string"},"end_date":{"type":"string"},"schema_version":{"description":"Only when you chose columns.","type":"integer"},"start_date":{"type":"string"}},"type":["object","null"]},"created_at":{"format":"date-time","type":"string"},"created_by":{"description":"A plain number for the person who created it. It is not a hash id and no operation takes it; show `creator.name` instead.","type":["integer","null"]},"creator":{"additionalProperties":true,"description":"The person who created it; null if their account was deleted. More of their account fields may appear; rely only on these.","properties":{"email":{"type":"string"},"id":{"description":"The same plain number as `created_by`, not a hash id.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]},"error_code":{"description":"Why it failed. `export_generation_failed`: the file could not be built; create a new export. `export_attempt_expired`: it did not finish in time. `export_queue_failed`: it could not be queued. Null unless `status` is `failed`.","enum":["export_generation_failed","export_attempt_expired","export_queue_failed",null],"type":["string","null"]},"expires_at":{"description":"When the download stops working: 3 days after the export became ready. The file is then deleted; the export stays in the list but can't be downloaded.","format":"date-time","type":["string","null"]},"file_size":{"description":"File size in bytes, once ready.","type":["integer","null"]},"id":{"description":"The export id. Use it to poll and to download.","type":"string"},"progress":{"properties":{"completed":{"description":"Rows written so far, not counting the header row. Updated every 500 rows; product exports update only at the end.","type":"integer"},"total":{"description":"Rows in the file, not counting the header row. Null until the export is ready: there is no total to show a percentage against while it runs.","type":["integer","null"]}},"required":["completed","total"],"type":"object"},"status":{"description":"`pending`: queued. `generating`: running. `ready`: the file can be downloaded. `failed`: see `error_code`.","enum":["pending","generating","ready","failed"],"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","config","status","created_at","updated_at","created_by","creator","progress","file_size","expires_at","error_code"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"429":{"content":{"application/json":{"example":{"error":{"code":"export_capacity","message":"Your team already has several exports in progress. Please try again when one has finished."},"status":429,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Your team already has 3 exports pending or generating."},"503":{"content":{"application/json":{"example":{"error":{"code":"export_creation_paused","message":"Exports are paused for a few minutes while we update YoPrint. Try again shortly."},"status":503,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Exports are paused for a few minutes during a YoPrint update, or the export could not be queued (`export_queue_failed`, \"The export could not be queued. Try again.\").","headers":{"Retry-After":{"description":"Seconds to wait (120) when exports are paused.","schema":{"type":"integer"}}}}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Export payments and refunds in a date range to CSV","tags":["Data exports"],"x-yoprint-docs":{"errors":[{"fix":"Send both dates, with `end_date` on or after `start_date`, and for sales orders a `date_field` from the list.","status":422,"when":"Dates are missing, not dates, or out of order, or, for sales orders, `date_field` is missing or not one of the six (`invalid_export_request`, \"Choose valid, ordered export dates and a supported date field.\")."},{"fix":"Use ids from the definitions operation, or omit `columns`.","status":422,"when":"A column id is unknown, `columns` is not a list, or it is empty (`invalid_export_request`, \"The selected export columns are invalid.\" or \"Select at least one export column.\")."},{"fix":"Send a string of up to 100 characters, or leave it out.","status":422,"when":"`idempotency_key` is not a string or is longer than 100 characters (`invalid_export_request`, \"The export request key is invalid.\")."},{"fix":"Poll the running export and download it instead, or wait until it finishes.","status":422,"when":"An export of this type is already pending or generating for your team (`duplicate_report`, \"There is already a report being generated. Please wait until the report is fully generated\")."},{"fix":"Use a new key for a new export.","status":422,"when":"The `idempotency_key` was used for a different export, or by another member (`invalid_export_request`, \"This request key was already used for a different export.\")."},{"fix":"Wait for one to finish, then try again.","status":429,"when":"Three exports are already pending or generating (`export_capacity`)."},{"fix":"When paused, wait the `Retry-After` seconds and send the request again. After a queue failure, send it again with the same `idempotency_key` to queue the same export.","status":503,"when":"Exports are paused during an update (`export_creation_paused`, with `Retry-After: 120`), even for a retry with the same key; or the export could not be queued (`export_queue_failed`, no `Retry-After`)."}],"group":"Imports and exports","notes":["The range is inclusive at both ends and is compared in UTC, with times. To cover whole days in your team's time zone, convert its midnights to UTC, or send the offset: `2026-10-01T00:00:00-07:00` to `2026-10-31T23:59:59.999-07:00`. There is no maximum range.","Amounts in the file are decimal strings with 2 decimal places and no currency symbol, such as `125.00`. In invoice and tax exports (`invoice_list`, `tax_list`), `tax_percentage` is a percentage as a decimal string (`8.25`, `0`), empty when the invoice has no single tax rate (for example a fixed tax amount). In sales order, invoice, and tax exports (`sales_order_list`, `invoice_list`, `tax_list`), the `paid` column is `TRUE` or `FALSE`.","`date` is the date the payment or refund was recorded, taken in UTC, written in your team's PDF date format (such as `17 Aug 2026`), not as `YYYY-MM-DD`.","`created_by` is the name of the person who created the order, not of the person who recorded the payment.","On a Customer Portal payment row, `order_id` and `invoices` hold order and invoice numbers separated by commas. `amount` is a decimal string with at least 2 decimal places and as many more as it needs, such as `125.00` or `-12.125`; parse it as a decimal.","The full flow: create the export, poll `GET /v1/api/store/{team_slug}/data_export/{id}` every few seconds until `status` is `ready` (or `failed`), then download the file with `GET /v1/api/store/{team_slug}/data_export/{id}/download` within 3 days.","Retrying with the same `idempotency_key` returns the same export and starts nothing new while it is `pending`, `generating`, `ready`, or failed with `export_generation_failed` (send a new key to try that one again). After `export_queue_failed` or `export_attempt_expired`, the same key queues the same export again, and the one-per-type (422 `duplicate_report`) and three-per-team (429 `export_capacity`) limits apply.","The file is CSV, UTF-8 with a byte order mark. Its first row holds the column ids, such as `order_id` (not the labels), in the order of `columns` or, without it, the default order. An export with no matching records has only that row."],"permission":"Any member of the team. Exports do not check the role: every member can export every type, including sales orders, invoices, payments and tax, even a member whose role can't see them in the web app.","related":["v1_public_data_export_show","v1_public_data_export_download","v1_public_data_export_definitions","v1_public_data_export_export_tax"],"rules":["`start_date` and `end_date` are required, and `end_date` can't be before `start_date`. There is no maximum range. There is no `date_field`: the range is when each payment was recorded.","One export of each type at a time for the whole team: while one is `pending` or `generating`, creating another of the same type is a 422 (`duplicate_report`).","At most 3 exports pending or generating per team, of any type. A fourth is a 429 (`export_capacity`).","`columns`, when sent, must be a non-empty list of column ids for this type. `GET /v1/api/store/{team_slug}/data_export/definitions` lists them with their labels.","`idempotency_key`, when sent, must be a string of at most 100 characters. Reusing a key with a different type, different settings or another person is a 422."],"side_effects":["Queues the export and returns it at once with `status` `pending`. The file is built in the background.","People with the Download Center open see it appear and update live. No email is sent.","The file is kept for 3 days after it is ready, then deleted. The export stays in the list as history."]}}},"/v1/api/store/{team_slug}/data_export/export_purchase_order_list":{"post":{"description":"Starts a CSV export of purchase orders whose issue date falls in the range, one row per purchase order, with the vendor, status, ordered and received totals, and the related sales orders and customers. Deleted purchase orders are left out. It runs in the background: the response is the new export with `status` `pending`.","operationId":"v1_public_data_export_export_purchase_order_list","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-10-31T23:59:59.999Z","idempotency_key":"export-purchase-order-list-2026-10","start_date":"2026-10-01T00:00:00Z"},"schema":{"properties":{"columns":{"description":"The columns to include, in the order you want them in the file. Omit it for every column in the default order. Repeats are dropped.","items":{"enum":["id","name","vendor","issue_date","due_date","billing_address_label","warehouse_label","creator","status","received_subtotal","received_tax","received_total","ordered_subtotal","ordered_tax","ordered_total","related_orders","related_customers","internal_note","vendor_note"],"type":"string"},"minItems":1,"type":"array","uniqueItems":true},"end_date":{"description":"End of the range, inclusive, on or after `start_date`. A date alone means midnight UTC at its start, which leaves that day out, so send the last moment of the day: `2026-10-31T23:59:59.999Z`.","format":"date-time","type":"string"},"idempotency_key":{"description":"Optional, a string of up to 100 characters. Send the same key to retry the same request safely: you get the export it created, and nothing new starts while that export is `pending`, `generating`, `ready`, or failed with `export_generation_failed`. If it failed with `export_queue_failed` or `export_attempt_expired`, the same key queues it again. Keys are shared by the whole team.","maxLength":100,"type":"string"},"start_date":{"description":"Start of the range, inclusive: a date and time in UTC, such as `2026-10-01T00:00:00Z`. An offset (`2026-10-01T00:00:00-07:00`) is accepted and converted to UTC; a value with neither is read as UTC.","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"config":{"end_date":"2026-10-31T23:59:59.999Z","start_date":"2026-10-01T00:00:00Z"},"created_at":"2026-11-03T09:30:00+00:00","created_by":1001,"creator":{"email":"alex@example.com","id":1001,"name":"Alex Rivera"},"error_code":null,"expires_at":null,"file_size":null,"id":"G59hl28azOL22k","progress":{"completed":0,"total":null},"status":"pending","type":"purchase_order_list","updated_at":"2026-11-03T09:30:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"config":{"description":"What you asked for: the dates (and `date_field`) as you sent them, and the `columns` you chose, without repeats, with `schema_version`. Null for customer and product exports sent without `columns`.","properties":{"columns":{"description":"Only when you chose columns.","items":{"type":"string"},"type":"array"},"date_field":{"description":"Sales order exports only.","type":"string"},"end_date":{"type":"string"},"schema_version":{"description":"Only when you chose columns.","type":"integer"},"start_date":{"type":"string"}},"type":["object","null"]},"created_at":{"format":"date-time","type":"string"},"created_by":{"description":"A plain number for the person who created it. It is not a hash id and no operation takes it; show `creator.name` instead.","type":["integer","null"]},"creator":{"additionalProperties":true,"description":"The person who created it; null if their account was deleted. More of their account fields may appear; rely only on these.","properties":{"email":{"type":"string"},"id":{"description":"The same plain number as `created_by`, not a hash id.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]},"error_code":{"description":"Why it failed. `export_generation_failed`: the file could not be built; create a new export. `export_attempt_expired`: it did not finish in time. `export_queue_failed`: it could not be queued. Null unless `status` is `failed`.","enum":["export_generation_failed","export_attempt_expired","export_queue_failed",null],"type":["string","null"]},"expires_at":{"description":"When the download stops working: 3 days after the export became ready. The file is then deleted; the export stays in the list but can't be downloaded.","format":"date-time","type":["string","null"]},"file_size":{"description":"File size in bytes, once ready.","type":["integer","null"]},"id":{"description":"The export id. Use it to poll and to download.","type":"string"},"progress":{"properties":{"completed":{"description":"Rows written so far, not counting the header row. Updated every 500 rows; product exports update only at the end.","type":"integer"},"total":{"description":"Rows in the file, not counting the header row. Null until the export is ready: there is no total to show a percentage against while it runs.","type":["integer","null"]}},"required":["completed","total"],"type":"object"},"status":{"description":"`pending`: queued. `generating`: running. `ready`: the file can be downloaded. `failed`: see `error_code`.","enum":["pending","generating","ready","failed"],"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","config","status","created_at","updated_at","created_by","creator","progress","file_size","expires_at","error_code"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"429":{"content":{"application/json":{"example":{"error":{"code":"export_capacity","message":"Your team already has several exports in progress. Please try again when one has finished."},"status":429,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Your team already has 3 exports pending or generating."},"503":{"content":{"application/json":{"example":{"error":{"code":"export_creation_paused","message":"Exports are paused for a few minutes while we update YoPrint. Try again shortly."},"status":503,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Exports are paused for a few minutes during a YoPrint update, or the export could not be queued (`export_queue_failed`, \"The export could not be queued. Try again.\").","headers":{"Retry-After":{"description":"Seconds to wait (120) when exports are paused.","schema":{"type":"integer"}}}}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Export purchase orders in a date range to CSV","tags":["Data exports"],"x-yoprint-docs":{"errors":[{"fix":"Send both dates, with `end_date` on or after `start_date`, and for sales orders a `date_field` from the list.","status":422,"when":"Dates are missing, not dates, or out of order, or, for sales orders, `date_field` is missing or not one of the six (`invalid_export_request`, \"Choose valid, ordered export dates and a supported date field.\")."},{"fix":"Use ids from the definitions operation, or omit `columns`.","status":422,"when":"A column id is unknown, `columns` is not a list, or it is empty (`invalid_export_request`, \"The selected export columns are invalid.\" or \"Select at least one export column.\")."},{"fix":"Send a string of up to 100 characters, or leave it out.","status":422,"when":"`idempotency_key` is not a string or is longer than 100 characters (`invalid_export_request`, \"The export request key is invalid.\")."},{"fix":"Poll the running export and download it instead, or wait until it finishes.","status":422,"when":"An export of this type is already pending or generating for your team (`duplicate_report`, \"There is already a report being generated. Please wait until the report is fully generated\")."},{"fix":"Use a new key for a new export.","status":422,"when":"The `idempotency_key` was used for a different export, or by another member (`invalid_export_request`, \"This request key was already used for a different export.\")."},{"fix":"Wait for one to finish, then try again.","status":429,"when":"Three exports are already pending or generating (`export_capacity`)."},{"fix":"When paused, wait the `Retry-After` seconds and send the request again. After a queue failure, send it again with the same `idempotency_key` to queue the same export.","status":503,"when":"Exports are paused during an update (`export_creation_paused`, with `Retry-After: 120`), even for a retry with the same key; or the export could not be queued (`export_queue_failed`, no `Retry-After`)."}],"group":"Imports and exports","notes":["The range is inclusive at both ends and is compared in UTC, with times. To cover whole days in your team's time zone, convert its midnights to UTC, or send the offset: `2026-10-01T00:00:00-07:00` to `2026-10-31T23:59:59.999-07:00`. There is no maximum range.","Amounts in the file are decimal strings with 2 decimal places and no currency symbol, such as `125.00`. In invoice and tax exports (`invoice_list`, `tax_list`), `tax_percentage` is a percentage as a decimal string (`8.25`, `0`), empty when the invoice has no single tax rate (for example a fixed tax amount). In sales order, invoice, and tax exports (`sales_order_list`, `invoice_list`, `tax_list`), the `paid` column is `TRUE` or `FALSE`.","Dates in the file are `YYYY-MM-DD`, in your team's time zone.","The full flow: create the export, poll `GET /v1/api/store/{team_slug}/data_export/{id}` every few seconds until `status` is `ready` (or `failed`), then download the file with `GET /v1/api/store/{team_slug}/data_export/{id}/download` within 3 days.","Retrying with the same `idempotency_key` returns the same export and starts nothing new while it is `pending`, `generating`, `ready`, or failed with `export_generation_failed` (send a new key to try that one again). After `export_queue_failed` or `export_attempt_expired`, the same key queues the same export again, and the one-per-type (422 `duplicate_report`) and three-per-team (429 `export_capacity`) limits apply.","The file is CSV, UTF-8 with a byte order mark. Its first row holds the column ids, such as `order_id` (not the labels), in the order of `columns` or, without it, the default order. An export with no matching records has only that row."],"permission":"Any member of the team. Exports do not check the role: every member can export every type, including sales orders, invoices, payments and tax, even a member whose role can't see them in the web app.","related":["v1_public_data_export_show","v1_public_data_export_download","v1_public_data_export_definitions"],"rules":["`start_date` and `end_date` are required, and `end_date` can't be before `start_date`. There is no maximum range. There is no `date_field`: the range is the purchase order's issue date.","One export of each type at a time for the whole team: while one is `pending` or `generating`, creating another of the same type is a 422 (`duplicate_report`).","At most 3 exports pending or generating per team, of any type. A fourth is a 429 (`export_capacity`).","`columns`, when sent, must be a non-empty list of column ids for this type. `GET /v1/api/store/{team_slug}/data_export/definitions` lists them with their labels.","`idempotency_key`, when sent, must be a string of at most 100 characters. Reusing a key with a different type, different settings or another person is a 422."],"side_effects":["Queues the export and returns it at once with `status` `pending`. The file is built in the background.","People with the Download Center open see it appear and update live. No email is sent.","The file is kept for 3 days after it is ready, then deleted. The export stays in the list as history."]}}},"/v1/api/store/{team_slug}/data_export/export_sales_order":{"post":{"description":"Starts a CSV export of your team's sales orders whose chosen date (`date_field`) falls in the range. Quotes and draft orders are left out. One row per order, with its customer, dates, status and totals. It runs in the background: the response is the new export with `status` `pending`.","operationId":"v1_public_data_export_export_sales_order","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"date_field":"issue_date","end_date":"2026-10-31T23:59:59.999Z","idempotency_key":"export-sales-order-list-2026-10","start_date":"2026-10-01T00:00:00Z"},"schema":{"properties":{"columns":{"description":"The columns to include, in the order you want them in the file. Omit it for every column in the default order. Repeats are dropped.","items":{"enum":["name","order_id","issue_date","creator","customer_po_number","customer_email","customer_contact_name","customer_name","customer_tax_exempt","customer_brand_profile","pricing_group","payment_term","pricing_strategy","warehouse","production_start_date","production_due_date","shipment_due_date","customer_in_hand_date","client_note","prod_note","jobs","status","subtotal","discount","tax","total","balance_due","paid","last_payment_date","tags"],"type":"string"},"minItems":1,"type":"array","uniqueItems":true},"date_field":{"description":"Which order date the range applies to: `issue_date` (issue date), `deposit_due` (deposit due), `due_date` (production due), `ship_due_date` (shipment due), `cust_due_date` (customer in-hand) or `start_date` (production start).","enum":["issue_date","deposit_due","due_date","ship_due_date","cust_due_date","start_date"],"type":"string"},"end_date":{"description":"End of the range, inclusive, on or after `start_date`. A date alone means midnight UTC at its start, which leaves that day out, so send the last moment of the day: `2026-10-31T23:59:59.999Z`.","format":"date-time","type":"string"},"idempotency_key":{"description":"Optional, a string of up to 100 characters. Send the same key to retry the same request safely: you get the export it created, and nothing new starts while that export is `pending`, `generating`, `ready`, or failed with `export_generation_failed`. If it failed with `export_queue_failed` or `export_attempt_expired`, the same key queues it again. Keys are shared by the whole team.","maxLength":100,"type":"string"},"start_date":{"description":"Start of the range, inclusive: a date and time in UTC, such as `2026-10-01T00:00:00Z`. An offset (`2026-10-01T00:00:00-07:00`) is accepted and converted to UTC; a value with neither is read as UTC.","format":"date-time","type":"string"}},"required":["start_date","end_date","date_field"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"config":{"date_field":"issue_date","end_date":"2026-10-31T23:59:59.999Z","start_date":"2026-10-01T00:00:00Z"},"created_at":"2026-11-03T09:30:00+00:00","created_by":1001,"creator":{"email":"alex@example.com","id":1001,"name":"Alex Rivera"},"error_code":null,"expires_at":null,"file_size":null,"id":"G59hl28azOL22k","progress":{"completed":0,"total":null},"status":"pending","type":"sales_order_list","updated_at":"2026-11-03T09:30:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"config":{"description":"What you asked for: the dates (and `date_field`) as you sent them, and the `columns` you chose, without repeats, with `schema_version`. Null for customer and product exports sent without `columns`.","properties":{"columns":{"description":"Only when you chose columns.","items":{"type":"string"},"type":"array"},"date_field":{"description":"Sales order exports only.","type":"string"},"end_date":{"type":"string"},"schema_version":{"description":"Only when you chose columns.","type":"integer"},"start_date":{"type":"string"}},"type":["object","null"]},"created_at":{"format":"date-time","type":"string"},"created_by":{"description":"A plain number for the person who created it. It is not a hash id and no operation takes it; show `creator.name` instead.","type":["integer","null"]},"creator":{"additionalProperties":true,"description":"The person who created it; null if their account was deleted. More of their account fields may appear; rely only on these.","properties":{"email":{"type":"string"},"id":{"description":"The same plain number as `created_by`, not a hash id.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]},"error_code":{"description":"Why it failed. `export_generation_failed`: the file could not be built; create a new export. `export_attempt_expired`: it did not finish in time. `export_queue_failed`: it could not be queued. Null unless `status` is `failed`.","enum":["export_generation_failed","export_attempt_expired","export_queue_failed",null],"type":["string","null"]},"expires_at":{"description":"When the download stops working: 3 days after the export became ready. The file is then deleted; the export stays in the list but can't be downloaded.","format":"date-time","type":["string","null"]},"file_size":{"description":"File size in bytes, once ready.","type":["integer","null"]},"id":{"description":"The export id. Use it to poll and to download.","type":"string"},"progress":{"properties":{"completed":{"description":"Rows written so far, not counting the header row. Updated every 500 rows; product exports update only at the end.","type":"integer"},"total":{"description":"Rows in the file, not counting the header row. Null until the export is ready: there is no total to show a percentage against while it runs.","type":["integer","null"]}},"required":["completed","total"],"type":"object"},"status":{"description":"`pending`: queued. `generating`: running. `ready`: the file can be downloaded. `failed`: see `error_code`.","enum":["pending","generating","ready","failed"],"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","config","status","created_at","updated_at","created_by","creator","progress","file_size","expires_at","error_code"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"429":{"content":{"application/json":{"example":{"error":{"code":"export_capacity","message":"Your team already has several exports in progress. Please try again when one has finished."},"status":429,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Your team already has 3 exports pending or generating."},"503":{"content":{"application/json":{"example":{"error":{"code":"export_creation_paused","message":"Exports are paused for a few minutes while we update YoPrint. Try again shortly."},"status":503,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Exports are paused for a few minutes during a YoPrint update, or the export could not be queued (`export_queue_failed`, \"The export could not be queued. Try again.\").","headers":{"Retry-After":{"description":"Seconds to wait (120) when exports are paused.","schema":{"type":"integer"}}}}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Export sales orders in a date range to CSV","tags":["Data exports"],"x-yoprint-docs":{"errors":[{"fix":"Send both dates, with `end_date` on or after `start_date`, and for sales orders a `date_field` from the list.","status":422,"when":"Dates are missing, not dates, or out of order, or, for sales orders, `date_field` is missing or not one of the six (`invalid_export_request`, \"Choose valid, ordered export dates and a supported date field.\")."},{"fix":"Use ids from the definitions operation, or omit `columns`.","status":422,"when":"A column id is unknown, `columns` is not a list, or it is empty (`invalid_export_request`, \"The selected export columns are invalid.\" or \"Select at least one export column.\")."},{"fix":"Send a string of up to 100 characters, or leave it out.","status":422,"when":"`idempotency_key` is not a string or is longer than 100 characters (`invalid_export_request`, \"The export request key is invalid.\")."},{"fix":"Poll the running export and download it instead, or wait until it finishes.","status":422,"when":"An export of this type is already pending or generating for your team (`duplicate_report`, \"There is already a report being generated. Please wait until the report is fully generated\")."},{"fix":"Use a new key for a new export.","status":422,"when":"The `idempotency_key` was used for a different export, or by another member (`invalid_export_request`, \"This request key was already used for a different export.\")."},{"fix":"Wait for one to finish, then try again.","status":429,"when":"Three exports are already pending or generating (`export_capacity`)."},{"fix":"When paused, wait the `Retry-After` seconds and send the request again. After a queue failure, send it again with the same `idempotency_key` to queue the same export.","status":503,"when":"Exports are paused during an update (`export_creation_paused`, with `Retry-After: 120`), even for a retry with the same key; or the export could not be queued (`export_queue_failed`, no `Retry-After`)."}],"group":"Imports and exports","notes":["The range is inclusive at both ends and is compared in UTC, with times. To cover whole days in your team's time zone, convert its midnights to UTC, or send the offset: `2026-10-01T00:00:00-07:00` to `2026-10-31T23:59:59.999-07:00`. There is no maximum range.","Amounts in the file are decimal strings with 2 decimal places and no currency symbol, such as `125.00`. In invoice and tax exports (`invoice_list`, `tax_list`), `tax_percentage` is a percentage as a decimal string (`8.25`, `0`), empty when the invoice has no single tax rate (for example a fixed tax amount). In sales order, invoice, and tax exports (`sales_order_list`, `invoice_list`, `tax_list`), the `paid` column is `TRUE` or `FALSE`.","Dates in the file are `YYYY-MM-DD`, in your team's time zone.","The full flow: create the export, poll `GET /v1/api/store/{team_slug}/data_export/{id}` every few seconds until `status` is `ready` (or `failed`), then download the file with `GET /v1/api/store/{team_slug}/data_export/{id}/download` within 3 days.","Retrying with the same `idempotency_key` returns the same export and starts nothing new while it is `pending`, `generating`, `ready`, or failed with `export_generation_failed` (send a new key to try that one again). After `export_queue_failed` or `export_attempt_expired`, the same key queues the same export again, and the one-per-type (422 `duplicate_report`) and three-per-team (429 `export_capacity`) limits apply.","The file is CSV, UTF-8 with a byte order mark. Its first row holds the column ids, such as `order_id` (not the labels), in the order of `columns` or, without it, the default order. An export with no matching records has only that row."],"permission":"Any member of the team. Exports do not check the role: every member can export every type, including sales orders, invoices, payments and tax, even a member whose role can't see them in the web app.","related":["v1_public_data_export_show","v1_public_data_export_download","v1_public_data_export_definitions"],"rules":["`start_date` and `end_date` are required, and `end_date` can't be before `start_date`. There is no maximum range. `date_field` is required and must be one of the six order dates.","One export of each type at a time for the whole team: while one is `pending` or `generating`, creating another of the same type is a 422 (`duplicate_report`).","At most 3 exports pending or generating per team, of any type. A fourth is a 429 (`export_capacity`).","`columns`, when sent, must be a non-empty list of column ids for this type. `GET /v1/api/store/{team_slug}/data_export/definitions` lists them with their labels.","`idempotency_key`, when sent, must be a string of at most 100 characters. Reusing a key with a different type, different settings or another person is a 422."],"side_effects":["Queues the export and returns it at once with `status` `pending`. The file is built in the background.","People with the Download Center open see it appear and update live. No email is sent.","The file is kept for 3 days after it is ready, then deleted. The export stays in the list as history."]}}},"/v1/api/store/{team_slug}/data_export/export_simple_product_list":{"post":{"description":"Starts a CSV export of your team's custom simple products (deleted products are left out). It runs in the background: the response is the new export with `status` `pending`.\n\nThe columns match the simple product CSV template, plus `status`, the product's sales status: `On sale` or `Phased out`. `price` is a decimal string with at least 2 decimal places (`10.00`, `5.125`); parse it as a decimal. `weight` has 2. Send no body for every column, or `columns` to choose them.","operationId":"v1_public_data_export_export_simple_product_list","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"columns":["title","brand","supplier_code","price","status"],"idempotency_key":"export-simple-product-list-1"},"schema":{"properties":{"columns":{"description":"The columns to include, in the order you want them in the file. Omit it for every column in the default order. Repeats are dropped.","items":{"enum":["title","brand","description","supplier_code","weight","price","status"],"type":"string"},"minItems":1,"type":"array","uniqueItems":true},"idempotency_key":{"description":"Optional, a string of up to 100 characters. Send the same key to retry the same request safely: you get the export it created, and nothing new starts while that export is `pending`, `generating`, `ready`, or failed with `export_generation_failed`. If it failed with `export_queue_failed` or `export_attempt_expired`, the same key queues it again. Keys are shared by the whole team.","maxLength":100,"type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":{"config":{"columns":["title","brand","supplier_code","price","status"],"schema_version":1},"created_at":"2026-11-03T09:30:00+00:00","created_by":1001,"creator":{"email":"alex@example.com","id":1001,"name":"Alex Rivera"},"error_code":null,"expires_at":null,"file_size":null,"id":"G59hl28azOL22k","progress":{"completed":0,"total":null},"status":"pending","type":"simple_product_list","updated_at":"2026-11-03T09:30:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"config":{"description":"What you asked for: the dates (and `date_field`) as you sent them, and the `columns` you chose, without repeats, with `schema_version`. Null for customer and product exports sent without `columns`.","properties":{"columns":{"description":"Only when you chose columns.","items":{"type":"string"},"type":"array"},"date_field":{"description":"Sales order exports only.","type":"string"},"end_date":{"type":"string"},"schema_version":{"description":"Only when you chose columns.","type":"integer"},"start_date":{"type":"string"}},"type":["object","null"]},"created_at":{"format":"date-time","type":"string"},"created_by":{"description":"A plain number for the person who created it. It is not a hash id and no operation takes it; show `creator.name` instead.","type":["integer","null"]},"creator":{"additionalProperties":true,"description":"The person who created it; null if their account was deleted. More of their account fields may appear; rely only on these.","properties":{"email":{"type":"string"},"id":{"description":"The same plain number as `created_by`, not a hash id.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]},"error_code":{"description":"Why it failed. `export_generation_failed`: the file could not be built; create a new export. `export_attempt_expired`: it did not finish in time. `export_queue_failed`: it could not be queued. Null unless `status` is `failed`.","enum":["export_generation_failed","export_attempt_expired","export_queue_failed",null],"type":["string","null"]},"expires_at":{"description":"When the download stops working: 3 days after the export became ready. The file is then deleted; the export stays in the list but can't be downloaded.","format":"date-time","type":["string","null"]},"file_size":{"description":"File size in bytes, once ready.","type":["integer","null"]},"id":{"description":"The export id. Use it to poll and to download.","type":"string"},"progress":{"properties":{"completed":{"description":"Rows written so far, not counting the header row. Updated every 500 rows; product exports update only at the end.","type":"integer"},"total":{"description":"Rows in the file, not counting the header row. Null until the export is ready: there is no total to show a percentage against while it runs.","type":["integer","null"]}},"required":["completed","total"],"type":"object"},"status":{"description":"`pending`: queued. `generating`: running. `ready`: the file can be downloaded. `failed`: see `error_code`.","enum":["pending","generating","ready","failed"],"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","config","status","created_at","updated_at","created_by","creator","progress","file_size","expires_at","error_code"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"429":{"content":{"application/json":{"example":{"error":{"code":"export_capacity","message":"Your team already has several exports in progress. Please try again when one has finished."},"status":429,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Your team already has 3 exports pending or generating."},"503":{"content":{"application/json":{"example":{"error":{"code":"export_creation_paused","message":"Exports are paused for a few minutes while we update YoPrint. Try again shortly."},"status":503,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Exports are paused for a few minutes during a YoPrint update, or the export could not be queued (`export_queue_failed`, \"The export could not be queued. Try again.\").","headers":{"Retry-After":{"description":"Seconds to wait (120) when exports are paused.","schema":{"type":"integer"}}}}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Export all simple products to CSV","tags":["Data exports"],"x-yoprint-docs":{"errors":[{"fix":"Use ids from the definitions operation, or omit `columns`.","status":422,"when":"A column id is unknown, `columns` is not a list, or it is empty (`invalid_export_request`, \"The selected export columns are invalid.\" or \"Select at least one export column.\")."},{"fix":"Send a string of up to 100 characters, or leave it out.","status":422,"when":"`idempotency_key` is not a string or is longer than 100 characters (`invalid_export_request`, \"The export request key is invalid.\")."},{"fix":"Poll the running export and download it instead, or wait until it finishes.","status":422,"when":"An export of this type is already pending or generating for your team (`duplicate_report`, \"There is already a report being generated. Please wait until the report is fully generated\")."},{"fix":"Use a new key for a new export.","status":422,"when":"The `idempotency_key` was used for a different export, or by another member (`invalid_export_request`, \"This request key was already used for a different export.\")."},{"fix":"Wait for one to finish, then try again.","status":429,"when":"Three exports are already pending or generating (`export_capacity`)."},{"fix":"When paused, wait the `Retry-After` seconds and send the request again. After a queue failure, send it again with the same `idempotency_key` to queue the same export.","status":503,"when":"Exports are paused during an update (`export_creation_paused`, with `Retry-After: 120`), even for a retry with the same key; or the export could not be queued (`export_queue_failed`, no `Retry-After`)."}],"group":"Imports and exports","notes":["The full flow: create the export, poll `GET /v1/api/store/{team_slug}/data_export/{id}` every few seconds until `status` is `ready` (or `failed`), then download the file with `GET /v1/api/store/{team_slug}/data_export/{id}/download` within 3 days.","Retrying with the same `idempotency_key` returns the same export and starts nothing new while it is `pending`, `generating`, `ready`, or failed with `export_generation_failed` (send a new key to try that one again). After `export_queue_failed` or `export_attempt_expired`, the same key queues the same export again, and the one-per-type (422 `duplicate_report`) and three-per-team (429 `export_capacity`) limits apply.","The file is CSV, UTF-8 with a byte order mark. Its first row holds the column ids, such as `order_id` (not the labels), in the order of `columns` or, without it, the default order. An export with no matching records has only that row.","`progress.completed` stays 0 until a product export is ready."],"permission":"Any member of the team. Exports do not check the role: every member can export every type, including sales orders, invoices, payments and tax, even a member whose role can't see them in the web app.","related":["v1_public_data_export_show","v1_public_data_export_download","v1_public_data_export_definitions","v1_public_data_export_export_variant_product_list"],"rules":["One export of each type at a time for the whole team: while one is `pending` or `generating`, creating another of the same type is a 422 (`duplicate_report`).","At most 3 exports pending or generating per team, of any type. A fourth is a 429 (`export_capacity`).","`columns`, when sent, must be a non-empty list of column ids for this type. `GET /v1/api/store/{team_slug}/data_export/definitions` lists them with their labels.","`idempotency_key`, when sent, must be a string of at most 100 characters. Reusing a key with a different type, different settings or another person is a 422."],"side_effects":["Queues the export and returns it at once with `status` `pending`. The file is built in the background.","People with the Download Center open see it appear and update live. No email is sent.","The file is kept for 3 days after it is ready, then deleted. The export stays in the list as history."]}}},"/v1/api/store/{team_slug}/data_export/export_tax":{"post":{"description":"Starts a CSV export of the tax report. It exports invoices for orders that meet all of these conditions:\n\n1. **Fully paid**: The order's paid amount meets or exceeds its total. Orders paid in part are excluded.\n2. **Current invoice format**: The order is not deleted, and its invoices use YoPrint's current invoice format (v2).\n3. **Qualifying activity on the final transaction day**: YoPrint checks only the order's last calendar day of transactions (measured in UTC). That final day must contain a payment, a refund, or Customer Portal checkout credit applied to the order.\n4. **Date range matches the final transaction day**: The export date range must cover that last UTC transaction day.\n\nAn order will not appear in any tax export if its final UTC transaction day has only non-portal customer credit applied (or if other transactions occurred on a later UTC day without a payment or refund).\n\nEach qualifying invoice appears once, with the same columns as the invoice export (including `tax` and `tax_percentage`). It runs in the background: the response is the new export with `status` `pending`.\n\nUse this report for tax collected on fully paid orders. For every invoice issued in a period, use the invoice export.","operationId":"v1_public_data_export_export_tax","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-10-31T23:59:59.999Z","idempotency_key":"export-tax-list-2026-10","start_date":"2026-10-01T00:00:00Z"},"schema":{"properties":{"columns":{"description":"The columns to include, in the order you want them in the file. Omit it for every column in the default order. Repeats are dropped.","items":{"enum":["order_id","order_name","order_status","order_issue_date","issue_date","order_creator","order_customer_in_hand_date","invoice_id","customer_email","customer_contact_name","customer_name","customer_tax_exempt","order_warehouse","shipping_label","shipping_address1","shipping_address2","shipping_city","shipping_state","shipping_state_code","shipping_country","shipping_country_code","shipping_postcode","jobs","discount","subtotal","total","delivery","tax","tax_percentage","paid_amount","balance_due","paid","last_payment_date"],"type":"string"},"minItems":1,"type":"array","uniqueItems":true},"end_date":{"description":"End of the range, inclusive, on or after `start_date`. A date alone means midnight UTC at its start, which leaves that day out, so send the last moment of the day: `2026-10-31T23:59:59.999Z`.","format":"date-time","type":"string"},"idempotency_key":{"description":"Optional, a string of up to 100 characters. Send the same key to retry the same request safely: you get the export it created, and nothing new starts while that export is `pending`, `generating`, `ready`, or failed with `export_generation_failed`. If it failed with `export_queue_failed` or `export_attempt_expired`, the same key queues it again. Keys are shared by the whole team.","maxLength":100,"type":"string"},"start_date":{"description":"Start of the range, inclusive: a date and time in UTC, such as `2026-10-01T00:00:00Z`. An offset (`2026-10-01T00:00:00-07:00`) is accepted and converted to UTC; a value with neither is read as UTC.","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"config":{"end_date":"2026-10-31T23:59:59.999Z","start_date":"2026-10-01T00:00:00Z"},"created_at":"2026-11-03T09:30:00+00:00","created_by":1001,"creator":{"email":"alex@example.com","id":1001,"name":"Alex Rivera"},"error_code":null,"expires_at":null,"file_size":null,"id":"G59hl28azOL22k","progress":{"completed":0,"total":null},"status":"pending","type":"tax_list","updated_at":"2026-11-03T09:30:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"config":{"description":"What you asked for: the dates (and `date_field`) as you sent them, and the `columns` you chose, without repeats, with `schema_version`. Null for customer and product exports sent without `columns`.","properties":{"columns":{"description":"Only when you chose columns.","items":{"type":"string"},"type":"array"},"date_field":{"description":"Sales order exports only.","type":"string"},"end_date":{"type":"string"},"schema_version":{"description":"Only when you chose columns.","type":"integer"},"start_date":{"type":"string"}},"type":["object","null"]},"created_at":{"format":"date-time","type":"string"},"created_by":{"description":"A plain number for the person who created it. It is not a hash id and no operation takes it; show `creator.name` instead.","type":["integer","null"]},"creator":{"additionalProperties":true,"description":"The person who created it; null if their account was deleted. More of their account fields may appear; rely only on these.","properties":{"email":{"type":"string"},"id":{"description":"The same plain number as `created_by`, not a hash id.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]},"error_code":{"description":"Why it failed. `export_generation_failed`: the file could not be built; create a new export. `export_attempt_expired`: it did not finish in time. `export_queue_failed`: it could not be queued. Null unless `status` is `failed`.","enum":["export_generation_failed","export_attempt_expired","export_queue_failed",null],"type":["string","null"]},"expires_at":{"description":"When the download stops working: 3 days after the export became ready. The file is then deleted; the export stays in the list but can't be downloaded.","format":"date-time","type":["string","null"]},"file_size":{"description":"File size in bytes, once ready.","type":["integer","null"]},"id":{"description":"The export id. Use it to poll and to download.","type":"string"},"progress":{"properties":{"completed":{"description":"Rows written so far, not counting the header row. Updated every 500 rows; product exports update only at the end.","type":"integer"},"total":{"description":"Rows in the file, not counting the header row. Null until the export is ready: there is no total to show a percentage against while it runs.","type":["integer","null"]}},"required":["completed","total"],"type":"object"},"status":{"description":"`pending`: queued. `generating`: running. `ready`: the file can be downloaded. `failed`: see `error_code`.","enum":["pending","generating","ready","failed"],"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","config","status","created_at","updated_at","created_by","creator","progress","file_size","expires_at","error_code"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"429":{"content":{"application/json":{"example":{"error":{"code":"export_capacity","message":"Your team already has several exports in progress. Please try again when one has finished."},"status":429,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Your team already has 3 exports pending or generating."},"503":{"content":{"application/json":{"example":{"error":{"code":"export_creation_paused","message":"Exports are paused for a few minutes while we update YoPrint. Try again shortly."},"status":503,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Exports are paused for a few minutes during a YoPrint update, or the export could not be queued (`export_queue_failed`, \"The export could not be queued. Try again.\").","headers":{"Retry-After":{"description":"Seconds to wait (120) when exports are paused.","schema":{"type":"integer"}}}}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Export the tax report for a date range to CSV","tags":["Data exports"],"x-yoprint-docs":{"errors":[{"fix":"Send both dates, with `end_date` on or after `start_date`, and for sales orders a `date_field` from the list.","status":422,"when":"Dates are missing, not dates, or out of order, or, for sales orders, `date_field` is missing or not one of the six (`invalid_export_request`, \"Choose valid, ordered export dates and a supported date field.\")."},{"fix":"Use ids from the definitions operation, or omit `columns`.","status":422,"when":"A column id is unknown, `columns` is not a list, or it is empty (`invalid_export_request`, \"The selected export columns are invalid.\" or \"Select at least one export column.\")."},{"fix":"Send a string of up to 100 characters, or leave it out.","status":422,"when":"`idempotency_key` is not a string or is longer than 100 characters (`invalid_export_request`, \"The export request key is invalid.\")."},{"fix":"Poll the running export and download it instead, or wait until it finishes.","status":422,"when":"An export of this type is already pending or generating for your team (`duplicate_report`, \"There is already a report being generated. Please wait until the report is fully generated\")."},{"fix":"Use a new key for a new export.","status":422,"when":"The `idempotency_key` was used for a different export, or by another member (`invalid_export_request`, \"This request key was already used for a different export.\")."},{"fix":"Wait for one to finish, then try again.","status":429,"when":"Three exports are already pending or generating (`export_capacity`)."},{"fix":"When paused, wait the `Retry-After` seconds and send the request again. After a queue failure, send it again with the same `idempotency_key` to queue the same export.","status":503,"when":"Exports are paused during an update (`export_creation_paused`, with `Retry-After: 120`), even for a retry with the same key; or the export could not be queued (`export_queue_failed`, no `Retry-After`)."}],"group":"Imports and exports","notes":["The range is inclusive at both ends and is compared in UTC, with times. To cover whole days in your team's time zone, convert its midnights to UTC, or send the offset: `2026-10-01T00:00:00-07:00` to `2026-10-31T23:59:59.999-07:00`. There is no maximum range.","Amounts in the file are decimal strings with 2 decimal places and no currency symbol, such as `125.00`. In invoice and tax exports (`invoice_list`, `tax_list`), `tax_percentage` is a percentage as a decimal string (`8.25`, `0`), empty when the invoice has no single tax rate (for example a fixed tax amount). In sales order, invoice, and tax exports (`sales_order_list`, `invoice_list`, `tax_list`), the `paid` column is `TRUE` or `FALSE`.","Dates in the file are `YYYY-MM-DD`, in your team's time zone.","To be included in a tax export, an order must meet all four conditions:","- Fully paid: paid amount meets or exceeds the total (partial payments are excluded).","- Current invoice format: older legacy invoices are not included.","- The export date range covers the order's last transaction day in UTC. If any transaction (including customer credit) was recorded on a later UTC day, earlier transactions do not qualify.","- That last UTC day contains a payment, a refund, or Customer Portal checkout credit applied to the order. An order is excluded from all tax exports if its final UTC transaction day has only non-portal customer credit applied.","The full flow: create the export, poll `GET /v1/api/store/{team_slug}/data_export/{id}` every few seconds until `status` is `ready` (or `failed`), then download the file with `GET /v1/api/store/{team_slug}/data_export/{id}/download` within 3 days.","Retrying with the same `idempotency_key` returns the same export and starts nothing new while it is `pending`, `generating`, `ready`, or failed with `export_generation_failed` (send a new key to try that one again). After `export_queue_failed` or `export_attempt_expired`, the same key queues the same export again, and the one-per-type (422 `duplicate_report`) and three-per-team (429 `export_capacity`) limits apply.","The file is CSV, UTF-8 with a byte order mark. Its first row holds the column ids, such as `order_id` (not the labels), in the order of `columns` or, without it, the default order. An export with no matching records has only that row."],"permission":"Any member of the team. Exports do not check the role: every member can export every type, including sales orders, invoices, payments and tax, even a member whose role can't see them in the web app.","related":["v1_public_data_export_show","v1_public_data_export_download","v1_public_data_export_definitions","v1_public_data_export_export_invoice","v1_public_data_export_export_payment_list"],"rules":["`start_date` and `end_date` are required, and `end_date` can't be before `start_date`. There is no maximum range. There is no `date_field`: the range is matched against the payments and refunds (and credit from Customer Portal payments applied to the order) recorded on the order's last transaction day.","One export of each type at a time for the whole team: while one is `pending` or `generating`, creating another of the same type is a 422 (`duplicate_report`).","At most 3 exports pending or generating per team, of any type. A fourth is a 429 (`export_capacity`).","`columns`, when sent, must be a non-empty list of column ids for this type. `GET /v1/api/store/{team_slug}/data_export/definitions` lists them with their labels.","`idempotency_key`, when sent, must be a string of at most 100 characters. Reusing a key with a different type, different settings or another person is a 422."],"side_effects":["Queues the export and returns it at once with `status` `pending`. The file is built in the background.","People with the Download Center open see it appear and update live. No email is sent.","The file is kept for 3 days after it is ready, then deleted. The export stays in the list as history."]}}},"/v1/api/store/{team_slug}/data_export/export_variant_product_list":{"post":{"description":"Starts a CSV export of your team's custom variant products, one row per variant (size and color). Deleted products and variants are left out. It runs in the background: the response is the new export with `status` `pending`.\n\nThe columns match the variant product CSV template, plus `status`, the variant's sales status: `On sale` or `Phased out`. `price` is a decimal string with at least 2 decimal places (`5.20`); parse it as a decimal. A zero price is left empty. Send no body for every column, or `columns` to choose them.","operationId":"v1_public_data_export_export_variant_product_list","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"columns":["supplier_style_code","title","size_label","color_label","price"],"idempotency_key":"export-variant-product-list-1"},"schema":{"properties":{"columns":{"description":"The columns to include, in the order you want them in the file. Omit it for every column in the default order. Repeats are dropped.","items":{"enum":["supplier_style_code","title","brand","description","supplier_code","price","weight","size_id","size_label","color_id","color_label","color_hex","status"],"type":"string"},"minItems":1,"type":"array","uniqueItems":true},"idempotency_key":{"description":"Optional, a string of up to 100 characters. Send the same key to retry the same request safely: you get the export it created, and nothing new starts while that export is `pending`, `generating`, `ready`, or failed with `export_generation_failed`. If it failed with `export_queue_failed` or `export_attempt_expired`, the same key queues it again. Keys are shared by the whole team.","maxLength":100,"type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":{"config":{"columns":["supplier_style_code","title","size_label","color_label","price"],"schema_version":1},"created_at":"2026-11-03T09:30:00+00:00","created_by":1001,"creator":{"email":"alex@example.com","id":1001,"name":"Alex Rivera"},"error_code":null,"expires_at":null,"file_size":null,"id":"G59hl28azOL22k","progress":{"completed":0,"total":null},"status":"pending","type":"variant_product_list","updated_at":"2026-11-03T09:30:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"config":{"description":"What you asked for: the dates (and `date_field`) as you sent them, and the `columns` you chose, without repeats, with `schema_version`. Null for customer and product exports sent without `columns`.","properties":{"columns":{"description":"Only when you chose columns.","items":{"type":"string"},"type":"array"},"date_field":{"description":"Sales order exports only.","type":"string"},"end_date":{"type":"string"},"schema_version":{"description":"Only when you chose columns.","type":"integer"},"start_date":{"type":"string"}},"type":["object","null"]},"created_at":{"format":"date-time","type":"string"},"created_by":{"description":"A plain number for the person who created it. It is not a hash id and no operation takes it; show `creator.name` instead.","type":["integer","null"]},"creator":{"additionalProperties":true,"description":"The person who created it; null if their account was deleted. More of their account fields may appear; rely only on these.","properties":{"email":{"type":"string"},"id":{"description":"The same plain number as `created_by`, not a hash id.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]},"error_code":{"description":"Why it failed. `export_generation_failed`: the file could not be built; create a new export. `export_attempt_expired`: it did not finish in time. `export_queue_failed`: it could not be queued. Null unless `status` is `failed`.","enum":["export_generation_failed","export_attempt_expired","export_queue_failed",null],"type":["string","null"]},"expires_at":{"description":"When the download stops working: 3 days after the export became ready. The file is then deleted; the export stays in the list but can't be downloaded.","format":"date-time","type":["string","null"]},"file_size":{"description":"File size in bytes, once ready.","type":["integer","null"]},"id":{"description":"The export id. Use it to poll and to download.","type":"string"},"progress":{"properties":{"completed":{"description":"Rows written so far, not counting the header row. Updated every 500 rows; product exports update only at the end.","type":"integer"},"total":{"description":"Rows in the file, not counting the header row. Null until the export is ready: there is no total to show a percentage against while it runs.","type":["integer","null"]}},"required":["completed","total"],"type":"object"},"status":{"description":"`pending`: queued. `generating`: running. `ready`: the file can be downloaded. `failed`: see `error_code`.","enum":["pending","generating","ready","failed"],"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","config","status","created_at","updated_at","created_by","creator","progress","file_size","expires_at","error_code"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"429":{"content":{"application/json":{"example":{"error":{"code":"export_capacity","message":"Your team already has several exports in progress. Please try again when one has finished."},"status":429,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Your team already has 3 exports pending or generating."},"503":{"content":{"application/json":{"example":{"error":{"code":"export_creation_paused","message":"Exports are paused for a few minutes while we update YoPrint. Try again shortly."},"status":503,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Exports are paused for a few minutes during a YoPrint update, or the export could not be queued (`export_queue_failed`, \"The export could not be queued. Try again.\").","headers":{"Retry-After":{"description":"Seconds to wait (120) when exports are paused.","schema":{"type":"integer"}}}}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Export all variant products to CSV","tags":["Data exports"],"x-yoprint-docs":{"errors":[{"fix":"Use ids from the definitions operation, or omit `columns`.","status":422,"when":"A column id is unknown, `columns` is not a list, or it is empty (`invalid_export_request`, \"The selected export columns are invalid.\" or \"Select at least one export column.\")."},{"fix":"Send a string of up to 100 characters, or leave it out.","status":422,"when":"`idempotency_key` is not a string or is longer than 100 characters (`invalid_export_request`, \"The export request key is invalid.\")."},{"fix":"Poll the running export and download it instead, or wait until it finishes.","status":422,"when":"An export of this type is already pending or generating for your team (`duplicate_report`, \"There is already a report being generated. Please wait until the report is fully generated\")."},{"fix":"Use a new key for a new export.","status":422,"when":"The `idempotency_key` was used for a different export, or by another member (`invalid_export_request`, \"This request key was already used for a different export.\")."},{"fix":"Wait for one to finish, then try again.","status":429,"when":"Three exports are already pending or generating (`export_capacity`)."},{"fix":"When paused, wait the `Retry-After` seconds and send the request again. After a queue failure, send it again with the same `idempotency_key` to queue the same export.","status":503,"when":"Exports are paused during an update (`export_creation_paused`, with `Retry-After: 120`), even for a retry with the same key; or the export could not be queued (`export_queue_failed`, no `Retry-After`)."}],"group":"Imports and exports","notes":["The full flow: create the export, poll `GET /v1/api/store/{team_slug}/data_export/{id}` every few seconds until `status` is `ready` (or `failed`), then download the file with `GET /v1/api/store/{team_slug}/data_export/{id}/download` within 3 days.","Retrying with the same `idempotency_key` returns the same export and starts nothing new while it is `pending`, `generating`, `ready`, or failed with `export_generation_failed` (send a new key to try that one again). After `export_queue_failed` or `export_attempt_expired`, the same key queues the same export again, and the one-per-type (422 `duplicate_report`) and three-per-team (429 `export_capacity`) limits apply.","The file is CSV, UTF-8 with a byte order mark. Its first row holds the column ids, such as `order_id` (not the labels), in the order of `columns` or, without it, the default order. An export with no matching records has only that row.","`progress.completed` stays 0 until a product export is ready."],"permission":"Any member of the team. Exports do not check the role: every member can export every type, including sales orders, invoices, payments and tax, even a member whose role can't see them in the web app.","related":["v1_public_data_export_show","v1_public_data_export_download","v1_public_data_export_definitions","v1_public_data_export_export_simple_product_list"],"rules":["One export of each type at a time for the whole team: while one is `pending` or `generating`, creating another of the same type is a 422 (`duplicate_report`).","At most 3 exports pending or generating per team, of any type. A fourth is a 429 (`export_capacity`).","`columns`, when sent, must be a non-empty list of column ids for this type. `GET /v1/api/store/{team_slug}/data_export/definitions` lists them with their labels.","`idempotency_key`, when sent, must be a string of at most 100 characters. Reusing a key with a different type, different settings or another person is a 422."],"side_effects":["Queues the export and returns it at once with `status` `pending`. The file is built in the background.","People with the Download Center open see it appear and update live. No email is sent.","The file is kept for 3 days after it is ready, then deleted. The export stays in the list as history."]}}},"/v1/api/store/{team_slug}/data_export/presets":{"get":{"description":"Lists the saved column choices (presets) you can use: the team's shared presets, and your own personal ones. Other members' personal presets are not shown. Sorted by type, then name; not paged.\n\nA preset only stores `columns`. To use one, send its `config.columns` as `columns` when you create an export.","operationId":"v1_public_data_export_presets","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"config":{"columns":["invoice_id","customer_name","total","tax"],"schema_version":1},"id":"ZUFZpcm8jcw4J0","is_team_default":false,"name":"Accounting","type":"invoice_list","user_id":"VG7s3tFzyQbO2N"},{"config":{"columns":["invoice_id","order_id","total","paid_amount","balance_due"],"schema_version":1},"id":"cDHnZCTddDiS2c","is_team_default":true,"name":"Month end","type":"invoice_list","user_id":null}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"config":{"properties":{"columns":{"description":"Column ids, in file order. Send them as `columns` when you create an export.","items":{"type":"string"},"type":"array"},"schema_version":{"description":"Version of the column list (1).","type":"integer"}},"type":"object"},"id":{"description":"The preset id. Use it to delete the preset.","type":"string"},"is_team_default":{"description":"The team's default preset for this type. At most one per type.","type":"boolean"},"name":{"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"},"user_id":{"description":"Your user id (a hash id) for a personal preset; null for a shared team preset.","type":["string","null"]}},"required":["id","name","type","config","is_team_default","user_id"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List export column presets","tags":["Data exports"],"x-yoprint-docs":{"group":"Imports and exports","permission":"Any member of the team.","related":["v1_public_data_export_presets_store","v1_public_data_export_presets_delete"]}},"post":{"description":"Saves a named set of columns for one export type. By default it is a personal preset that only you see. The team owner can save it as the team default (`is_team_default: true`), which is shared with everyone and replaces the previous default for that type.\n\nPresets can't be edited: delete one and save it again.","operationId":"v1_public_data_export_presets_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"columns":["invoice_id","customer_name","total","tax"],"is_team_default":false,"name":"Accounting","type":"invoice_list"},"schema":{"properties":{"columns":{"description":"Column ids for this type, in file order. Repeats are dropped. See the definitions operation.","items":{"type":"string"},"minItems":1,"type":"array"},"is_team_default":{"default":false,"description":"Team owner only. Shares the preset with the team as the default for this type.","type":"boolean"},"name":{"description":"Spaces at either end are removed.","maxLength":120,"minLength":1,"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"}},"required":["name","type","columns"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"data":{"config":{"columns":["invoice_id","customer_name","total","tax"],"schema_version":1},"id":"ZUFZpcm8jcw4J0","is_team_default":false,"name":"Accounting","type":"invoice_list","user_id":"VG7s3tFzyQbO2N"},"status":201,"success":true},"schema":{"properties":{"data":{"properties":{"config":{"properties":{"columns":{"description":"Column ids, in file order. Send them as `columns` when you create an export.","items":{"type":"string"},"type":"array"},"schema_version":{"description":"Version of the column list (1).","type":"integer"}},"type":"object"},"id":{"description":"The preset id. Use it to delete the preset.","type":"string"},"is_team_default":{"description":"The team's default preset for this type. At most one per type.","type":"boolean"},"name":{"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"},"user_id":{"description":"Your user id (a hash id) for a personal preset; null for a shared team preset.","type":["string","null"]}},"required":["id","name","type","config","is_team_default","user_id"],"type":"object"},"status":{"example":201,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"content":{"application/json":{"example":{"error":{"code":"team_default_forbidden","message":"Only the team owner can set a team default."},"status":403,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"You are not the team owner and sent `is_team_default: true`."},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Save an export column preset","tags":["Data exports"],"x-yoprint-docs":{"errors":[{"fix":"Send a `name` of 1 to 120 characters, a `type`, and `is_team_default` as `true` or `false` or not at all.","status":422,"when":"`name` is missing, blank, not a string or over 120 characters; `type` is missing or not a string; or `is_team_default` is not a boolean (`invalid_export_request`, \"Enter a valid preset name, export type and default setting.\")."},{"fix":"Send `columns` as a list of column ids.","status":422,"when":"`columns` is missing or not a list (`invalid_export_request`, \"The selected export columns are invalid.\")."},{"fix":"Use a type the definitions operation lists.","status":422,"when":"`type` is not one of the nine export types (`invalid_export_request`, \"Unsupported export type.\")."},{"fix":"Use column ids the definitions operation lists for this type.","status":422,"when":"A column id is not one of this type's columns, or is not a string (`invalid_export_request`, \"The selected export columns are invalid.\"), or `columns` is empty (\"Select at least one export column.\")."},{"fix":"Save it as a personal preset, or ask the team owner.","status":403,"when":"You are not the team owner and sent `is_team_default: true` (`team_default_forbidden`, \"Only the team owner can set a team default.\")."}],"group":"Imports and exports","notes":["Each refusal names the first problem only. The checks run in the order of the errors above: name, type and default setting; `columns` is a list; `type` is known; the column ids; and only then the team owner check.","These 422 answers have no `error.fields`: the problem is in `error.message`, for example `{\"status\": 422, \"success\": false, \"error\": {\"code\": \"invalid_export_request\", \"message\": \"Unsupported export type.\"}}`."],"permission":"Any member for a personal preset. Only the team owner can save a team default.","related":["v1_public_data_export_presets","v1_public_data_export_definitions"],"rules":["`name` is required, up to 120 characters, and not blank. Names don't have to be unique.","`type` must be one of the nine export types, and `columns` a non-empty list of that type's column ids.","Saving a team default turns off `is_team_default` on the type's previous default. That preset stays shared."]}}},"/v1/api/store/{team_slug}/data_export/presets/{presetId}":{"delete":{"description":"Deletes a preset for good. You can delete your own personal presets. Only the team owner can delete a shared team preset. Answers `204` with an empty body.","operationId":"v1_public_data_export_presets_delete","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The preset's `id`, from the presets list.","example":"ZUFZpcm8jcw4J0","in":"path","name":"presetId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted. The body is empty."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"content":{"application/json":{"example":{"error":{"code":"team_default_forbidden","message":"Only the team owner can remove a shared preset."},"status":403,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"A shared preset and you are not the team owner (`team_default_forbidden`), or another member's personal preset (`preset_forbidden`, \"You can only remove your own presets.\")."},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete an export column preset","tags":["Data exports"],"x-yoprint-docs":{"errors":[{"fix":"Delete only your own presets, or ask the team owner.","status":403,"when":"It is a shared preset and you are not the team owner (`team_default_forbidden`, \"Only the team owner can remove a shared preset.\"), or it is another member's personal preset (`preset_forbidden`, \"You can only remove your own presets.\")."},{"fix":"Use an `id` from the presets list.","status":404,"when":"No preset of this team has this id."}],"group":"Imports and exports","notes":["The team owner can't delete another member's personal preset either."],"permission":"Your own personal presets: you. Shared team presets: the team owner only.","related":["v1_public_data_export_presets"]}}},"/v1/api/store/{team_slug}/data_export/{id}":{"get":{"description":"Returns one export. Poll it after you create an export: when `status` is `ready`, download the file; when it is `failed`, `error_code` says why.\n\n`pending` and `generating` mean it is still running. `progress.completed` counts rows written so far.","operationId":"v1_public_data_export_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The export's `id`, from the create answer. A hash id; unique keys and document numbers are refused with 404.","example":"G59hl28azOL22k","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"config":{"date_field":"issue_date","end_date":"2026-10-31T23:59:59.999Z","start_date":"2026-10-01T00:00:00Z"},"created_at":"2026-11-03T09:30:00+00:00","created_by":1001,"creator":{"email":"alex@example.com","id":1001,"name":"Alex Rivera"},"error_code":null,"expires_at":"2026-11-06T09:30:40+00:00","file_size":482113,"id":"G59hl28azOL22k","progress":{"completed":1250,"total":1250},"status":"ready","type":"sales_order_list","updated_at":"2026-11-03T09:30:40+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"config":{"description":"What you asked for: the dates (and `date_field`) as you sent them, and the `columns` you chose, without repeats, with `schema_version`. Null for customer and product exports sent without `columns`.","properties":{"columns":{"description":"Only when you chose columns.","items":{"type":"string"},"type":"array"},"date_field":{"description":"Sales order exports only.","type":"string"},"end_date":{"type":"string"},"schema_version":{"description":"Only when you chose columns.","type":"integer"},"start_date":{"type":"string"}},"type":["object","null"]},"created_at":{"format":"date-time","type":"string"},"created_by":{"description":"A plain number for the person who created it. It is not a hash id and no operation takes it; show `creator.name` instead.","type":["integer","null"]},"creator":{"additionalProperties":true,"description":"The person who created it; null if their account was deleted. More of their account fields may appear; rely only on these.","properties":{"email":{"type":"string"},"id":{"description":"The same plain number as `created_by`, not a hash id.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]},"error_code":{"description":"Why it failed. `export_generation_failed`: the file could not be built; create a new export. `export_attempt_expired`: it did not finish in time. `export_queue_failed`: it could not be queued. Null unless `status` is `failed`.","enum":["export_generation_failed","export_attempt_expired","export_queue_failed",null],"type":["string","null"]},"expires_at":{"description":"When the download stops working: 3 days after the export became ready. The file is then deleted; the export stays in the list but can't be downloaded.","format":"date-time","type":["string","null"]},"file_size":{"description":"File size in bytes, once ready.","type":["integer","null"]},"id":{"description":"The export id. Use it to poll and to download.","type":"string"},"progress":{"properties":{"completed":{"description":"Rows written so far, not counting the header row. Updated every 500 rows; product exports update only at the end.","type":"integer"},"total":{"description":"Rows in the file, not counting the header row. Null until the export is ready: there is no total to show a percentage against while it runs.","type":["integer","null"]}},"required":["completed","total"],"type":"object"},"status":{"description":"`pending`: queued. `generating`: running. `ready`: the file can be downloaded. `failed`: see `error_code`.","enum":["pending","generating","ready","failed"],"type":"string"},"type":{"enum":["customer_list","sales_order_list","invoice_list","invoice_item_list","payment_list","purchase_order_list","tax_list","simple_product_list","variant_product_list"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","config","status","created_at","updated_at","created_by","creator","progress","file_size","expires_at","error_code"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a data export","tags":["Data exports"],"x-yoprint-docs":{"errors":[{"fix":"Use the `id` the create operation returned.","status":404,"when":"The id is not one of this team's exports."}],"group":"Imports and exports","notes":["An export still `pending` or `generating` about an hour after it was queued is marked `failed` with `export_attempt_expired` the next time YoPrint checks: when someone on your team creates an export, or at the regular cleanup. Create it again (the same `idempotency_key` queues the same export again); a smaller date range or fewer columns finishes sooner."],"permission":"Any member of the team, for any of the team's exports.","related":["v1_public_data_export_download","v1_public_data_export_index"]}}},"/v1/api/store/{team_slug}/data_export/{id}/download":{"get":{"description":"Sends the export's CSV file itself, not JSON and not a link. The file is named `yoprint_<type>_export-<YYYY-MM-DD>.csv`, with the date (UTC) the export was created (in `Content-Disposition`).\n\nIt works only while the export is `ready` and not expired, which is 3 days after it became ready. You can download it as many times as you like in that time.\n\nSave the answer to a file. The `Accept: application/json` header every request sends is fine here: the file still comes back as CSV.\n\n```bash\ncurl -o export.csv -H \"Authorization: Bearer YOUR_API_KEY\" -H \"Accept: application/json\" \\\n  https://secure.yoprint.com/v1/api/store/your-team/data_export/G59hl28azOL22k/download\n```","operationId":"v1_public_data_export_download","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The export's `id`, from the create answer. A hash id; unique keys and document numbers are refused with 404.","example":"G59hl28azOL22k","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}},"description":"Binary download response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download a data export's file","tags":["Data exports"],"x-yoprint-docs":{"errors":[{"fix":"Read the export first: download only when `status` is `ready` and `expires_at` is in the future. If it expired, create a new export.","status":404,"when":"The export is not ready yet, failed, expired, or its file was removed. All of these answer the same 404 (`page_not_found`)."},{"fix":"Use the `id` the create operation returned.","status":404,"when":"The id is not one of this team's exports."}],"group":"Imports and exports","notes":["The response has `Cache-Control: private, no-store`. Save the file; do not rely on caches.","The file is UTF-8 with a byte order mark, so spreadsheet apps read accents correctly. Strip the first three bytes if your CSV reader does not expect it."],"permission":"Any member of the team, for any of the team's exports.","related":["v1_public_data_export_show"]}}},"/v1/api/store/{team_slug}/decode_barcode":{"post":{"description":"Turns the text of a barcode or QR code printed by YoPrint on a work order, packing slip, label or purchase order into the record it points to: its type and id. Use it in a scanner app.\n\nYoPrint codes look like `y9-0p-<kind>-<number>`, where kind is `ord` (sales order or quote), `po` (purchase order), `ship` (shipment), `job` (job) or `ta` (stock transfer). For a job or shipment, `parent` is its order.","operationId":"v1_public_misc_decode_barcode","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"value":"y9-0p-job-1234"},"schema":{"properties":{"value":{"description":"The scanned text, starting with `y9-0p-`.","pattern":"^y9-0p-","type":"string"}},"required":["value"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"id":"K6iF8n29iwOZnj","parent":{"id":"V4keXwwxMQyXw7","object_type":"sales_order","type":"sales_order"},"type":"job"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"id":{"description":"The record's id.","type":"string"},"object_type":{"description":"Quotes only: `quote`.","type":"string"},"parent":{"description":"Jobs and shipments: the order they belong to.","properties":{"id":{"type":"string"},"object_type":{"type":"string"},"type":{"enum":["sales_order","quote"],"type":"string"}},"type":"object"},"type":{"enum":["sales_order","quote","purchase_order","shipment","job","transfer_adjustment"],"type":"string"}},"required":["type","id"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Decode a YoPrint barcode","tags":["Barcodes"],"x-yoprint-docs":{"errors":[{"fix":"Send the scanned text exactly as read. It is not a YoPrint code otherwise.","status":422,"when":"`value` is missing or does not start with `y9-0p-` (`validation_failed`; `error.fields` names the field)."},{"fix":"Check you are using the right team. A deleted record can't be scanned.","status":404,"when":"The kind is unknown, or the record does not exist on this team or was deleted. The error has no code or message."}],"group":"Production","notes":["The number in the code is not the id the API uses. Always decode it here instead of building ids yourself."],"permission":"Any member of the team. It does not check whether you can view the record.","rules":["`value` is required and must start with `y9-0p-`."]}}},"/v1/api/store/{team_slug}/external_integration_logs/order/{hash_id}":{"get":{"description":"Lists the newest QuickBooks Online and Shopify sync errors recorded for a sales order or quote, at most 10. Use `type` to see only one integration's errors.\n\nSome QuickBooks errors include the details QuickBooks sent in `error_payload`; errors about a QuickBooks Payment also name it in `quickbooks_payment_id`, with QuickBooks' own words in `quickbooks_message`. Shopify errors come with words to show people: `display_title`, `display_message` and `display_next_step`. Every log names its order in `order`.","operationId":"v1_public_external_integration_logs_order","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id`. A hash id; unique keys and document numbers are refused with 404.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}},{"description":"Only this integration's errors. `shopify`: the four `shopify_*` types. `qbo`: `qbo_bootstrap_error` (the sync could not start), `qbo_sync_endpoint_error`, `qbo_sync_internal_error`, `qbo_sync_transform_error`, `qbo_sync_lookup_error` and the older `qbo_order_sync_error`; it leaves out the older `qbo_order_payment_sync_error`. Leave it out for every type.","in":"query","name":"type","required":false,"schema":{"enum":["shopify","qbo"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"created_at":"2026-11-03T09:30:00+00:00","error_code":"6240","error_message":"(Invoice) Duplicate Name Exists Error","error_payload":"The name supplied already exists.","helpscout_article_id":null,"id":"cD67OPTEAMlQ96","order":{"deleted":false,"id":"V4keXwwxMQyXw7","scoped_id":"SO1001","type":"sales_order"},"quickbooks_message":null,"quickbooks_payment_id":null,"retryable":false,"type":"qbo_sync_endpoint_error"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"display_message":{"type":"string"},"display_next_step":{"type":"string"},"display_reference":{"description":"The log's `id`, for support.","type":"string"},"display_title":{"description":"Shopify logs only: a title, message, next step and reference to show people.","type":"string"},"display_variant":{"enum":["error","warning"],"type":"string"},"error_code":{"description":"QuickBooks' error code, or for a Shopify fulfillment conflict the kind of conflict, such as `tracking_mismatch`.","type":["string","null"]},"error_message":{"description":"QuickBooks logs: the message with what was syncing in front, such as `(Invoice) Duplicate Name Exists Error`. Shopify logs: the same text as `display_message`.","type":["string","null"]},"error_payload":{"description":"Some QuickBooks Online logs: the details QuickBooks sent (text or an object). Otherwise null, and always null for Shopify logs."},"external_integration":{"additionalProperties":true,"description":"Only with `with=external_integration`: the integration the log came from (`id`, `type`, `subtype`, `label`, `status` and more).","type":["object","null"]},"helpscout_article_id":{"description":"Always null: no log type links a help article.","type":["string","null"]},"id":{"type":"string"},"order":{"additionalProperties":false,"description":"The sales order or quote the log is about; null when it is not about one.","properties":{"deleted":{"description":"True when the order has been deleted.","type":"boolean"},"id":{"description":"The order's id, for the order operations.","type":"string"},"scoped_id":{"description":"The order or quote number people see, such as `SO1001`. Not an id.","type":"string"},"type":{"enum":["sales_order","quote"],"type":"string"}},"required":["id","scoped_id","type","deleted"],"type":["object","null"]},"quickbooks_message":{"description":"QuickBooks' own words for the refusal, when the log kept them. Null otherwise.","type":["string","null"]},"quickbooks_payment_id":{"description":"The QuickBooks Payment's Id, when the log is about one (for example QuickBooks refused to delete it, or its sync is held). Null otherwise.","type":["string","null"]},"retryable":{"type":"boolean"},"shipment_id":{"description":"Only when the log is about a shipment: the shipment's id.","type":"string"},"shopify_admin_url":{"description":"Only when the log has one, such as a fulfillment conflict: the order in the Shopify admin.","type":"string"},"type":{"description":"QuickBooks Online: `qbo_sync_endpoint_error` (QuickBooks refused the record), `qbo_sync_internal_error`, `qbo_sync_transform_error`, `qbo_sync_lookup_error`, `qbo_bootstrap_error` (the sync could not start, for example because QuickBooks must be reconnected); older logs can have `qbo_order_sync_error`, `qbo_po_sync_error` and other `qbo_*_sync_error` types. Shopify: `shopify_endpoint_error`, `shopify_processing_error`, `shopify_internal_error`, `shopify_fulfillment_conflict`.","type":"string"}},"type":"object"},"maxItems":10,"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a sales order's integration errors","tags":["Integration logs"],"x-yoprint-docs":{"errors":[{"fix":"Use the order's `id`, not its unique key or number.","status":404,"when":"The id is not a valid id for this team."},{"fix":"Send `shopify`, `qbo`, or nothing.","status":422,"when":"`type` is not `shopify` or `qbo` (`validation_failed`; `error.fields` names the field)."}],"group":"Team settings","notes":["At most the 10 newest logs, newest first, with no paging.","An id that decodes but matches nothing returns an empty list, not 404.","Add `?with=external_integration` to include the integration each log came from."],"permission":"Any member of the team.","related":["v1_public_external_integration_logs_purchase_order","v1_public_external_integration_logs_shipment"]}}},"/v1/api/store/{team_slug}/external_integration_logs/purchase_order/{hash_id}":{"get":{"description":"Lists the newest sync errors recorded for a purchase order, at most 10: mostly QuickBooks Online purchase order and vendor sync errors.","operationId":"v1_public_external_integration_logs_purchase_order","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The purchase order's `id`. A hash id; unique keys and document numbers are refused with 404.","example":"WHxaO1cQCiDr0P","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"created_at":"2026-11-03T09:30:00+00:00","error_code":"6240","error_message":"(Bill) Duplicate Name Exists Error","error_payload":"The name supplied already exists.","helpscout_article_id":null,"id":"6lSV8aMrZ8OhH8","order":null,"quickbooks_message":null,"quickbooks_payment_id":null,"retryable":false,"type":"qbo_sync_endpoint_error"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"display_message":{"type":"string"},"display_next_step":{"type":"string"},"display_reference":{"description":"The log's `id`, for support.","type":"string"},"display_title":{"description":"Shopify logs only: a title, message, next step and reference to show people.","type":"string"},"display_variant":{"enum":["error","warning"],"type":"string"},"error_code":{"description":"QuickBooks' error code, or for a Shopify fulfillment conflict the kind of conflict, such as `tracking_mismatch`.","type":["string","null"]},"error_message":{"description":"QuickBooks logs: the message with what was syncing in front, such as `(Invoice) Duplicate Name Exists Error`. Shopify logs: the same text as `display_message`.","type":["string","null"]},"error_payload":{"description":"Some QuickBooks Online logs: the details QuickBooks sent (text or an object). Otherwise null, and always null for Shopify logs."},"external_integration":{"additionalProperties":true,"description":"Only with `with=external_integration`: the integration the log came from (`id`, `type`, `subtype`, `label`, `status` and more).","type":["object","null"]},"helpscout_article_id":{"description":"Always null: no log type links a help article.","type":["string","null"]},"id":{"type":"string"},"order":{"additionalProperties":false,"description":"The sales order or quote the log is about; null when it is not about one.","properties":{"deleted":{"description":"True when the order has been deleted.","type":"boolean"},"id":{"description":"The order's id, for the order operations.","type":"string"},"scoped_id":{"description":"The order or quote number people see, such as `SO1001`. Not an id.","type":"string"},"type":{"enum":["sales_order","quote"],"type":"string"}},"required":["id","scoped_id","type","deleted"],"type":["object","null"]},"quickbooks_message":{"description":"QuickBooks' own words for the refusal, when the log kept them. Null otherwise.","type":["string","null"]},"quickbooks_payment_id":{"description":"The QuickBooks Payment's Id, when the log is about one (for example QuickBooks refused to delete it, or its sync is held). Null otherwise.","type":["string","null"]},"retryable":{"type":"boolean"},"shipment_id":{"description":"Only when the log is about a shipment: the shipment's id.","type":"string"},"shopify_admin_url":{"description":"Only when the log has one, such as a fulfillment conflict: the order in the Shopify admin.","type":"string"},"type":{"description":"QuickBooks Online: `qbo_sync_endpoint_error` (QuickBooks refused the record), `qbo_sync_internal_error`, `qbo_sync_transform_error`, `qbo_sync_lookup_error`, `qbo_bootstrap_error` (the sync could not start, for example because QuickBooks must be reconnected); older logs can have `qbo_order_sync_error`, `qbo_po_sync_error` and other `qbo_*_sync_error` types. Shopify: `shopify_endpoint_error`, `shopify_processing_error`, `shopify_internal_error`, `shopify_fulfillment_conflict`.","type":"string"}},"type":"object"},"maxItems":10,"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a purchase order's integration errors","tags":["Integration logs"],"x-yoprint-docs":{"errors":[{"fix":"Use the purchase order's `id`.","status":404,"when":"The id is not a valid id for this team."}],"group":"Team settings","notes":["At most the 10 newest logs, newest first, with no paging.","An id that decodes but matches nothing returns an empty list, not 404.","Add `?with=external_integration` to include the integration each log came from."],"permission":"Any member of the team.","related":["v1_public_external_integration_logs_order"]}}},"/v1/api/store/{team_slug}/external_integration_logs/shipment/{hash_id}":{"get":{"description":"Lists the newest sync errors recorded for a shipment, at most 10, such as Shopify fulfillment conflicts.","operationId":"v1_public_external_integration_logs_shipment","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's `id`. A hash id; unique keys and document numbers are refused with 404.","example":"1R5UAqv27Ln0FH","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"created_at":"2026-11-03T09:30:00+00:00","display_message":"The shipment tracking details in YoPrint do not match the fulfillment already recorded in Shopify.","display_next_step":"Review the shipment summary and Shopify fulfillment details before retrying.","display_reference":"GO7FnHrXOFVrg2","display_title":"Shipment tracking does not match Shopify","display_variant":"warning","error_code":"tracking_mismatch","error_message":"The shipment tracking details in YoPrint do not match the fulfillment already recorded in Shopify.","error_payload":null,"helpscout_article_id":null,"id":"GO7FnHrXOFVrg2","order":{"deleted":false,"id":"V4keXwwxMQyXw7","scoped_id":"SO1001","type":"sales_order"},"quickbooks_message":null,"quickbooks_payment_id":null,"retryable":false,"shipment_id":"1R5UAqv27Ln0FH","shopify_admin_url":"https://example.com/admin/orders/1001","type":"shopify_fulfillment_conflict"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"display_message":{"type":"string"},"display_next_step":{"type":"string"},"display_reference":{"description":"The log's `id`, for support.","type":"string"},"display_title":{"description":"Shopify logs only: a title, message, next step and reference to show people.","type":"string"},"display_variant":{"enum":["error","warning"],"type":"string"},"error_code":{"description":"QuickBooks' error code, or for a Shopify fulfillment conflict the kind of conflict, such as `tracking_mismatch`.","type":["string","null"]},"error_message":{"description":"QuickBooks logs: the message with what was syncing in front, such as `(Invoice) Duplicate Name Exists Error`. Shopify logs: the same text as `display_message`.","type":["string","null"]},"error_payload":{"description":"Some QuickBooks Online logs: the details QuickBooks sent (text or an object). Otherwise null, and always null for Shopify logs."},"external_integration":{"additionalProperties":true,"description":"Only with `with=external_integration`: the integration the log came from (`id`, `type`, `subtype`, `label`, `status` and more).","type":["object","null"]},"helpscout_article_id":{"description":"Always null: no log type links a help article.","type":["string","null"]},"id":{"type":"string"},"order":{"additionalProperties":false,"description":"The sales order or quote the log is about; null when it is not about one.","properties":{"deleted":{"description":"True when the order has been deleted.","type":"boolean"},"id":{"description":"The order's id, for the order operations.","type":"string"},"scoped_id":{"description":"The order or quote number people see, such as `SO1001`. Not an id.","type":"string"},"type":{"enum":["sales_order","quote"],"type":"string"}},"required":["id","scoped_id","type","deleted"],"type":["object","null"]},"quickbooks_message":{"description":"QuickBooks' own words for the refusal, when the log kept them. Null otherwise.","type":["string","null"]},"quickbooks_payment_id":{"description":"The QuickBooks Payment's Id, when the log is about one (for example QuickBooks refused to delete it, or its sync is held). Null otherwise.","type":["string","null"]},"retryable":{"type":"boolean"},"shipment_id":{"description":"Only when the log is about a shipment: the shipment's id.","type":"string"},"shopify_admin_url":{"description":"Only when the log has one, such as a fulfillment conflict: the order in the Shopify admin.","type":"string"},"type":{"description":"QuickBooks Online: `qbo_sync_endpoint_error` (QuickBooks refused the record), `qbo_sync_internal_error`, `qbo_sync_transform_error`, `qbo_sync_lookup_error`, `qbo_bootstrap_error` (the sync could not start, for example because QuickBooks must be reconnected); older logs can have `qbo_order_sync_error`, `qbo_po_sync_error` and other `qbo_*_sync_error` types. Shopify: `shopify_endpoint_error`, `shopify_processing_error`, `shopify_internal_error`, `shopify_fulfillment_conflict`.","type":"string"}},"type":"object"},"maxItems":10,"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a shipment's integration errors","tags":["Integration logs"],"x-yoprint-docs":{"errors":[{"fix":"Use the shipment's `id`.","status":404,"when":"The id is not a valid id for this team."}],"group":"Team settings","notes":["At most the 10 newest logs, newest first, with no paging.","An id that decodes but matches nothing returns an empty list, not 404.","Add `?with=external_integration` to include the integration each log came from."],"permission":"Any member of the team.","related":["v1_public_external_integration_logs_order"]}}},"/v1/api/store/{team_slug}/get_all_product_brands":{"get":{"description":"Returns every brand name in use: the brands of all supplier catalogs YoPrint carries, plus the brands of your own products (deleted ones included). For autocomplete. The answer is `{\"data\": [...]}` with no `success` or `status` fields, and may contain `null`.","operationId":"v1_public_product_brands_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":["Example Brand","Northwind"]},"schema":{"additionalProperties":false,"properties":{"data":{"items":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":"array"}},"required":["data"],"type":"object"}}},"description":"The names, in no set order. Only `data`: no `success` or `status`."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List all product brands","tags":["Products"],"x-yoprint-docs":{"group":"Products and catalog","notes":["The catalog part covers every supplier, not only the ones your team connected."],"permission":"Any member of the team.","related":["v1_public_product_sizes_index"]}}},"/v1/api/store/{team_slug}/get_all_product_sizes":{"get":{"description":"Returns every size name in use: the size names of your variant products (deleted variants included) plus every size name in the supplier catalogs YoPrint carries. For autocomplete. The answer is `{\"data\": [...]}` with no `success` or `status` fields.","operationId":"v1_public_product_sizes_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":["S","M","L","XL"]},"schema":{"additionalProperties":false,"properties":{"data":{"items":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":"array"}},"required":["data"],"type":"object"}}},"description":"The names, in no set order. Only `data`: no `success` or `status`."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List all size names","tags":["Products"],"x-yoprint-docs":{"group":"Products and catalog","permission":"Any member of the team.","related":["v1_public_product_brands_index"]}}},"/v1/api/store/{team_slug}/hydrate_product":{"post":{"description":"Returns a product with every option you can sell, in the shape sales order line pickers use: `size_data`, `color_data` and `attr_data` (one row per size and color combination). It is also how you get a supplier catalog style's size and color ids. Read-only.\n\nWhat `id` names depends on `type`. Your own simple product is `db_simple` here (and on stock levels), but `user_simple` on sales order lines.\n\n| `type` | `id` | What comes back |\n| --- | --- | --- |\n| `db_simple` or `custom` | One of your products | A simple product (`type: simple`) with its `price`, or a variant product (`type: variant`) with its live variants in `attr_data`. |\n| `db_variant` | One of your variants | Its whole parent product (`type: variant`). |\n| `db_catalog` | A catalog product id: one size and color, such as `ssa-B00000001` | Its whole catalog style (`type: variant_catalog`). |\n| `db_catalog_style` | A catalog style id, such as `ssa-5000` | The same style. |\n\n**A supplier catalog product, step by step**\n\n1. Start from a catalog id you have: the product id of an existing catalog sales order line (send it as `db_catalog`), or a style id (`db_catalog_style`). Catalog ids are the supplier code, a dash, then the supplier's own key. A style id ends in the supplier's style key: for SanMar (`smr`) that is the style number people see; other suppliers use their own key, which is not always the style number shown (S&S Activewear's is S&S's own style key; the style number people see comes back as `style_name`). The public API can't search the catalog by keyword.\n2. Call this operation. In `attr_data`, pick the row by `size_label` and `color_label`. Its `id` is the catalog product id and its `provider` is the supplier code.\n3. Get the supplier cost with Get live supplier pricing, sending that `id`.\n4. Add the line with Add a line item: `product.properties.id` is the row's `id` and `pricing.catalog.provider` is the row's `provider`.\n\nSupplier codes: `ssa` S&S Activewear, `ssaca` S&S Activewear Canada, `smr` SanMar, `sanmar_ca` SanMar Canada, `agst` Momentec (Augusta Sportswear), `agstca` Momentec Canada, `asc` AS Colour. Older catalogs with stored prices only: `alp` and `alpca` (AlphaBroder), `conde`, `tsf`, `deltapp` (Delta Apparel).","operationId":"v1_public_hydrate_imported_product","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"catalog":{"summary":"A catalog product's whole style","value":{"id":"ssa-B00000001","type":"db_catalog"}},"variant":{"summary":"One of your variant products","value":{"id":"Xe3wCbaZYrxJAI","type":"db_simple"}}},"schema":{"additionalProperties":false,"properties":{"context":{"description":"`mockup_editor` also refuses catalog products the team can't use for mockups.","enum":["mockup_editor",null],"type":["string","null"]},"id":{"description":"A product or variant hash id, or a catalog id (catalog ids are plain strings such as `ssa-B00000001`).","type":"string"},"type":{"enum":["db_simple","custom","db_variant","db_catalog","db_catalog_style"],"type":"string"}},"required":["type","id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"attr_data":[{"available":true,"color_hex":"#000000","color_id":"black","color_image":"https://example.com/swatches/black.jpg","color_label":"Black","display_dscnt":false,"dscnt":false,"id":"ssa-B00000001","provider":"ssa","size_id":"0300","size_label":"M","updated_at":"2026-11-01T06:00:00+00:00","weight":0.4},{"available":true,"color_hex":"#000000","color_id":"black","color_image":"https://example.com/swatches/black.jpg","color_label":"Black","display_dscnt":false,"dscnt":false,"id":"ssa-B00000002","provider":"ssa","size_id":"0400","size_label":"L","updated_at":"2026-11-01T06:00:00+00:00","weight":0.45}],"brand":"Example Brand","color_data":[{"hex":"#000000","id":"black","image":"https://example.com/swatches/black.jpg","label":"Black"}],"display_dscnt":false,"dscnt":false,"id":"ssa-5000","product_type":"SSActivewear","size_data":[{"id":"0300","label":"M"},{"id":"0400","label":"L"}],"style_id":"ssa-5000","style_name":"5000","title":"Heavy Cotton T-Shirt","trashed":false,"type":"variant_catalog","variant_type":"size_color"},"status":200,"success":true},"schema":{"properties":{"data":{"discriminator":{"mapping":{"simple":"#/components/schemas/YourSimpleProduct","variant":"#/components/schemas/YourVariantProduct","variant_catalog":"#/components/schemas/SupplierCatalogStyle"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/SupplierCatalogStyle"},{"$ref":"#/components/schemas/YourVariantProduct"},{"$ref":"#/components/schemas/YourSimpleProduct"}],"title":"What came back?"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Load a product for a sales order line","tags":["Products"],"x-yoprint-docs":{"errors":[{"fix":"Check `type` and `id`.","status":404,"when":"A catalog product without a style, a catalog style without products, a variant without its product, or, with `context: mockup_editor`, a catalog style the team can't use for mockups: `error.code` is the number `404` and `error.message` is `product_not_found`. Nothing with this id at all (or a deleted product): `error.code` null."},{"fix":"Send both.","status":422,"when":"`type` is not one of the five, `id` is missing, or `context` is not `mockup_editor`. `error.code` is `validation_failed`."}],"group":"Products and catalog","permission":"Any member of the team.","related":["v1_public_real_time_data_fetcher_pricing","v2_public_order_item_store","v1_public_misc_product_stock"],"rules":["Deleted products and variants are not found (404).","Catalog lookups read YoPrint's copy of the supplier catalogs; they make no call to the supplier."]}}},"/v1/api/store/{team_slug}/imports":{"get":{"description":"Lists your team's import jobs, newest first, a page at a time. Each job is one import: a service pricing CSV upload, a Printavo import, or a CSV import from the older uploader (retired in September 2026). Service pricing jobs are always `completed` with `failed_item_count` 0: a failed upload leaves no job.\n\nYou only see the jobs whose kind you are allowed to import. Use `page` and `per_page` (default 25, at most 100). There are no filters.\n\nImports made in the web app's current Import Portal (customers, vendors and products from CSV) are kept separately and are not listed here. They appear in the import activity feed, `GET /v1/api/store/{team_slug}/source-imports/activity`.","operationId":"v1_public_imports_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The page to read, from 1.","in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}},{"description":"Jobs per page.","in":"query","name":"per_page","required":false,"schema":{"default":25,"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"already_imported_count":0,"auto_commit":true,"completed_at":"2026-11-03T09:30:02+00:00","created_at":"2026-11-03T09:30:00+00:00","display_status":"completed","display_status_label":null,"duplicate_count":0,"entity_type":"service_pricing","error_csv_url":null,"failed_item_count":0,"id":"L4wYdA6Rav79IZ","legacy_status":"import_success","source_account_ref":null,"source_type":"csv","status":"completed","success_item_count":1,"target_mode":"existing_service","total_item_count":1,"unresolved_item_count":0,"updated_at":"2026-11-03T09:30:02+00:00"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":25,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"already_imported_count":{"description":"Items skipped because they were imported before.","type":"integer"},"auto_commit":{"description":"True when the job saves its rows without a separate review step.","type":"boolean"},"completed_at":{"description":"When the job reached a final status.","format":"date-time","type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"display_status":{"description":"A status slug formatted for UI display: matches `status`, or is `imported_with_unresolved_rows` when some items succeeded and some failed.","type":"string"},"display_status_label":{"description":"A human-readable status label: `\"Imported with unresolved rows\"` when `display_status` is `imported_with_unresolved_rows`, otherwise null.","type":["string","null"]},"duplicate_count":{"description":"Items skipped as duplicates within the job.","type":"integer"},"entity_type":{"description":"What was imported. For CSV imports: `service_pricing` (the CSV type supported via API), or older uploader types (`customer`, `vendor`, `simple_product`, `variant_product`, `custom_product`). For Printavo imports: Printavo record types (such as `customer`, `vendor`).","type":"string"},"error_csv_url":{"description":"Web app download URL for a failed-rows CSV. Null for service pricing and Printavo jobs, and for new imports. Only retired CSV uploader jobs (pre-September 2026) may have a link. Because this is a web app link that API keys cannot open, download the file via the API using `GET /v1/api/store/{team_slug}/imports/{hash_id}/artifacts/error-csv`. Check `failed_item_count` to see if items failed.","type":["string","null"]},"failed_item_count":{"description":"Items that failed. Always 0 on service pricing imports: they are all or nothing, and any error fails with 422 without creating an import job. Only Printavo imports and retired CSV uploader jobs can have failed items.","type":"integer"},"id":{"description":"The import job's id (a hash id).","type":"string"},"legacy_status":{"description":"An older status word kept for the web app, such as `import_success` or `validation_failed`. Prefer `status`.","type":["string","null"]},"source_account_ref":{"description":"The connected source account, for Printavo jobs.","type":["string","null"]},"source_type":{"description":"Where the data came from.","enum":["csv","printavo"],"type":"string"},"status":{"description":"`completed`, `completed_with_errors` and `failed` are final.","enum":["pending","staged","ready_to_commit","committing","completed","completed_with_errors","failed"],"type":"string"},"success_item_count":{"description":"Items saved.","type":"integer"},"target_mode":{"description":"Service pricing jobs: `existing_service` or `create`. Otherwise usually null.","type":["string","null"]},"total_item_count":{"description":"Rows (items) in the job. A service pricing job has one item: the whole price table.","type":"integer"},"unresolved_item_count":{"description":"Failed items: the same number as `failed_item_count`.","type":"integer"},"updated_at":{"format":"date-time","type":["string","null"]}},"required":["id","source_type","entity_type","status","display_status","total_item_count","success_item_count","failed_item_count","created_at"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List import jobs","tags":["CSV imports"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team admin for permission to create and update customers, vendors, products or services.","status":403,"when":"You can't import any kind of record (a plain `{\"message\": \"Insufficient Permission\"}` body, not the usual envelope)."},{"fix":"Send `page` from 1 and `per_page` from 1 to 100.","status":422,"when":"`page` or `per_page` is not a whole number in range (`validation_failed`; `error.fields` names the field)."}],"group":"Imports and exports","permission":"Any member who can import at least one kind of record: customers (permission to create and to update all customers), vendors (create and update vendors), products (create and update products) or service pricing (update services). When the Printavo importer is on, members who can manage settings qualify too. Each job is visible only to members with the permissions its kind needs: the ones above, and create and update services for a service pricing job that created a service. Printavo jobs also need the Printavo importer turned on for the team; Printavo jobs for records other than customers and vendors need permission to manage settings.","related":["v1_public_imports_show","v1_public_imports_csv_store","v1_public_source_imports_activity_index"]}}},"/v1/api/store/{team_slug}/imports/csv":{"post":{"description":"Uploads a price table as a CSV file and saves it on a service in one request.\n\n- `target_mode=existing_service`: permanently overwrites the service's whole price table. Any existing options or price breaks missing from the file are deleted. The service's name and locations do not change.\n- `target_mode=create`: creates a new service with these prices.\n\nSend `multipart/form-data`. The import runs while you wait, and it is all or nothing. If anything in the file is wrong, you get `422` with the first problem found (a row problem names its line), and nothing is saved: no price changes and no import job. Otherwise the response is the finished import job, always `completed` with `failed_item_count` 0. You can read it again later with `GET /v1/api/store/{team_slug}/imports/{hash_id}`. There is never a file of failed rows for these imports.\n\nOnly service pricing is accepted here (`entity_type=service_pricing`). Customer, vendor and product CSV files are imported in the YoPrint web app's Import Portal.\n\n**The file.** Start from `PUT /v1/api/store/{team_slug}/csv/template/service_pricing`.\n\n- A `.csv` file of at most 6,240 KB, with at most 600 data rows and at least one, in UTF-8.\n- The first header must be exactly `qty/type`. Add at least one more column; each is an option of the service (for example `1 Color`). Header names can't be blank or repeated.\n- Each row is a price break. `qty/type` is a number, the first row's must be 1, and no quantity can repeat.\n- Every cell needs a value. A cell is one price (`12.50`) or two, `first|additional` (`12.50|9.00`). Prices are numbers with at most 3 decimal places, written with a digit before the point (`0.50`, not `.50`) and no spaces.","operationId":"v1_public_imports_csv_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"encoding":{"file":{"contentType":"text/csv"}},"examples":{"create":{"summary":"Create a service with these prices","value":{"allow_cust_loc":"1","entity_type":"service_pricing","file":"qty/type,1 Color,2 Color\n1,10.00|11.00,12.00|13.00\n12,8.50|9.00,10.00|11.00\n","locations":[{"id":"454DGJ3i6EQpq0"},{"id":"XDz01LsIUDpguv"}],"name":"Puff print","pricing_type":"additional","target_mode":"create"},"x-yoprint-variant":"A new service"},"existing_service":{"summary":"Replace an existing service's prices","value":{"entity_type":"service_pricing","file":"qty/type,1 Color,2 Color\n1,10.00|11.00,12.00|13.00\n12,8.50|9.00,10.00|11.00\n","service_id":"IIVE3hadAUOmIA","target_mode":"existing_service"},"x-yoprint-variant":"An existing service"}},"schema":{"oneOf":[{"description":"Permanently overwrites the service's whole price table with the file; omitted options and breaks are deleted.","properties":{"entity_type":{"const":"service_pricing","type":"string"},"file":{"description":"The CSV file: a name ending in `.csv`, at most 6,240 KB and 600 data rows.","format":"binary","type":"string"},"service_id":{"description":"The service's id (a hash id), for example the `service_id` of a job's service.","type":"string"},"target_mode":{"const":"existing_service","type":"string"}},"required":["entity_type","file","target_mode","service_id"],"title":"An existing service","type":"object"},{"description":"Creates a service with this name, these locations and these prices.","properties":{"allow_cust_loc":{"description":"\"Allow custom locations on jobs\": `1` for yes, `0` for no. A form sends text, and `true` or `false` are refused.","enum":["1","0"],"type":"string"},"entity_type":{"const":"service_pricing","type":"string"},"file":{"description":"The CSV file: a name ending in `.csv`, at most 6,240 KB and 600 data rows.","format":"binary","type":"string"},"locations":{"description":"The product locations the service applies to, at least one, each once. Send each id as its own form field with a numbered index: `locations[0][id]`, `locations[1][id]`, and so on. A JSON text in a single `locations` field is refused (`locations` must be an array).","items":{"properties":{"id":{"description":"A product location's `id` (a hash id) from `GET /v1/api/store/{team_slug}/service_location`.","type":"string"}},"required":["id"],"type":"object"},"minItems":1,"type":"array"},"name":{"description":"The new service's name.","type":"string"},"pricing_type":{"description":"`single`: per-item pricing. `additional`: per-item pricing with a second price for each additional location. `single_flat`: a flat rate per job.","enum":["single","additional","single_flat"],"type":"string"},"target_mode":{"const":"create","type":"string"}},"required":["entity_type","file","target_mode","name","allow_cust_loc","pricing_type","locations"],"title":"A new service","type":"object"}],"title":"Which service gets the prices?"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"already_imported_count":0,"auto_commit":true,"completed_at":"2026-11-03T09:30:02+00:00","created_at":"2026-11-03T09:30:00+00:00","display_status":"completed","display_status_label":null,"duplicate_count":0,"entity_type":"service_pricing","error_csv_url":null,"failed_item_count":0,"id":"L4wYdA6Rav79IZ","legacy_status":"import_success","source_account_ref":null,"source_type":"csv","status":"completed","success_item_count":1,"target_mode":"existing_service","total_item_count":1,"unresolved_item_count":0,"updated_at":"2026-11-03T09:30:02+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"already_imported_count":{"description":"Items skipped because they were imported before.","type":"integer"},"auto_commit":{"description":"True when the job saves its rows without a separate review step.","type":"boolean"},"completed_at":{"description":"When the job reached a final status.","format":"date-time","type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"display_status":{"description":"A status slug formatted for UI display: matches `status`, or is `imported_with_unresolved_rows` when some items succeeded and some failed.","type":"string"},"display_status_label":{"description":"A human-readable status label: `\"Imported with unresolved rows\"` when `display_status` is `imported_with_unresolved_rows`, otherwise null.","type":["string","null"]},"duplicate_count":{"description":"Items skipped as duplicates within the job.","type":"integer"},"entity_type":{"description":"What was imported. For CSV imports: `service_pricing` (the CSV type supported via API), or older uploader types (`customer`, `vendor`, `simple_product`, `variant_product`, `custom_product`). For Printavo imports: Printavo record types (such as `customer`, `vendor`).","type":"string"},"error_csv_url":{"description":"Web app download URL for a failed-rows CSV. Null for service pricing and Printavo jobs, and for new imports. Only retired CSV uploader jobs (pre-September 2026) may have a link. Because this is a web app link that API keys cannot open, download the file via the API using `GET /v1/api/store/{team_slug}/imports/{hash_id}/artifacts/error-csv`. Check `failed_item_count` to see if items failed.","type":["string","null"]},"failed_item_count":{"description":"Items that failed. Always 0 on service pricing imports: they are all or nothing, and any error fails with 422 without creating an import job. Only Printavo imports and retired CSV uploader jobs can have failed items.","type":"integer"},"id":{"description":"The import job's id (a hash id).","type":"string"},"legacy_status":{"description":"An older status word kept for the web app, such as `import_success` or `validation_failed`. Prefer `status`.","type":["string","null"]},"source_account_ref":{"description":"The connected source account, for Printavo jobs.","type":["string","null"]},"source_type":{"description":"Where the data came from.","enum":["csv","printavo"],"type":"string"},"status":{"description":"`completed`, `completed_with_errors` and `failed` are final.","enum":["pending","staged","ready_to_commit","committing","completed","completed_with_errors","failed"],"type":"string"},"success_item_count":{"description":"Items saved.","type":"integer"},"target_mode":{"description":"Service pricing jobs: `existing_service` or `create`. Otherwise usually null.","type":["string","null"]},"total_item_count":{"description":"Rows (items) in the job. A service pricing job has one item: the whole price table.","type":"integer"},"unresolved_item_count":{"description":"Failed items: the same number as `failed_item_count`.","type":"integer"},"updated_at":{"format":"date-time","type":["string","null"]}},"required":["id","source_type","entity_type","status","display_status","total_item_count","success_item_count","failed_item_count","created_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Import a service's price table from CSV","tags":["CSV imports"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team admin for permission to create or update services.","status":403,"when":"You lack the service permissions the target mode needs (a plain `{\"message\": \"Insufficient Permission\"}` body, not the usual envelope). Checked early, before `target_mode`, the service and the file's contents; without a valid `target_mode` it asks for both create and update."},{"fix":"Check the service's id.","status":404,"when":"`service_id` matches no service of this team."},{"fix":"Fix the field and send again.","status":422,"when":"A field is missing or invalid, the file is not `.csv` or is over 6,240 KB, or a location id is not yours (`validation_failed`; `error.fields` names the field)."},{"fix":"Fix the file and upload it again. Nothing was saved.","status":422,"when":"The file breaks a rule: `error.code` `single_error`, the problem in `error.message`, and `error.detail`, a list holding the same text. A row problem starts with its line, as in \"[LINE 3] Duplicate Quantity Break Detected: 12\"; header, encoding and empty-file problems have no line."},{"fix":"Split the table, or remove unused price breaks.","status":422,"when":"The file has more than 600 data rows: a plain `{\"message\": \"This import expands to 601 source rows. The limit for service_pricing imports is 600 source rows per request.\"}` body, not the usual envelope."},{"fix":"Write numbers like `0.50` with no spaces; for the second case, retry after the first upload finishes.","status":500,"when":"A price or quantity is written like `.50` or with a leading space, or a second upload for the same service (or the same new service name) waited 45 seconds and the first was still running (`{\"message\": \"Server Error\"}`). Nothing was saved."}],"group":"Imports and exports","notes":["Re-uploading the same file to the same service is safe: the result is the same table. With `create`, each successful upload makes another service, even with the same name.","Line numbers in error messages count the header as line 1, so the first data row is line 2.","Prices are saved as given, with up to 3 decimal places.","The public API has no operation that lists services. A job's services carry their `service_id`; take it from there or from YoPrint. Product location ids come from `GET /v1/api/store/{team_slug}/service_location`."],"permission":"To replace an existing service's prices: permission to update services. To create a service: permission to create and to update services.","related":["v1_public_csv_template_service_pricing","v1_public_service_location_index","v1_public_imports_show"],"rules":["`entity_type` must be `service_pricing`. Any other value is a 422.","`target_mode` is `existing_service` or `create`. With `existing_service`, send `service_id`. With `create`, send `name`, `allow_cust_loc`, `pricing_type` and at least one entry in `locations`.","Every location id must be one of your team's product locations, each listed once, or the request fails with \"One or more service locations are invalid.\"","The file must have the `.csv` extension and be at most 6,240 KB. It must hold at least one and at most 600 data rows.","First header exactly `qty/type`, then at least one option column. Option headers can't be blank or repeated.","Each `qty/type` value is a number, the first data row's is 1, and quantities can't repeat.","No empty cells (`0` is a value). Each cell is a price, or `first|additional`. Prices are numbers with at most 3 decimal places, between -2,147,483,648 and 2,147,483,648. Write a digit before the decimal point and no spaces: `.50` or ` 12` passes the number check but then fails with a server error.","All or nothing: the whole file is checked before anything is saved, and any problem stops the import with nothing saved. A returned job is always `completed`, with one item and `failed_item_count` 0.","One price import per service at a time, and one per new service name. A second upload waits up to 45 seconds for the first to finish; if the first is still running then, it fails with a server error. Retry after the first finishes."],"side_effects":["`existing_service`: permanently overwrites the service's whole price table with the file. Options and price breaks missing from the file are deleted. The service's name and locations do not change.","`create`: creates a service at the end of your service list, links the locations, then saves the prices.","If the service's pricing type is not `additional`, the second price in `first|additional` cells is ignored and the service keeps no additional-location prices.","A successful import is recorded as an import job, with the uploaded file attached. A failed one leaves no job: it does not appear in the import jobs list.","People with YoPrint open see the service and the import update live."]}}},"/v1/api/store/{team_slug}/imports/{hash_id}":{"get":{"description":"Returns one import job: its status and how many items succeeded, failed or were skipped.\n\n`completed`, `completed_with_errors` and `failed` are final. A service pricing upload is already final when its upload request returns, so you never need to poll it: its job is always `completed`, with one item and `failed_item_count` 0, because a failed upload saves nothing and leaves no job.","operationId":"v1_public_imports_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The import job's `id`, from the import jobs list or the upload answer. A hash id; unique keys and document numbers are refused with 404.","example":"L4wYdA6Rav79IZ","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"already_imported_count":0,"auto_commit":true,"completed_at":"2026-11-03T09:30:02+00:00","created_at":"2026-11-03T09:30:00+00:00","display_status":"completed","display_status_label":null,"duplicate_count":0,"entity_type":"service_pricing","error_csv_url":null,"failed_item_count":0,"id":"L4wYdA6Rav79IZ","legacy_status":"import_success","source_account_ref":null,"source_type":"csv","status":"completed","success_item_count":1,"target_mode":"existing_service","total_item_count":1,"unresolved_item_count":0,"updated_at":"2026-11-03T09:30:02+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"already_imported_count":{"description":"Items skipped because they were imported before.","type":"integer"},"auto_commit":{"description":"True when the job saves its rows without a separate review step.","type":"boolean"},"completed_at":{"description":"When the job reached a final status.","format":"date-time","type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"display_status":{"description":"A status slug formatted for UI display: matches `status`, or is `imported_with_unresolved_rows` when some items succeeded and some failed.","type":"string"},"display_status_label":{"description":"A human-readable status label: `\"Imported with unresolved rows\"` when `display_status` is `imported_with_unresolved_rows`, otherwise null.","type":["string","null"]},"duplicate_count":{"description":"Items skipped as duplicates within the job.","type":"integer"},"entity_type":{"description":"What was imported. For CSV imports: `service_pricing` (the CSV type supported via API), or older uploader types (`customer`, `vendor`, `simple_product`, `variant_product`, `custom_product`). For Printavo imports: Printavo record types (such as `customer`, `vendor`).","type":"string"},"error_csv_url":{"description":"Web app download URL for a failed-rows CSV. Null for service pricing and Printavo jobs, and for new imports. Only retired CSV uploader jobs (pre-September 2026) may have a link. Because this is a web app link that API keys cannot open, download the file via the API using `GET /v1/api/store/{team_slug}/imports/{hash_id}/artifacts/error-csv`. Check `failed_item_count` to see if items failed.","type":["string","null"]},"failed_item_count":{"description":"Items that failed. Always 0 on service pricing imports: they are all or nothing, and any error fails with 422 without creating an import job. Only Printavo imports and retired CSV uploader jobs can have failed items.","type":"integer"},"id":{"description":"The import job's id (a hash id).","type":"string"},"legacy_status":{"description":"An older status word kept for the web app, such as `import_success` or `validation_failed`. Prefer `status`.","type":["string","null"]},"source_account_ref":{"description":"The connected source account, for Printavo jobs.","type":["string","null"]},"source_type":{"description":"Where the data came from.","enum":["csv","printavo"],"type":"string"},"status":{"description":"`completed`, `completed_with_errors` and `failed` are final.","enum":["pending","staged","ready_to_commit","committing","completed","completed_with_errors","failed"],"type":"string"},"success_item_count":{"description":"Items saved.","type":"integer"},"target_mode":{"description":"Service pricing jobs: `existing_service` or `create`. Otherwise usually null.","type":["string","null"]},"total_item_count":{"description":"Rows (items) in the job. A service pricing job has one item: the whole price table.","type":"integer"},"unresolved_item_count":{"description":"Failed items: the same number as `failed_item_count`.","type":"integer"},"updated_at":{"format":"date-time","type":["string","null"]}},"required":["id","source_type","entity_type","status","display_status","total_item_count","success_item_count","failed_item_count","created_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get an import job","tags":["CSV imports"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team admin for the permissions, or read jobs you can see in the list.","status":403,"when":"You lack the permissions this job's kind needs (a plain `{\"message\": \"Insufficient Permission\"}` body), or it is a Printavo job and the Printavo importer is off for the team (`printavo_importer_disabled`)."},{"fix":"Use an `id` from the list.","status":404,"when":"No import job of this team has this id."}],"group":"Imports and exports","permission":"Any member who can import at least one kind of record: customers (permission to create and to update all customers), vendors (create and update vendors), products (create and update products) or service pricing (update services). When the Printavo importer is on, members who can manage settings qualify too. Each job is visible only to members with the permissions its kind needs: the ones above, and create and update services for a service pricing job that created a service. Printavo jobs also need the Printavo importer turned on for the team; Printavo jobs for records other than customers and vendors need permission to manage settings.","related":["v1_public_imports_index","v1_public_imports_artifacts_error_csv"]}}},"/v1/api/store/{team_slug}/imports/{hash_id}/artifacts/error-csv":{"get":{"description":"Downloads the CSV of rows that failed in an import job, with the reason for each row. It is a file, not JSON.\n\n**In practice it answers `404`.** Nothing creates this file any more. Service pricing uploads never have one: they are all or nothing, so a job exists only when every row was saved. Printavo imports don't have one either. Only jobs from the older CSV uploader, retired in September 2026, may still have a file, until it expires 90 days after it was made; after that it answers `410`. To see what failed, read the job's `failed_item_count`.","operationId":"v1_public_imports_artifacts_error_csv","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The import job's `id`, from the import jobs list or the upload answer. A hash id; unique keys and document numbers are refused with 404.","example":"L4wYdA6Rav79IZ","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"format":"binary","type":"string"}}},"description":"The failed rows, with the original columns plus the error message and row number.","headers":{"Content-Disposition":{"description":"attachment; filename=\"<name>.csv\"","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download an import job's failed rows","tags":["CSV imports"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team admin for the permissions.","status":403,"when":"You lack the permissions this job's kind needs (a plain `{\"message\": \"Insufficient Permission\"}` body), or it is a Printavo job and the Printavo importer is off (`printavo_importer_disabled`)."},{"fix":"Check `error_csv_url` on the job first; null means there is no file.","status":404,"when":"The job does not exist, or it has no error file (then `error.code` is `page_not_found`). Every service pricing and Printavo job you can read answers this."},{"fix":"The file is gone for good. Read the job's counts instead.","status":410,"when":"The error file expired or was removed: a plain `{\"message\": \"This import artifact has expired.\"}` or `{\"message\": \"This import artifact is no longer available.\"}` body."}],"group":"Imports and exports","permission":"Any member who can import at least one kind of record: customers (permission to create and to update all customers), vendors (create and update vendors), products (create and update products) or service pricing (update services). When the Printavo importer is on, members who can manage settings qualify too. Each job is visible only to members with the permissions its kind needs: the ones above, and create and update services for a service pricing job that created a service. Printavo jobs also need the Printavo importer turned on for the team; Printavo jobs for records other than customers and vendors need permission to manage settings.","related":["v1_public_imports_show"]}}},"/v1/api/store/{team_slug}/invoice":{"get":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_invoice_filter` (POST /v2/api/store/{team_slug}/v2/invoice/filter) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nReturns one page of your team's invoices of saved, non-draft sales orders and quotes (invoices of deleted, draft or autosaved orders, and deleted invoices, are left out). No filters or sort: only `page`; the order isn't guaranteed.\n\nEach row is a summary: number, order, customer, dates, deposit, totals (`calc_total` and the other `calc_*` fields are in thousandths, an older encoding: 12.50 is `12500`; see [Money and quantities](/concepts/money-and-quantities/)), `paid_amount`, `is_paid` and PDF links (they carry their own access token).","operationId":"v1_public_invoice_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The page to read. The page size is the team's list page size setting (50 unless the team changed it).","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"billing_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"calc_delivery_total":15000,"calc_deposit_total":169880,"calc_discount":0,"calc_subtotal":315000,"calc_tax":24750,"calc_total":339750,"created_at":"2026-11-03T15:00:00+00:00","customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","deposit_due":"2026-11-05T00:00:00+00:00","deposit_required":true,"full_amount_due":"2026-11-20T00:00:00+00:00","id":"cBRpSf5nw6upt5","is_paid":false,"order_cust_due_date":"2026-11-10T00:00:00+00:00","order_id":"sFbALVSYD55eXe","order_issue_date":"2026-11-02T00:00:00+00:00","order_name":"Team shirts","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","order_ship_due_date":"2026-11-08T00:00:00+00:00","paid_amount":100000,"pdf_url":[{"is_custom":false,"url":"https://example.com/pdf/invoice.pdf"}],"scoped_id":"1001","shipping_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"}}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"An invoice summary. Amounts are in thousandths.","properties":{"billing_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"calc_delivery_total":{"description":"Shipping. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_deposit_total":{"description":"Deposit amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_discount":{"description":"Discount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_subtotal":{"description":"Subtotal. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_tax":{"description":"Tax. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_total":{"description":"Total. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"created_at":{"format":"date-time","type":"string"},"customer":{"oneOf":[{"additionalProperties":true,"description":"The customer (the full customer record).","properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":"string"},"name":{"example":"Northwind Apparel","type":"string"}},"type":"object"},{"type":"null"}]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"deposit_due":{"description":"Deposit due. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"deposit_required":{"type":["boolean","integer","null"]},"full_amount_due":{"description":"Full amount due. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_paid":{"type":"boolean"},"order_cust_due_date":{"description":"Order customer due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"order_name":{"type":["string","null"]},"order_object_type":{"example":"sales_order","type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"order_ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"paid_amount":{"description":"Allocated payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"pdf_url":{"description":"PDF links (with their own access token): the standard invoice PDF first (`url`, `is_custom: false`), then one entry per enabled custom invoice template (`label`, `type`, `description`, `url`, the `show_in_*` flags, `is_custom: true`).","items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"is_custom":{"type":"boolean"},"label":{"type":"string"},"type":{"type":"string"},"url":{"type":"string"}},"type":"object"},"type":"array"},"scoped_id":{"description":"The invoice number.","example":"1001","type":["string","null"]},"shipping_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List invoices (v1)","tags":["Invoices"],"x-yoprint-docs":{"group":"Invoices and payments","notes":["The response is one page with `pagination`. The page size is the team's list page size setting (50 unless the team changed it); `per_page` is not read. Send `page` (from 1) in the body or the query string for later pages."],"permission":"Any member of the team.","prefer":"v2_public_invoice_filter","related":["v2_public_invoice_filter","v1_public_invoice_show"],"status":"legacy"}}},"/v1/api/store/{team_slug}/invoice/export_pdf":{"post":{"description":"Returns one PDF with up to 100 invoices, made while you wait (`<date and time> - invoices.pdf`, shown inline). Nothing is stored. Ids that aren't your team's invoices are skipped without an error.","operationId":"v1_public_invoice_export_pdf","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"invoice":[{"id":"cBRpSf5nw6upt5"},{"id":"gtnwEWU4Npp9eC"}]},"schema":{"properties":{"invoice":{"items":{"properties":{"id":{"description":"An invoice hash id.","example":"V4keXwwxMQyXw7","type":"string"}},"required":["id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}},"required":["invoice"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"Binary download response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download invoices as one PDF","tags":["Invoices"],"x-yoprint-docs":{"errors":[{"fix":"Send 1 to 100 `{ \"id\": ... }` objects under `invoice`.","status":422,"when":"`invoice` is missing, empty or has more than 100 entries."}],"group":"Invoices and payments","notes":["If none of the ids is yours you may get an empty PDF rather than an error: check your ids first."],"permission":"Any member of the team.","related":["v2_public_invoice_filter","v2_public_invoice_show"],"rules":["1 to 100 invoices per call: \"The invoice may not have more than 100 items.\""]}}},"/v1/api/store/{team_slug}/invoice/{hash_id}":{"get":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_invoice_show` (GET /v2/api/store/{team_slug}/v2/invoice/{unique_key}) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nReturns one invoice by its hash id. Invoices made in the current invoice system come back in the same shape as Get an invoice (v2) but without `items` unless you add `?with=items`; very old invoices come back in the old shape, with `order_items` and `jobs`. Prefer Get an invoice.","operationId":"v1_public_invoice_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The invoice's hash id. Hash ids only: a unique key or a document number gives 404.","example":"cBRpSf5nw6upt5","in":"path","name":"hash_id","required":true,"schema":{"example":"cBRpSf5nw6upt5","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"auto_invoice_managed":false,"bill_to_status":"okay","billing_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"billing_address_id":"117KfwwfreX15N","calc_deposit_total":169880,"cart_item_subtotal":{"dp":4,"value":3150000},"created_at":"2026-11-03T15:00:00+00:00","credit_card_surcharge":{"dp":4,"value":0},"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"deposit_due":"2026-11-05T00:00:00+00:00","deposit_required":true,"discount_subtotal":{"dp":4,"value":0},"external_type":null,"from_legacy":false,"full_amount_due":"2026-11-20T00:00:00+00:00","id":"cBRpSf5nw6upt5","is_external":false,"is_paid":false,"is_valid":true,"issue_date":"2026-11-03T00:00:00+00:00","lock_version":1730000000000000,"order":{"id":"sFbALVSYD55eXe","scoped_id":"SO1001"},"order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","paid_amount":100000,"pdf_url":[{"description":"Invoice pdf","label":"Invoice","object_type":"invoice","url":"https://example.com/pdf/invoice.pdf"}],"scoped_id":"1001","ship_to_status":"okay","shipment_subtotal":{"dp":4,"value":150000},"shipment_tax_subtotal":{"dp":4,"value":0},"shipping_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"shipping_address_id":"117KfwwfreX15N","tax_subtotal":{"dp":4,"value":247500},"total":{"dp":4,"value":3397500},"version":2},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"An invoice. Amounts are decimal pairs at the stored scale (4 decimal places for invoice totals), except `paid_amount` and `calc_deposit_total` (thousandths). The `calc_*` totals are deprecated copies of the decimal-pair ones.","properties":{"auto_invoice_managed":{"description":"YoPrint keeps this invoice in step with the order (Auto Invoice).","type":"boolean"},"bill_to_status":{"description":"How Bill To compares with the order's.","enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"billing_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"billing_address_id":{"description":"Bill To.","example":"117KfwwfreX15N","type":["string","null"]},"calc_delivery_total":{"deprecated":true,"description":"**Deprecated:** use `shipment_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_deposit_total":{"description":"The order's deposit amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `cart_item_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"cart_item_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Billed sales order lines and shipping fees (price × quantity); `shipment_subtotal` is 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 is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Read `dp` every time: it can differ between fields and records."},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"credit_card_surcharge":{"$ref":"#/components/schemas/BigDecimalValue","description":"A 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). Read `dp` every time: it can differ between fields and records."},"customer":{"oneOf":[{"additionalProperties":true,"description":"The customer (the full customer record).","properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":"string"},"name":{"example":"Northwind Apparel","type":"string"}},"type":"object"},{"type":"null"}]},"deposit_due":{"description":"From the order. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"deposit_required":{"description":"From the order.","type":["boolean","integer","null"]},"discount_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Discounts. 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."},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"full_amount_due":{"description":"From the order. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"is_paid":{"description":"Paid amount covers the total (also true for a zero total).","type":"boolean"},"is_valid":{"description":"False when the invoice needs fixing: no lines, lines without a tax line, or a customer that differs from the order's.","type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"lock_version":{"example":1730000000000000,"type":"integer"},"order":{"additionalProperties":true,"description":"The sales order or quote in the v2 order shape: its header fields, with `status` and `assigned_users`, but no `items`.","properties":{"id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"scoped_id":{"example":"SO1001","type":["string","null"]}},"type":"object"},"order_id":{"description":"The sales order or quote it bills.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"order_quote":{"description":"The order is a quote.","type":"boolean"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"paid_amount":{"description":"Allocated payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"pdf_url":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Invoice","type":"string"},"object_type":{"example":"invoice","type":"string"},"url":{"description":"A download link with its own long-lived access token: don't publish it.","example":"https://example.com/pdf/invoice.pdf","type":"string"}},"type":"object"},"type":"array"},"scoped_id":{"description":"The invoice number.","example":"1001","type":["string","null"]},"ship_to_status":{"enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"shipment_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping fees (already in `cart_item_subtotal`). 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."},"shipment_tax_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"The tax on shipping (included in `tax_subtotal`). 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."},"shipping_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"shipping_address_id":{"description":"Ship To.","example":"117KfwwfreX15N","type":["string","null"]},"tax_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Tax. 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."},"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The invoice total. 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."},"version":{"example":2,"type":"integer"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get an invoice (v1)","tags":["Invoices"],"x-yoprint-docs":{"errors":[{"fix":"Check the hash id.","status":404,"when":"The invoice isn't your team's."}],"group":"Invoices and payments","permission":"Any member of the team.","prefer":"v2_public_invoice_show","related":["v2_public_invoice_show"],"status":"legacy"}},"patch":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_invoice_update` (PUT /v2/api/store/{team_slug}/v2/invoice/{unique_key}) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nSets only the invoice number (`scoped_id`); nothing else on the invoice can change here. PUT and PATCH behave the same. Returns the invoice.\n\nPrefer Update an invoice: it checks your sales order permission, can change the rest of the header in the same call, and lets the QuickBooks Online sync pick up the change. This route does none of that.","operationId":"v1_public_invoice_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The invoice's hash id. Hash ids only: a unique key or a document number gives 404.","example":"cBRpSf5nw6upt5","in":"path","name":"hash_id","required":true,"schema":{"example":"cBRpSf5nw6upt5","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"scoped_id":"1001"},"schema":{"properties":{"scoped_id":{"description":"The new invoice number, as a string. Not checked for duplicates.","example":"1001","type":"string"}},"required":["scoped_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"auto_invoice_managed":false,"bill_to_status":"okay","billing_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"billing_address_id":"117KfwwfreX15N","calc_deposit_total":169880,"cart_item_subtotal":{"dp":4,"value":3150000},"created_at":"2026-11-03T15:00:00+00:00","credit_card_surcharge":{"dp":4,"value":0},"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"deposit_due":"2026-11-05T00:00:00+00:00","deposit_required":true,"discount_subtotal":{"dp":4,"value":0},"external_type":null,"from_legacy":false,"full_amount_due":"2026-11-20T00:00:00+00:00","id":"cBRpSf5nw6upt5","is_external":false,"is_paid":false,"is_valid":true,"issue_date":"2026-11-03T00:00:00+00:00","lock_version":1730000000000000,"order":{"id":"sFbALVSYD55eXe","scoped_id":"SO1001"},"order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","paid_amount":100000,"pdf_url":[{"description":"Invoice pdf","label":"Invoice","object_type":"invoice","url":"https://example.com/pdf/invoice.pdf"}],"scoped_id":"1001","ship_to_status":"okay","shipment_subtotal":{"dp":4,"value":150000},"shipment_tax_subtotal":{"dp":4,"value":0},"shipping_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"shipping_address_id":"117KfwwfreX15N","tax_subtotal":{"dp":4,"value":247500},"total":{"dp":4,"value":3397500},"version":2},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"An invoice. Amounts are decimal pairs at the stored scale (4 decimal places for invoice totals), except `paid_amount` and `calc_deposit_total` (thousandths). The `calc_*` totals are deprecated copies of the decimal-pair ones.","properties":{"auto_invoice_managed":{"description":"YoPrint keeps this invoice in step with the order (Auto Invoice).","type":"boolean"},"bill_to_status":{"description":"How Bill To compares with the order's.","enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"billing_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"billing_address_id":{"description":"Bill To.","example":"117KfwwfreX15N","type":["string","null"]},"calc_delivery_total":{"deprecated":true,"description":"**Deprecated:** use `shipment_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_deposit_total":{"description":"The order's deposit amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `cart_item_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"cart_item_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Billed sales order lines and shipping fees (price × quantity); `shipment_subtotal` is 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 is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Read `dp` every time: it can differ between fields and records."},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"credit_card_surcharge":{"$ref":"#/components/schemas/BigDecimalValue","description":"A 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). Read `dp` every time: it can differ between fields and records."},"customer":{"oneOf":[{"additionalProperties":true,"description":"The customer (the full customer record).","properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":"string"},"name":{"example":"Northwind Apparel","type":"string"}},"type":"object"},{"type":"null"}]},"deposit_due":{"description":"From the order. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"deposit_required":{"description":"From the order.","type":["boolean","integer","null"]},"discount_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Discounts. 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."},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"full_amount_due":{"description":"From the order. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"is_paid":{"description":"Paid amount covers the total (also true for a zero total).","type":"boolean"},"is_valid":{"description":"False when the invoice needs fixing: no lines, lines without a tax line, or a customer that differs from the order's.","type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"lock_version":{"example":1730000000000000,"type":"integer"},"order":{"additionalProperties":true,"description":"The sales order or quote in the v2 order shape: its header fields, with `status` and `assigned_users`, but no `items`.","properties":{"id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"scoped_id":{"example":"SO1001","type":["string","null"]}},"type":"object"},"order_id":{"description":"The sales order or quote it bills.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"order_quote":{"description":"The order is a quote.","type":"boolean"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"paid_amount":{"description":"Allocated payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"pdf_url":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Invoice","type":"string"},"object_type":{"example":"invoice","type":"string"},"url":{"description":"A download link with its own long-lived access token: don't publish it.","example":"https://example.com/pdf/invoice.pdf","type":"string"}},"type":"object"},"type":"array"},"scoped_id":{"description":"The invoice number.","example":"1001","type":["string","null"]},"ship_to_status":{"enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"shipment_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping fees (already in `cart_item_subtotal`). 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."},"shipment_tax_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"The tax on shipping (included in `tax_subtotal`). 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."},"shipping_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"shipping_address_id":{"description":"Ship To.","example":"117KfwwfreX15N","type":["string","null"]},"tax_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Tax. 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."},"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The invoice total. 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."},"version":{"example":2,"type":"integer"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change an invoice number (v1) (same as PUT)","tags":["Invoices"],"x-yoprint-docs":{"errors":[{"fix":"Send the number as a JSON string.","status":422,"when":"`scoped_id` is missing or not a string."},{"fix":"Check the hash id.","status":404,"when":"The invoice isn't your team's."}],"group":"Invoices and payments","patch":"same_as_put","permission":"Any member of the team; no sales order permission is checked.","prefer":"v2_public_invoice_update","related":["v2_public_invoice_update"],"side_effects":["Saves the number only: no recalculation, no QuickBooks Online sync trigger, no refresh of open web app pages."],"status":"legacy"}},"put":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_invoice_update` (PUT /v2/api/store/{team_slug}/v2/invoice/{unique_key}) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nSets only the invoice number (`scoped_id`); nothing else on the invoice can change here. PUT and PATCH behave the same. Returns the invoice.\n\nPrefer Update an invoice: it checks your sales order permission, can change the rest of the header in the same call, and lets the QuickBooks Online sync pick up the change. This route does none of that.","operationId":"v1_public_invoice_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The invoice's hash id. Hash ids only: a unique key or a document number gives 404.","example":"cBRpSf5nw6upt5","in":"path","name":"hash_id","required":true,"schema":{"example":"cBRpSf5nw6upt5","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"scoped_id":"1001"},"schema":{"properties":{"scoped_id":{"description":"The new invoice number, as a string. Not checked for duplicates.","example":"1001","type":"string"}},"required":["scoped_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"auto_invoice_managed":false,"bill_to_status":"okay","billing_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"billing_address_id":"117KfwwfreX15N","calc_deposit_total":169880,"cart_item_subtotal":{"dp":4,"value":3150000},"created_at":"2026-11-03T15:00:00+00:00","credit_card_surcharge":{"dp":4,"value":0},"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"deposit_due":"2026-11-05T00:00:00+00:00","deposit_required":true,"discount_subtotal":{"dp":4,"value":0},"external_type":null,"from_legacy":false,"full_amount_due":"2026-11-20T00:00:00+00:00","id":"cBRpSf5nw6upt5","is_external":false,"is_paid":false,"is_valid":true,"issue_date":"2026-11-03T00:00:00+00:00","lock_version":1730000000000000,"order":{"id":"sFbALVSYD55eXe","scoped_id":"SO1001"},"order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","paid_amount":100000,"pdf_url":[{"description":"Invoice pdf","label":"Invoice","object_type":"invoice","url":"https://example.com/pdf/invoice.pdf"}],"scoped_id":"1001","ship_to_status":"okay","shipment_subtotal":{"dp":4,"value":150000},"shipment_tax_subtotal":{"dp":4,"value":0},"shipping_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"shipping_address_id":"117KfwwfreX15N","tax_subtotal":{"dp":4,"value":247500},"total":{"dp":4,"value":3397500},"version":2},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"An invoice. Amounts are decimal pairs at the stored scale (4 decimal places for invoice totals), except `paid_amount` and `calc_deposit_total` (thousandths). The `calc_*` totals are deprecated copies of the decimal-pair ones.","properties":{"auto_invoice_managed":{"description":"YoPrint keeps this invoice in step with the order (Auto Invoice).","type":"boolean"},"bill_to_status":{"description":"How Bill To compares with the order's.","enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"billing_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"billing_address_id":{"description":"Bill To.","example":"117KfwwfreX15N","type":["string","null"]},"calc_delivery_total":{"deprecated":true,"description":"**Deprecated:** use `shipment_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_deposit_total":{"description":"The order's deposit amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `cart_item_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"cart_item_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Billed sales order lines and shipping fees (price × quantity); `shipment_subtotal` is 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 is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Read `dp` every time: it can differ between fields and records."},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"credit_card_surcharge":{"$ref":"#/components/schemas/BigDecimalValue","description":"A 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). Read `dp` every time: it can differ between fields and records."},"customer":{"oneOf":[{"additionalProperties":true,"description":"The customer (the full customer record).","properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":"string"},"name":{"example":"Northwind Apparel","type":"string"}},"type":"object"},{"type":"null"}]},"deposit_due":{"description":"From the order. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"deposit_required":{"description":"From the order.","type":["boolean","integer","null"]},"discount_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Discounts. 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."},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"full_amount_due":{"description":"From the order. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"is_paid":{"description":"Paid amount covers the total (also true for a zero total).","type":"boolean"},"is_valid":{"description":"False when the invoice needs fixing: no lines, lines without a tax line, or a customer that differs from the order's.","type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"lock_version":{"example":1730000000000000,"type":"integer"},"order":{"additionalProperties":true,"description":"The sales order or quote in the v2 order shape: its header fields, with `status` and `assigned_users`, but no `items`.","properties":{"id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"scoped_id":{"example":"SO1001","type":["string","null"]}},"type":"object"},"order_id":{"description":"The sales order or quote it bills.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"order_quote":{"description":"The order is a quote.","type":"boolean"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"paid_amount":{"description":"Allocated payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"pdf_url":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Invoice","type":"string"},"object_type":{"example":"invoice","type":"string"},"url":{"description":"A download link with its own long-lived access token: don't publish it.","example":"https://example.com/pdf/invoice.pdf","type":"string"}},"type":"object"},"type":"array"},"scoped_id":{"description":"The invoice number.","example":"1001","type":["string","null"]},"ship_to_status":{"enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"shipment_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping fees (already in `cart_item_subtotal`). 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."},"shipment_tax_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"The tax on shipping (included in `tax_subtotal`). 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."},"shipping_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"shipping_address_id":{"description":"Ship To.","example":"117KfwwfreX15N","type":["string","null"]},"tax_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Tax. 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."},"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The invoice total. 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."},"version":{"example":2,"type":"integer"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change an invoice number (v1)","tags":["Invoices"],"x-yoprint-docs":{"errors":[{"fix":"Send the number as a JSON string.","status":422,"when":"`scoped_id` is missing or not a string."},{"fix":"Check the hash id.","status":404,"when":"The invoice isn't your team's."}],"group":"Invoices and payments","patch":"same_as_put","permission":"Any member of the team; no sales order permission is checked.","prefer":"v2_public_invoice_update","related":["v2_public_invoice_update"],"side_effects":["Saves the number only: no recalculation, no QuickBooks Online sync trigger, no refresh of open web app pages."],"status":"legacy"}}},"/v1/api/store/{team_slug}/is_authenticated":{"get":{"description":"Answers `200` with `{\"is_authenticated\": true}` when the key is valid and its owner is a member of the team in the path. It reads nothing else and changes nothing, so it is the cheapest way to test a key before you build on it.\n\n- `401` means the key is missing, wrong or was reset.\n- `404` means the team slug does not exist, or the key's owner is not a member of that team.\n\nSend the key as `Authorization: Bearer YOUR_API_KEY`.","operationId":"v1_public_misc_is_authenticated","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"is_authenticated":true},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"is_authenticated":{"const":true,"description":"Always true. Failures are 401 or 404, never false.","type":"boolean"}},"required":["is_authenticated"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Check that your API key works for a team","tags":["API key"],"x-yoprint-docs":{"errors":[{"fix":"Send `Authorization: Bearer YOUR_API_KEY` with the current key from your Profile page.","status":401,"when":"No key was sent, or the key is wrong or was reset."},{"fix":"Check the team slug, and use a key that belongs to a member of that team.","status":404,"when":"The team slug does not exist, or the key's owner is not a member of that team."}],"group":"Account","notes":["The response never says `false`. Treat any non-200 answer as \"not authenticated for this team\".","A key belongs to a person, not to a team. The same key works for every team its owner belongs to; change the slug in the path.","Send the key in one place only. If you send it more than once, the `user_api_key` query parameter wins, then a `user_api_key` body field, then the `Authorization` header; a wrong key in the first place found is not retried from the next.","Only personal API keys work on the public API. Tokens issued to AI apps are refused with 401."],"permission":"Any valid personal API key whose owner belongs to the team.","side_effects":["Counts as a use of the key: the \"last used\" time on your Profile page updates."]}}},"/v1/api/store/{team_slug}/job":{"get":{"description":"Returns one page of your team's jobs, across all sales orders.\n\nOnly jobs on sales orders are listed: quotes, drafts and deleted jobs are left out. Each job is the full job (as in Get one job of an order) without `services`, `pipelines` and `pending_approval`; `mockup` and `production_file` are included.\n\nThe order is not guaranteed. To filter or sort, use Filter jobs. To list the jobs of one sales order, use List the jobs of a sales order or quote.","operationId":"v1_public_job_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The page to read. The page size is the team's list page size setting (50 unless the team changed it).","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"assigned_users":[],"auto_saved_for":null,"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"due_date":"2026-11-06T17:00:00+00:00","id":"WaGvtaWsx7Kcn4","is_rush":true,"item_count":48,"mockup":[],"name":"Front print","note":null,"order_id":"sFbALVSYD55eXe","order_scoped_id":"SO1001","pdf":[{"description":"Job details without mockup","label":"Job Details","url":"https://example.com/pdf/job-details.pdf"}],"position":1,"pricing_original_total":{"dp":6,"value":600000000},"pricing_rule_applied":null,"pricing_total":{"dp":6,"value":600000000},"production_file":[],"sales_order":{"is_quote":false,"is_rush":false,"name":"Team shirts","object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"scoped_id":"JOB-2419","start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"scaWHQnPLtqMPT","label":"Printing","position":3,"role":"job","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"scaWHQnPLtqMPT","status_last_change_date":"2026-11-03T15:05:00+00:00","total_qty_need_ordering":"0.00000000","unique_key":"job_EXAMPLEuniqueKey"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A job (without services, tasks and approvals; with its mockups and production files).","properties":{"approval_ready_mockup_design_count":{"type":"integer"},"assigned_users":{"description":"People on the job.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"auto_saved_for":{"description":"Set only on autosave copies.","example":null,"type":["string","null"]},"customer":{"additionalProperties":true,"properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"name":{"example":"Northwind Apparel","type":["string","null"]}},"type":"object"},"due_date":{"description":"Production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"from_legacy":{"type":"boolean"},"has_service":{"description":"Kept for older clients; not a count of services.","type":"boolean"},"id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"impression_count":{"type":["number","null"]},"inventory_status":{"description":"The stock status of the job's lines.","type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Units on the job.","example":48,"type":["number","null"]},"location_count":{"type":["number","null"]},"mockup":{"description":"Mockup files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"mockup_design_count":{"type":"integer"},"mockup_summary":{"additionalProperties":true,"properties":{"count":{"type":"integer"},"has_mockups":{"type":"boolean"}},"type":"object"},"name":{"example":"Team shirts","type":["string","null"]},"need_cust_provide_product":{"description":"Blanks are provided by the customer.","type":["boolean","integer","null"]},"note":{"type":["string","null"]},"order_customer_po_number":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pdf":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Job Details","type":"string"},"url":{"description":"A download link that carries its own long-lived access token: don't publish it.","example":"https://example.com/pdf/job-details.pdf","format":"uri","type":"string"}},"type":"object"},"type":"array"},"position":{"example":1,"type":["integer","null"]},"pricing_original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price before pricing rules, at the stored scale. 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_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null. These answers usually carry only `type`, the two ids and the two totals. List the jobs of a sales order or quote and Get one job of a sales order or quote answer with the full summary (the rule's current name and position, the prices before and after).","oneOf":[{"additionalProperties":true,"properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","type":["string","null"]},"after_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price after the rule. 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."},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","type":["string","null"]},"base_type":{"description":"Full summary only: `service_price`.","type":["string","null"]},"normal_price":{"description":"Full summary only: the price with no rule (the same as `base` for a job).","type":["string","null"]},"original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price before the rule. 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_id":{"description":"The pricing group.","example":"V4keXwwxMQyXw7","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The pricing rule.","example":"V4keXwwxMQyXw7","type":["string","null"]},"rule":{"description":"Full summary only: the rule as the group holds it now (`id`, `label`, `position`, where 1 is the first rule checked), or null when it no longer exists.","type":["object","null"]},"type":{"description":"`service` on a job.","type":["string","null"]}},"type":"object"},{"type":"null"}]},"pricing_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price, at the stored scale (usually 6 decimal places: `{ \"value\": 600000000, \"dp\": 6 }` is 600.00). 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."},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"qr_code_url":{"description":"A QR code image for the job.","example":"https://example.com/qr/job.png","type":["string","null"]},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"name":{"description":"Order name.","example":"Team shirts","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number as shown, with its `JOB-` prefix. Change a job number takes only the digits.","example":"JOB-2419","type":"string"},"services_still_valid":{"type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The job's current status: its production stage. Look it up in List job statuses, or read `status`.","example":"scaWHQnPLtqMPT","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"total_qty_need_ordering":{"description":"Quantity that still needs ordering, with 8 decimal places (`\"12.00000000\"`). A decimal string, such as `\"0.00000000\"`; parse it as a decimal.","example":"0.00000000","type":["string","null"]},"unique_key":{"description":"The job's unique key.","example":"job_EXAMPLEuniqueKey","type":["string","null"]},"version":{"example":2,"type":"integer"}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List jobs","tags":["Jobs"],"x-yoprint-docs":{"group":"Production","notes":["The response is one page with `pagination`. The page size is the team's list page size setting (50 unless the team changed it); `per_page` is not read. Send `page` (from 1) in the body or the query string for later pages."],"permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_job_filter","v2_public_job_show","v2_public_job_index_for_order"]}}},"/v1/api/store/{team_slug}/job/calendar":{"post":{"description":"Jobs whose start or due date falls in the range, or whose dates span it. Send `page` (an integer from 1) and optionally `per_page` (blank means 500, otherwise an integer from 1 to 1000) to read the range page by page: the response is that page of the whole range, uncapped, with `pagination`. Without `page`, or with a blank one, the response holds at most 1,200 rows and no `pagination`, and `per_page` is ignored. Any other `page` or `per_page` value is a 422 that names the field. Rows follow the requested sort, then id, so pages never overlap or skip.\n\nThe range runs from the start of the day of `start_date` to the end of the day of `end_date`. Send both as ISO 8601 date-times in UTC (`2026-11-01T00:00:00Z`): the day boundaries are taken from the date as written.\n\nEach job is the full job with its tasks (`pipelines`), `mockup` and `production_file`; `services` and `pending_approval` are left out. Only jobs on sales orders are listed: quotes, drafts and deleted jobs are left out.\n\nYou can narrow the range with the same `filters` and `sort` as Filter jobs. A date filter's `value` is a whole number of days, counted from the moment of the request in UTC: `eq` N matches the whole UTC day N days from today (0 is today, -1 yesterday); `gte` N matches dates on or after now plus N days; `lte` N matches dates on or before now **minus** N days. So \"due in the next 7 days\" is `due_date gte 0` and `due_date lte -7`, and \"overdue\" is `due_date lte 0`. This differs from the v2 filters (Filter invoices, the production control calendar), where `lte` and `gte` both count forward.","operationId":"v1_public_job_calendar","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-11-30T00:00:00Z","filters":[{"key":"status_type","operator":"nin","value":["end"]}],"page":1,"per_page":500,"start_date":"2026-11-01T00:00:00Z"},"schema":{"properties":{"end_date":{"description":"The last day of the range (ISO 8601). The range ends at the end of this day.","format":"date-time","type":"string"},"filters":{"description":"Conditions, all of which must match. Omit for no filter.","items":{"properties":{"key":{"description":"What to filter on. See the table in the description.","enum":["status_id","status_type","is_rush","start_date","due_date","start_date_is_set","due_date_is_set","need_cust_provide_product","job_has_pipelines","has_any_pipelines","status_last_change_date","status_completion_date","total_qty_need_ordering","order_created_by","search"],"type":"string"},"operator":{"description":"How to compare. Each kind of key accepts only some operators.","enum":["eq","neq","gt","gte","lt","lte","in","nin","bt","ct","sw","ew"],"type":"string"},"value":{"description":"What to compare with: text, a number of days, true or false, or an array of hash ids or options, by kind of key.","items":{"type":"string"},"type":["string","number","boolean","array"]}},"required":["key","operator","value"],"type":"object"},"minItems":1,"type":"array"},"page":{"description":"Read the range page by page. Without it, at most 1,200 jobs come back and no `pagination`.","minimum":1,"type":"integer"},"per_page":{"default":500,"description":"Page size when `page` is sent. Ignored without `page`.","maximum":1000,"minimum":1,"type":["integer","null"]},"sort":{"description":"Sort keys, applied in order, then by job id. Without `sort` the jobs come by job id.","items":{"properties":{"direction":{"enum":["asc","desc"],"type":"string"},"key":{"enum":["id","due_date","order_id","status_id","start_date","impression_count","item_count","scoped_id","is_rush","position","status_last_change_date","status_completion_date","order_due_date","order_ship_due_date","order_cust_due_date","order_issue_date","total_qty_need_ordering","order_ship_due_date_undated_last","created_at_id"],"type":"string"}},"required":["key","direction"],"type":"object"},"type":"array"},"start_date":{"description":"The first day of the range (ISO 8601). The range starts at the start of this day.","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"assigned_users":[],"auto_saved_for":null,"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"due_date":"2026-11-06T17:00:00+00:00","id":"WaGvtaWsx7Kcn4","is_rush":true,"item_count":48,"mockup":[],"name":"Front print","note":null,"order_id":"sFbALVSYD55eXe","order_scoped_id":"SO1001","pdf":[{"description":"Job details without mockup","label":"Job Details","url":"https://example.com/pdf/job-details.pdf"}],"pipelines":[{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-05T17:00:00+00:00","id":"hpioY1gDBQZdbI","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"hTFITko5Q0R83y","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T15:05:00+00:00"}],"position":1,"pricing_original_total":{"dp":6,"value":600000000},"pricing_rule_applied":null,"pricing_total":{"dp":6,"value":600000000},"production_file":[],"sales_order":{"is_quote":false,"is_rush":false,"name":"Team shirts","object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"scoped_id":"JOB-2419","start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"scaWHQnPLtqMPT","label":"Printing","position":3,"role":"job","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"scaWHQnPLtqMPT","status_last_change_date":"2026-11-03T15:05:00+00:00","total_qty_need_ordering":"0.00000000","unique_key":"job_EXAMPLEuniqueKey"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":500,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A job with its tasks (`pipelines`), mockups and production files.","properties":{"approval_ready_mockup_design_count":{"type":"integer"},"assigned_users":{"description":"People on the job.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"auto_saved_for":{"description":"Set only on autosave copies.","example":null,"type":["string","null"]},"customer":{"additionalProperties":true,"properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"name":{"example":"Northwind Apparel","type":["string","null"]}},"type":"object"},"due_date":{"description":"Production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"from_legacy":{"type":"boolean"},"has_service":{"description":"Kept for older clients; not a count of services.","type":"boolean"},"id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"impression_count":{"type":["number","null"]},"inventory_status":{"description":"The stock status of the job's lines.","type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Units on the job.","example":48,"type":["number","null"]},"location_count":{"type":["number","null"]},"mockup":{"description":"Mockup files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"mockup_design_count":{"type":"integer"},"mockup_summary":{"additionalProperties":true,"properties":{"count":{"type":"integer"},"has_mockups":{"type":"boolean"}},"type":"object"},"name":{"example":"Team shirts","type":["string","null"]},"need_cust_provide_product":{"description":"Blanks are provided by the customer.","type":["boolean","integer","null"]},"note":{"type":["string","null"]},"order_customer_po_number":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pdf":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Job Details","type":"string"},"url":{"description":"A download link that carries its own long-lived access token: don't publish it.","example":"https://example.com/pdf/job-details.pdf","format":"uri","type":"string"}},"type":"object"},"type":"array"},"pipelines":{"description":"The job's tasks.","items":{"additionalProperties":true,"description":"A task.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"type":"array"},"position":{"example":1,"type":["integer","null"]},"pricing_original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price before pricing rules, at the stored scale. 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_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null. These answers usually carry only `type`, the two ids and the two totals. List the jobs of a sales order or quote and Get one job of a sales order or quote answer with the full summary (the rule's current name and position, the prices before and after).","oneOf":[{"additionalProperties":true,"properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","type":["string","null"]},"after_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price after the rule. 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."},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","type":["string","null"]},"base_type":{"description":"Full summary only: `service_price`.","type":["string","null"]},"normal_price":{"description":"Full summary only: the price with no rule (the same as `base` for a job).","type":["string","null"]},"original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price before the rule. 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_id":{"description":"The pricing group.","example":"V4keXwwxMQyXw7","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The pricing rule.","example":"V4keXwwxMQyXw7","type":["string","null"]},"rule":{"description":"Full summary only: the rule as the group holds it now (`id`, `label`, `position`, where 1 is the first rule checked), or null when it no longer exists.","type":["object","null"]},"type":{"description":"`service` on a job.","type":["string","null"]}},"type":"object"},{"type":"null"}]},"pricing_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price, at the stored scale (usually 6 decimal places: `{ \"value\": 600000000, \"dp\": 6 }` is 600.00). 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."},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"qr_code_url":{"description":"A QR code image for the job.","example":"https://example.com/qr/job.png","type":["string","null"]},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"name":{"description":"Order name.","example":"Team shirts","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number as shown, with its `JOB-` prefix. Change a job number takes only the digits.","example":"JOB-2419","type":"string"},"services_still_valid":{"type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The job's current status: its production stage. Look it up in List job statuses, or read `status`.","example":"scaWHQnPLtqMPT","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"total_qty_need_ordering":{"description":"Quantity that still needs ordering, with 8 decimal places (`\"12.00000000\"`). A decimal string, such as `\"0.00000000\"`; parse it as a decimal.","example":"0.00000000","type":["string","null"]},"unique_key":{"description":"The job's unique key.","example":"job_EXAMPLEuniqueKey","type":["string","null"]},"version":{"example":2,"type":"integer"}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List jobs in a date range","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Send ISO 8601 dates and valid paging and filters. The error names the field.","status":422,"when":"A date is missing or not ISO 8601; `page` is filled but not an integer from 1; `per_page` is outside 1 to 1000; or a filter is invalid."}],"group":"Production","notes":["Without `page` you get the first 1,200 jobs of the range in the order you asked for (by id when you send no `sort`). A busy range can hold more: send `page` and read until `pagination.currentPage` equals `pagination.totalPages`."],"permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_job_filter","v1_public_work_pipeline_calendar","v1_public_production_control_filter"],"rules":["`start_date` and `end_date` are required ISO 8601 dates.","A job is in the range when its start date or its due date falls in it, or it starts before the range and is due after it. Undated jobs never appear."]}}},"/v1/api/store/{team_slug}/job/export_dymo_label":{"post":{"description":"Returns one PDF of small job labels sized 1\" x 2-1/8\" (Dymo), one label per job. The PDF is made while you wait and nothing is stored.","operationId":"v1_public_job_export_dymo_label","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"WaGvtaWsx7Kcn4"},{"id":"6E8Ybl4wnA5yBW"}],"schema":{"description":"The jobs to include, as a JSON array of objects (not an object with a list inside).","items":{"properties":{"id":{"description":"The hash id of one of the jobs.","example":"WaGvtaWsx7Kcn4","type":"string"}},"required":["id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"The labels as a PDF, shown inline (`Content-Disposition: inline`)."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download small job labels (PDF)","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Send at most 100 `{ \"id\": ... }` objects.","status":422,"when":"More than 100 ids (`limit_reached`), or an item without a valid `id`."},{"fix":"Send job hash ids from List jobs.","status":404,"when":"None of the ids is a job of your team (`job_not_found`)."}],"group":"Production","permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_job_export_job_label","v1_public_job_filter"],"rules":["Send between 1 and 100 ids. More than 100 is a 422 `limit_reached` (\"we only allow export of 100 jobs at a time\").","Ids that aren't jobs of your team are skipped. When none is left the response is a 404."]}}},"/v1/api/store/{team_slug}/job/export_job_detail":{"post":{"description":"Returns one PDF with the details of each job (work order style), without mockup images. To include mockups, use Download job details with mockups. The PDF is made while you wait and nothing is stored.","operationId":"v1_public_job_export_job_detail","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"WaGvtaWsx7Kcn4"},{"id":"6E8Ybl4wnA5yBW"}],"schema":{"description":"The jobs to include, as a JSON array of objects (not an object with a list inside).","items":{"properties":{"id":{"description":"The hash id of one of the jobs.","example":"WaGvtaWsx7Kcn4","type":"string"}},"required":["id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"The job details as a PDF, shown inline (`Content-Disposition: inline`)."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download job details (PDF)","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Send at most 100 `{ \"id\": ... }` objects.","status":422,"when":"More than 100 ids (`limit_reached`), or an item without a valid `id`."},{"fix":"Send job hash ids from List jobs.","status":404,"when":"None of the ids is a job of your team (`job_not_found`)."}],"group":"Production","permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_job_export_job_detail_mockup","v1_public_job_export_job_list"],"rules":["Send between 1 and 100 ids. More than 100 is a 422 `limit_reached` (\"we only allow export of 100 jobs at a time\").","Ids that aren't jobs of your team are skipped. When none is left the response is a 404."]}}},"/v1/api/store/{team_slug}/job/export_job_detail_mockup":{"post":{"description":"Returns one PDF with the details of each job, including its mockups. Otherwise the same as Download job details. The PDF is made while you wait and nothing is stored.","operationId":"v1_public_job_export_job_detail_mockup","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"WaGvtaWsx7Kcn4"},{"id":"6E8Ybl4wnA5yBW"}],"schema":{"description":"The jobs to include, as a JSON array of objects (not an object with a list inside).","items":{"properties":{"id":{"description":"The hash id of one of the jobs.","example":"WaGvtaWsx7Kcn4","type":"string"}},"required":["id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"The job details as a PDF, shown inline (`Content-Disposition: inline`)."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download job details with mockups (PDF)","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Send at most 100 `{ \"id\": ... }` objects.","status":422,"when":"More than 100 ids (`limit_reached`), or an item without a valid `id`."},{"fix":"Send job hash ids from List jobs.","status":404,"when":"None of the ids is a job of your team (`job_not_found`)."}],"group":"Production","notes":["Mockup images make the PDF larger and slower to build than Download job details."],"permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_job_export_job_detail"],"rules":["Send between 1 and 100 ids. More than 100 is a 422 `limit_reached` (\"we only allow export of 100 jobs at a time\").","Ids that aren't jobs of your team are skipped. When none is left the response is a 404."]}}},"/v1/api/store/{team_slug}/job/export_job_label":{"post":{"description":"Returns one PDF of 4\" x 6\" job labels, one per job. The PDF is made while you wait and nothing is stored.","operationId":"v1_public_job_export_job_label","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"WaGvtaWsx7Kcn4"},{"id":"6E8Ybl4wnA5yBW"}],"schema":{"description":"The jobs to include, as a JSON array of objects (not an object with a list inside).","items":{"properties":{"id":{"description":"The hash id of one of the jobs.","example":"WaGvtaWsx7Kcn4","type":"string"}},"required":["id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"The labels as a PDF, shown inline (`Content-Disposition: inline`)."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download job labels (PDF)","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Send at most 100 job hash ids of your team.","status":422,"when":"More than 100 ids (`limit_reached`); an item without a valid `id`; or none of the ids is a job of your team (the error code is `no_invoice_found`, even though these are jobs)."}],"group":"Production","permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_job_export_dymo_label","v1_public_job_filter"],"rules":["Send between 1 and 100 ids. More than 100 is a 422 `limit_reached` (\"we only allow export of 100 jobs at a time\").","Ids that aren't jobs of your team are skipped. When none is left the response is a 404."]}}},"/v1/api/store/{team_slug}/job/export_job_list":{"post":{"description":"Returns one PDF that lists the jobs in a table, stamped with the time it was made. The PDF is made while you wait and nothing is stored.","operationId":"v1_public_job_export_job_list","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"WaGvtaWsx7Kcn4"},{"id":"6E8Ybl4wnA5yBW"}],"schema":{"description":"The jobs to include, as a JSON array of objects (not an object with a list inside).","items":{"properties":{"id":{"description":"The hash id of one of the jobs.","example":"WaGvtaWsx7Kcn4","type":"string"}},"required":["id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"The job list as a PDF, shown inline (`Content-Disposition: inline`)."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download a job list (PDF)","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Send at most 100 `{ \"id\": ... }` objects.","status":422,"when":"More than 100 ids (`limit_reached`), or an item without a valid `id`."},{"fix":"Send job hash ids from List jobs.","status":404,"when":"None of the ids is a job of your team (`job_not_found`)."}],"group":"Production","permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_job_export_job_detail","v1_public_job_filter"],"rules":["Send between 1 and 100 ids. More than 100 is a 422 `limit_reached` (\"we only allow export of 100 jobs at a time\").","Ids that aren't jobs of your team are skipped. When none is left the response is a 404."]}}},"/v1/api/store/{team_slug}/job/filter":{"post":{"description":"Returns one page of your team's jobs that match the filters, in the order you ask for.\n\nOnly jobs on sales orders are listed: quotes, drafts and deleted jobs are left out. Each job is the full job (as in Get one job of an order) without `services`, `pipelines` and `pending_approval`; `mockup` and `production_file` are included.\n\nEvery condition in `filters` must match (they are joined with AND). Omit `filters` for no filter; an empty array is a 422. A `key` that isn't in the table, a missing `operator` or `value`, or a value of the wrong kind fails the whole request with 422; the message for `filters` (or `sort`) is the bare rule name `validation.filter_rule` (or `validation.filter_sort_rule`), with no detail, so check each filter against the table. Send real values: no key here matches empty columns with `\"null\"` or `\"\"` (for dates, use the `..._is_set` keys where the table has them). Hash ids in `value` are decoded for you. `system-current-user` stands for the caller only where a key's row says so; elsewhere it is compared as a raw value, so with `in` it matches nothing and with `nin` it matches every row that has a value.\n\n| `key` | Kind | Operators and `value` | Meaning |\n| --- | --- | --- | --- |\n| `status_id` | Hash ids | `in` or `nin`, with an array of hash ids. | The job status (hash ids from List job statuses). |\n| `status_type` | Options | `in` or `nin`, with an array of the listed values. | The kind of status: `start` (Pending), `pre_production` or `in_progress` (In Progress), `end` (Completed). |\n| `is_rush` | Yes or no | `eq` or `neq`, with `true` or `false`. | Rush jobs. |\n| `start_date` | Date | `eq`, `gte` or `lte`, with a whole number of days counted from now (UTC). See below. | The job's start date. |\n| `due_date` | Date | `eq`, `gte` or `lte`, with a whole number of days counted from now (UTC). See below. | The job's due date. |\n| `start_date_is_set` | Yes or no | `eq` or `neq`, with `true` or `false`. | The job has a start date (`eq true`) or none (`eq false`). Use `eq` only: any `neq` means \"has the date\". |\n| `due_date_is_set` | Yes or no | `eq` or `neq`, with `true` or `false`. | The job has a due date (`eq true`) or none (`eq false`). Use `eq` only: any `neq` means \"has the date\". |\n| `need_cust_provide_product` | Yes or no | `eq` or `neq`, with `true` or `false`. | Blanks are provided by the customer. |\n| `job_has_pipelines` | Hash ids | `in` or `nin`, with an array of hash ids. | The job has a task from one of these task presets. With `nin` it matches jobs that have a task from a preset outside the list, not jobs without those presets. |\n| `has_any_pipelines` | Yes or no | `eq` or `neq`, with `true` or `false`. | The job has at least one task. The operator and value aren't read: it always means \"has a task\". |\n| `status_last_change_date` | Date | `eq`, `gte` or `lte`, with a whole number of days counted from now (UTC). See below. | When the status last changed. |\n| `status_completion_date` | Date | `eq`, `gte` or `lte`, with a whole number of days counted from now (UTC). See below. | When the job reached a Completed status. |\n| `total_qty_need_ordering` | Number | `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, with a number. | The quantity that still needs ordering. |\n| `order_created_by` | Hash ids | `in` or `nin`, with an array of hash ids. | Who created the sales order (user hash ids). `system-current-user` is not supported here: with `in` it matches nothing, with `nin` everything. |\n| `search` | Text search | Any operator (`ct` reads best). The value must not be empty. | Job name, job number (`JOB-2419`, `2419` and `#2419` all match), order number, order name, customer PO and customer name. Every one of the first five words must match. |\n\nA date filter's `value` is a whole number of days, counted from the moment of the request in UTC: `eq` N matches the whole UTC day N days from today (0 is today, -1 yesterday); `gte` N matches dates on or after now plus N days; `lte` N matches dates on or before now **minus** N days. So \"due in the next 7 days\" is `due_date gte 0` and `due_date lte -7`, and \"overdue\" is `due_date lte 0`. This differs from the v2 filters (Filter invoices, the production control calendar), where `lte` and `gte` both count forward.\n\nThe response is one page with `pagination`. The page size is the team's list page size setting (50 unless the team changed it); `per_page` is not read. Send `page` (from 1) in the body or the query string for later pages.","operationId":"v1_public_job_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"filters":[{"key":"status_type","operator":"in","value":["start","in_progress"]},{"key":"due_date","operator":"lte","value":-7}],"page":1,"sort":[{"direction":"asc","key":"due_date"}]},"schema":{"properties":{"filters":{"description":"Conditions, all of which must match. Omit for no filter.","items":{"properties":{"key":{"description":"What to filter on. See the table in the description.","enum":["status_id","status_type","is_rush","start_date","due_date","start_date_is_set","due_date_is_set","need_cust_provide_product","job_has_pipelines","has_any_pipelines","status_last_change_date","status_completion_date","total_qty_need_ordering","order_created_by","search"],"type":"string"},"operator":{"description":"How to compare. Each kind of key accepts only some operators.","enum":["eq","neq","gt","gte","lt","lte","in","nin","bt","ct","sw","ew"],"type":"string"},"value":{"description":"What to compare with: text, a number of days, true or false, or an array of hash ids or options, by kind of key.","items":{"type":"string"},"type":["string","number","boolean","array"]}},"required":["key","operator","value"],"type":"object"},"minItems":1,"type":"array"},"page":{"default":1,"description":"The page to read.","minimum":1,"type":"integer"},"sort":{"description":"Sort keys, applied in order. Without `sort` the order is not guaranteed.","items":{"properties":{"direction":{"enum":["asc","desc"],"type":"string"},"key":{"enum":["id","due_date","order_id","status_id","start_date","impression_count","item_count","scoped_id","is_rush","position","status_last_change_date","status_completion_date","order_due_date","order_ship_due_date","order_cust_due_date","order_issue_date","total_qty_need_ordering","order_ship_due_date_undated_last","created_at_id"],"type":"string"}},"required":["key","direction"],"type":"object"},"type":"array"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"assigned_users":[],"auto_saved_for":null,"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"due_date":"2026-11-06T17:00:00+00:00","id":"WaGvtaWsx7Kcn4","is_rush":true,"item_count":48,"mockup":[],"name":"Front print","note":null,"order_id":"sFbALVSYD55eXe","order_scoped_id":"SO1001","pdf":[{"description":"Job details without mockup","label":"Job Details","url":"https://example.com/pdf/job-details.pdf"}],"position":1,"pricing_original_total":{"dp":6,"value":600000000},"pricing_rule_applied":null,"pricing_total":{"dp":6,"value":600000000},"production_file":[],"sales_order":{"is_quote":false,"is_rush":false,"name":"Team shirts","object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"scoped_id":"JOB-2419","start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"scaWHQnPLtqMPT","label":"Printing","position":3,"role":"job","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"scaWHQnPLtqMPT","status_last_change_date":"2026-11-03T15:05:00+00:00","total_qty_need_ordering":"0.00000000","unique_key":"job_EXAMPLEuniqueKey"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A job (without services, tasks and approvals; with its mockups and production files).","properties":{"approval_ready_mockup_design_count":{"type":"integer"},"assigned_users":{"description":"People on the job.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"auto_saved_for":{"description":"Set only on autosave copies.","example":null,"type":["string","null"]},"customer":{"additionalProperties":true,"properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"name":{"example":"Northwind Apparel","type":["string","null"]}},"type":"object"},"due_date":{"description":"Production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"from_legacy":{"type":"boolean"},"has_service":{"description":"Kept for older clients; not a count of services.","type":"boolean"},"id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"impression_count":{"type":["number","null"]},"inventory_status":{"description":"The stock status of the job's lines.","type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Units on the job.","example":48,"type":["number","null"]},"location_count":{"type":["number","null"]},"mockup":{"description":"Mockup files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"mockup_design_count":{"type":"integer"},"mockup_summary":{"additionalProperties":true,"properties":{"count":{"type":"integer"},"has_mockups":{"type":"boolean"}},"type":"object"},"name":{"example":"Team shirts","type":["string","null"]},"need_cust_provide_product":{"description":"Blanks are provided by the customer.","type":["boolean","integer","null"]},"note":{"type":["string","null"]},"order_customer_po_number":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pdf":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Job Details","type":"string"},"url":{"description":"A download link that carries its own long-lived access token: don't publish it.","example":"https://example.com/pdf/job-details.pdf","format":"uri","type":"string"}},"type":"object"},"type":"array"},"position":{"example":1,"type":["integer","null"]},"pricing_original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price before pricing rules, at the stored scale. 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_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null. These answers usually carry only `type`, the two ids and the two totals. List the jobs of a sales order or quote and Get one job of a sales order or quote answer with the full summary (the rule's current name and position, the prices before and after).","oneOf":[{"additionalProperties":true,"properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","type":["string","null"]},"after_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price after the rule. 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."},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","type":["string","null"]},"base_type":{"description":"Full summary only: `service_price`.","type":["string","null"]},"normal_price":{"description":"Full summary only: the price with no rule (the same as `base` for a job).","type":["string","null"]},"original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price before the rule. 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_id":{"description":"The pricing group.","example":"V4keXwwxMQyXw7","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The pricing rule.","example":"V4keXwwxMQyXw7","type":["string","null"]},"rule":{"description":"Full summary only: the rule as the group holds it now (`id`, `label`, `position`, where 1 is the first rule checked), or null when it no longer exists.","type":["object","null"]},"type":{"description":"`service` on a job.","type":["string","null"]}},"type":"object"},{"type":"null"}]},"pricing_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price, at the stored scale (usually 6 decimal places: `{ \"value\": 600000000, \"dp\": 6 }` is 600.00). 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."},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"qr_code_url":{"description":"A QR code image for the job.","example":"https://example.com/qr/job.png","type":["string","null"]},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"name":{"description":"Order name.","example":"Team shirts","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number as shown, with its `JOB-` prefix. Change a job number takes only the digits.","example":"JOB-2419","type":"string"},"services_still_valid":{"type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The job's current status: its production stage. Look it up in List job statuses, or read `status`.","example":"scaWHQnPLtqMPT","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"total_qty_need_ordering":{"description":"Quantity that still needs ordering, with 8 decimal places (`\"12.00000000\"`). A decimal string, such as `\"0.00000000\"`; parse it as a decimal.","example":"0.00000000","type":["string","null"]},"unique_key":{"description":"The job's unique key.","example":"job_EXAMPLEuniqueKey","type":["string","null"]},"version":{"example":2,"type":"integer"}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Filter jobs","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Check each filter against the table. Leave `filters` out to read everything.","status":422,"when":"A filter has an unknown `key`, a missing part, or an operator or value its kind doesn't accept; or `filters` is an empty array."}],"group":"Production","notes":["Status ids come from List job statuses; task preset ids from List task presets."],"permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_job_index","v1_public_job_calendar","v1_public_status_list_job","v1_public_pipeline_index"],"rules":["Status types are `start` (Pending), `pre_production` and `in_progress` (In Progress), and `end` (Completed).","A sort `key` that isn't listed, or a `direction` other than `asc` or `desc`, is a 422."]}}},"/v1/api/store/{team_slug}/job/{hash_id}":{"get":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_job_show` (GET /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/job/{job_id}) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nRetired. This v1 route always fails with HTTP 500 and the bare body `{ \"message\": \"Server Error\" }` (the deprecation text is not shown in production). Use Get one job of an order on the v2 API, which reads a job through its sales order.","operationId":"v1_public_job_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"WaGvtaWsx7Kcn4","in":"path","name":"hash_id","required":true,"schema":{"example":"WaGvtaWsx7Kcn4","type":"string"}}],"responses":{"200":{"description":"Never sent: this retired route always fails with HTTP 500."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a job (retired)","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Use the v2 route.","status":404,"when":"The id is not one of your team's hash ids (checked before the 500)."},{"fix":"Call Get one job of an order (`GET /v2/sales_order/{hash_id}/job/{job_id}`) instead.","status":500,"when":"Always, as `{ \"message\": \"Server Error\" }`."}],"group":"Production","prefer":"v2_public_job_show","related":["v2_public_job_show"],"status":"legacy"}}},"/v1/api/store/{team_slug}/job/{hash_id}/status":{"put":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_job_change_status` (PUT /v2/api/store/{team_slug}/v2/job/{hash_id}/status) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nRetired. This v1 route validates the body, then always fails with HTTP 500 and the bare body `{ \"message\": \"Server Error\" }` (the deprecation text is not shown in production). Nothing changes. Use Change a job's status on the v2 API.","operationId":"v1_public_job_change_status","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"WaGvtaWsx7Kcn4","in":"path","name":"hash_id","required":true,"schema":{"example":"WaGvtaWsx7Kcn4","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"status_id":"scaWHQnPLtqMPT"},"schema":{"properties":{"notify_customer":{"description":"Accepted and ignored.","type":["boolean","null"]},"status_id":{"description":"A job status hash id.","example":"V4keXwwxMQyXw7","type":"string"}},"required":["status_id"],"type":"object"}}},"required":true},"responses":{"200":{"description":"Never sent: this retired route always fails with HTTP 500."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change a job's status (retired)","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Send a job status hash id.","status":422,"when":"`status_id` is missing or not a hash id."},{"fix":"Use the v2 route.","status":404,"when":"The id is not one of your team's hash ids (checked first)."},{"fix":"Call `PUT /v2/job/{hash_id}/status` instead.","status":500,"when":"Always, after validation, as `{ \"message\": \"Server Error\" }`. Nothing changes."}],"group":"Production","prefer":"v2_public_job_change_status","related":["v2_public_job_change_status"],"status":"legacy"}}},"/v1/api/store/{team_slug}/misc/calc_tax":{"post":{"description":"Returns the US sales tax rate YoPrint's automatic sales tax would apply when shipping to an address, and whether shipping is taxable. It returns a rate, not a tax amount, and saves nothing.\n\nThe rate is tax-free (`type` `tax_free`, `total` 0) when your team is not on a US plan, the customer is tax exempt, the address is outside the US, your team has no nexus address in the address's state, or that state has no sales tax. Otherwise YoPrint locates the address and looks up its combined rate, applying each state's origin or destination rules.\n\n`total` is the combined rate as the percentage × 10,000: 8.25% is `82500`. This is not the thousandths used for other rates in the API (where 8.25% is `8250`).","operationId":"v1_public_misc_calc_tax","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"address_id":"RNG2OuYC20YzXs","customer_id":"63KcENAAsKuipY"},"schema":{"properties":{"address_id":{"description":"The ship-to address id: one of the customer's addresses, or one of your team's.","type":"string"},"customer_id":{"description":"Optional. The customer: their tax exemption applies, and the address must be theirs or your team's.","type":"string"}},"required":["address_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"shipping_taxable":true,"total":"82500","type":"single_tax"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"shipping_taxable":{"description":"Whether shipping charges are taxed at this address. On a tax-free answer it is often `true` and means nothing: nothing is taxed.","type":"boolean"},"total":{"description":"The combined rate, as the percentage × 10,000: 8.25% is `82500`. A string (`\"82500\"`) or a number (`82500`), depending on the state; `0` when tax-free. Parse both.","type":["integer","number","string"]},"type":{"description":"`single_tax`: one combined rate in `total`.","enum":["tax_free","single_tax"],"type":"string"}},"required":["type","total","shipping_taxable"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/FeatureGatedValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Look up the automatic sales tax rate for an address","tags":["Sales tax"],"x-yoprint-docs":{"errors":[{"fix":"Upgrade the plan, or set tax on the order yourself.","status":422,"when":"Your plan does not include automatic sales tax (a plain `{\"message\": \"This feature is not available to your team's plan.\"}` body)."},{"fix":"Send the ship-to address id.","status":422,"when":"`address_id` is missing, or `address_id` or `customer_id` is not an id of this team (`validation_failed`; `error.fields` names the field)."},{"fix":"Retry later.","status":422,"when":"The rate could not be looked up (`auto_tax_calculation_failed`, \"Auto Tax calculation failed. Please retry later.\")."},{"fix":"Use an address of this customer or of your team.","status":404,"when":"The address or customer does not exist on this team, or the address belongs to another customer."}],"group":"Sales","notes":["A tax-free answer does not say why (not US, exempt, no nexus in that state, or a state without sales tax). Check the customer's exemption and your nexus addresses if you expected tax."],"permission":"Any member of a team whose plan includes automatic sales tax.","rules":["`address_id` is required. With `customer_id`, the address must belong to that customer or to your team.","Only US destinations get a rate; everything else is tax-free."],"side_effects":["Looks the address up with an external geocoding service and a tax rate service. Results are cached, so repeat lookups are fast. Nothing is charged to your team."]}}},"/v1/api/store/{team_slug}/participant/{id}":{"delete":{"description":"Removes a person from an order's or purchase order's message thread, so they stop getting its emails and texts. Past messages still show them, marked removed (`trashed: true`). There is no restore; add them again with the order's participant operations.","operationId":"v1_public_participant_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The participant's `id`, from the order's participant list. A hash id; unique keys and document numbers are refused with 404.","example":"vKNPqQz8fsYDuT","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove a message participant","tags":["Message participants"],"x-yoprint-docs":{"errors":[{"fix":"Use an `id` from the order's participant list.","status":404,"when":"No participant of this team has this id, or it was already removed."}],"group":"Messages and activity","permission":"Any member of the team, for any participant on the team.","related":["v1_public_sales_order_participant_store","v1_public_participant_show"],"side_effects":["They stop receiving the order's customer emails and texts.","People with the order open see the change live."]}},"get":{"description":"Returns one person on an order's or purchase order's message thread: who they are (`type`), how to reach them, and what they receive (`status`, `can_receive_mail`, `can_receive_sms`).\n\nTo list or add participants, use the sales order participant operations.","operationId":"v1_public_participant_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The participant's `id`, from the order's participant list. A hash id; unique keys and document numbers are refused with 404.","example":"vKNPqQz8fsYDuT","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"can_receive_mail":true,"can_receive_sms":false,"contact":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"63KcENAAsKuipY","default_receive_sms":false,"email":"jordan@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Jordan","id":"uTCR3hxPDePBUK","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"contact_id":"uTCR3hxPDePBUK","delivery_channel":null,"delivery_created_at":null,"delivery_destination":null,"delivery_destination_name":null,"delivery_id":null,"delivery_latest_error_reason":null,"delivery_message_id":null,"delivery_participant_id":null,"delivery_state":null,"delivery_status":null,"delivery_updated_at":null,"email":"jordan@example.com","id":"vKNPqQz8fsYDuT","name":"Jordan Lee","order_id":"V4keXwwxMQyXw7","phone":"+1 201 555 0123","purchase_order_id":null,"status":"all","trashed":false,"type":"contact"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact":{"additionalProperties":true,"description":"The contact's own record (`id`, `first_name`, `last_name`, `email`, `phone`, `phone_country`, `customer_id` or `vendor_id`, and more). Null when the participant has no contact.","type":["object","null"]},"contact_id":{"type":["string","null"]},"delivery_channel":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_created_at":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_destination":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_destination_name":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_id":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_latest_error_reason":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_message_id":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_participant_id":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_state":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_status":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_updated_at":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"email":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]},"order_id":{"type":["string","null"]},"phone":{"description":"A contact's phone. Null for team members and guests.","type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"status":{"description":"What they get. The emails and texts YoPrint sends on the order by itself (approval requests, order details, reminders) go only to `all` and `message`; `notification` and `disabled` get none of them.","enum":["message","notification","all","disabled"],"type":"string"},"trashed":{"description":"Always false here: a removed participant answers 404.","type":"boolean"},"type":{"description":"`user`: a team member. `contact`: one of the customer's or vendor's contacts (name, email and phone come from the contact). `guest`: just a name and email.","enum":["user","contact","guest"],"type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a message participant","tags":["Message participants"],"x-yoprint-docs":{"errors":[{"fix":"Use an `id` from the order's participant list.","status":404,"when":"No participant of this team has this id, or it was removed."}],"group":"Messages and activity","permission":"Any member of the team, for any participant on the team.","related":["v1_public_participant_update_patch","v1_public_participant_destroy","v1_public_sales_order_participant_index"]}},"patch":{"description":"Use `PUT` to change a message participant. `PATCH` does the same but does not validate the fields: an unsupported `status` value is accepted and saved directly. Address and contact immutability rules still apply and can return 422. Leaving out `status` still resets it to `all`.","operationId":"v1_public_participant_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The participant's `id`, from the order's participant list. A hash id; unique keys and document numbers are refused with 404.","example":"vKNPqQz8fsYDuT","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"guest_to_contact":{"summary":"Turn a guest into a contact of the order's customer","value":{"contact_id":"QKyWRMoL0kTU05","status":"all","type":"contact"}},"stop_texts":{"summary":"Keep emails, stop texts","value":{"can_receive_mail":true,"can_receive_sms":false,"status":"all"}}},"schema":{"properties":{"can_receive_mail":{"description":"Unchanged when left out.","type":"boolean"},"can_receive_sms":{"description":"Unchanged when left out.","type":"boolean"},"contact_id":{"description":"A contact of your team. Used only with `type`. It must be the participant's current contact or, for a guest, a contact of the order's customer (or the purchase order's vendor) with the guest's email address.","type":"string"},"email":{"description":"Can't be changed: leave it out. Without `type`, an address other than the one stored on the participant is refused with 422 `participant_email_immutable`; the same address (ignoring case and surrounding spaces) changes nothing. Ignored with `type`.","format":"email","type":"string"},"name":{"description":"A guest's name. It is saved for contacts and team members too, but their name always comes from their own record.","type":"string"},"status":{"description":"What they receive. The emails and texts YoPrint sends on the order by itself go only to `all` and `message`. Becomes `all` when left out.","enum":["message","notification","all","disabled"],"type":"string"},"type":{"const":"contact","description":"Send `contact` together with `contact_id` to turn a guest into that contact. Sending `type` always requires `contact_id`.","type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":{"can_receive_mail":true,"can_receive_sms":false,"contact":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"63KcENAAsKuipY","default_receive_sms":false,"email":"jordan@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Jordan","id":"uTCR3hxPDePBUK","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"contact_id":"uTCR3hxPDePBUK","delivery_channel":null,"delivery_created_at":null,"delivery_destination":null,"delivery_destination_name":null,"delivery_id":null,"delivery_latest_error_reason":null,"delivery_message_id":null,"delivery_participant_id":null,"delivery_state":null,"delivery_status":null,"delivery_updated_at":null,"email":"jordan@example.com","id":"vKNPqQz8fsYDuT","name":"Jordan Lee","order_id":"V4keXwwxMQyXw7","phone":"+1 201 555 0123","purchase_order_id":null,"status":"all","trashed":false,"type":"contact"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact":{"additionalProperties":true,"description":"The contact's own record (`id`, `first_name`, `last_name`, `email`, `phone`, `phone_country`, `customer_id` or `vendor_id`, and more). Null when the participant has no contact.","type":["object","null"]},"contact_id":{"type":["string","null"]},"delivery_channel":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_created_at":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_destination":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_destination_name":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_id":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_latest_error_reason":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_message_id":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_participant_id":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_state":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_status":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_updated_at":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"email":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]},"order_id":{"type":["string","null"]},"phone":{"description":"A contact's phone. Null for team members and guests.","type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"status":{"description":"What they get. The emails and texts YoPrint sends on the order by itself (approval requests, order details, reminders) go only to `all` and `message`; `notification` and `disabled` get none of them.","enum":["message","notification","all","disabled"],"type":"string"},"trashed":{"description":"Always false here: a removed participant answers 404.","type":"boolean"},"type":{"description":"`user`: a team member. `contact`: one of the customer's or vendor's contacts (name, email and phone come from the contact). `guest`: just a name and email.","enum":["user","contact","guest"],"type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change a message participant without checks","tags":["Message participants"],"x-yoprint-docs":{"errors":[{"fix":"Send values from the lists here.","status":422,"when":"A value is not allowed, for example `status` or `email` (`PUT`) (`validation_failed`; `error.fields` names the field)."},{"fix":"Leave `email` out. To reach another address, add it as a new participant.","status":422,"when":"`email` differs from the participant's stored address (`participant_email_immutable`)."},{"fix":"Add the contact as a new participant instead.","status":422,"when":"`contact_id` would switch the participant to another contact (`participant_destination_immutable`). Only a guest can become a contact, of the order's customer (or the purchase order's vendor), with the same address."},{"fix":"Use ids from the API, and send `contact_id` whenever you send `type`.","status":404,"when":"The participant does not exist, or `type` was sent without a valid `contact_id`."}],"group":"Messages and activity","permission":"Any member of the team, for any participant on the team.","related":["v1_public_participant_show","v1_public_sales_order_participant_store"],"rules":["`status` is `message`, `notification`, `all` or `disabled`; left out, it becomes `all`.","A participant's email address can't change. Without `type`, sending an `email` other than the address stored on the participant (compared ignoring case and surrounding spaces) is refused: 422 `participant_email_immutable`, \"A recipient's email address can't be changed. Add the new address as a new recipient.\" For a contact or team member, the `email` you read comes from their own record, not from the participant, so sending it back can be refused: leave `email` out.","Sending `type` (whatever its value) needs `contact_id`, a contact of your team (otherwise 404). `type: \"guest\"` can't be used here.","The participant's contact can't be switched. `contact_id` may be the current contact (nothing changes) or, only for a guest, a contact of the order's customer (or the purchase order's vendor) whose email is the guest's address: the guest then becomes that contact. Anything else, including a team member, is refused: 422 `participant_destination_immutable`, \"A recipient can't be switched to another contact. Add the contact as a new recipient.\"","A refused change saves nothing, not even `status`."],"side_effects":["Changes what the participant receives from the order's future customer emails and texts. Past messages are unchanged.","People with the order open see the change live."]}},"put":{"description":"Changes what a participant receives on an order's or purchase order's message thread. It can't change where their messages go: a participant's email address and contact are fixed once added. To reach another address or contact, add it as a new participant with the order's participant operations, and remove this one if you like.\n\n**Always send `status`.** If you leave it out, it is reset to `all`.\n\n- To change what they receive, send `status` and, if you like, `can_receive_mail` and `can_receive_sms`.\n- To turn a guest into a contact, send `type: \"contact\"` with `contact_id`. The contact must belong to the order's customer (or the purchase order's vendor) and have the guest's email address.\n- A guest's `name` can change. For a contact or team member, name, email and phone come from their own record; change them there.","operationId":"v1_public_participant_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The participant's `id`, from the order's participant list. A hash id; unique keys and document numbers are refused with 404.","example":"vKNPqQz8fsYDuT","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"guest_to_contact":{"summary":"Turn a guest into a contact of the order's customer","value":{"contact_id":"QKyWRMoL0kTU05","status":"all","type":"contact"}},"stop_texts":{"summary":"Keep emails, stop texts","value":{"can_receive_mail":true,"can_receive_sms":false,"status":"all"}}},"schema":{"properties":{"can_receive_mail":{"description":"Unchanged when left out.","type":"boolean"},"can_receive_sms":{"description":"Unchanged when left out.","type":"boolean"},"contact_id":{"description":"A contact of your team. Used only with `type`. It must be the participant's current contact or, for a guest, a contact of the order's customer (or the purchase order's vendor) with the guest's email address.","type":"string"},"email":{"description":"Can't be changed: leave it out. Without `type`, an address other than the one stored on the participant is refused with 422 `participant_email_immutable`; the same address (ignoring case and surrounding spaces) changes nothing. Ignored with `type`.","format":"email","type":"string"},"name":{"description":"A guest's name. It is saved for contacts and team members too, but their name always comes from their own record.","type":"string"},"status":{"description":"What they receive. The emails and texts YoPrint sends on the order by itself go only to `all` and `message`. Becomes `all` when left out.","enum":["message","notification","all","disabled"],"type":"string"},"type":{"const":"contact","description":"Send `contact` together with `contact_id` to turn a guest into that contact. Sending `type` always requires `contact_id`.","type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":{"can_receive_mail":true,"can_receive_sms":false,"contact":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"63KcENAAsKuipY","default_receive_sms":false,"email":"jordan@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Jordan","id":"uTCR3hxPDePBUK","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"contact_id":"uTCR3hxPDePBUK","delivery_channel":null,"delivery_created_at":null,"delivery_destination":null,"delivery_destination_name":null,"delivery_id":null,"delivery_latest_error_reason":null,"delivery_message_id":null,"delivery_participant_id":null,"delivery_state":null,"delivery_status":null,"delivery_updated_at":null,"email":"jordan@example.com","id":"vKNPqQz8fsYDuT","name":"Jordan Lee","order_id":"V4keXwwxMQyXw7","phone":"+1 201 555 0123","purchase_order_id":null,"status":"all","trashed":false,"type":"contact"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact":{"additionalProperties":true,"description":"The contact's own record (`id`, `first_name`, `last_name`, `email`, `phone`, `phone_country`, `customer_id` or `vendor_id`, and more). Null when the participant has no contact.","type":["object","null"]},"contact_id":{"type":["string","null"]},"delivery_channel":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_created_at":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_destination":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_destination_name":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_id":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_latest_error_reason":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_message_id":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_participant_id":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_state":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_status":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"delivery_updated_at":{"description":"Always null here. Set only when the participant is read as one of a message's recipients.","type":["string","null"]},"email":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]},"order_id":{"type":["string","null"]},"phone":{"description":"A contact's phone. Null for team members and guests.","type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"status":{"description":"What they get. The emails and texts YoPrint sends on the order by itself (approval requests, order details, reminders) go only to `all` and `message`; `notification` and `disabled` get none of them.","enum":["message","notification","all","disabled"],"type":"string"},"trashed":{"description":"Always false here: a removed participant answers 404.","type":"boolean"},"type":{"description":"`user`: a team member. `contact`: one of the customer's or vendor's contacts (name, email and phone come from the contact). `guest`: just a name and email.","enum":["user","contact","guest"],"type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change a message participant","tags":["Message participants"],"x-yoprint-docs":{"errors":[{"fix":"Send values from the lists here.","status":422,"when":"A value is not allowed, for example `status` or `email` (`PUT`) (`validation_failed`; `error.fields` names the field)."},{"fix":"Leave `email` out. To reach another address, add it as a new participant.","status":422,"when":"`email` differs from the participant's stored address (`participant_email_immutable`)."},{"fix":"Add the contact as a new participant instead.","status":422,"when":"`contact_id` would switch the participant to another contact (`participant_destination_immutable`). Only a guest can become a contact, of the order's customer (or the purchase order's vendor), with the same address."},{"fix":"Use ids from the API, and send `contact_id` whenever you send `type`.","status":404,"when":"The participant does not exist, or `type` was sent without a valid `contact_id`."}],"group":"Messages and activity","permission":"Any member of the team, for any participant on the team.","related":["v1_public_participant_show","v1_public_sales_order_participant_store"],"rules":["`status` is `message`, `notification`, `all` or `disabled`; left out, it becomes `all`.","A participant's email address can't change. Without `type`, sending an `email` other than the address stored on the participant (compared ignoring case and surrounding spaces) is refused: 422 `participant_email_immutable`, \"A recipient's email address can't be changed. Add the new address as a new recipient.\" For a contact or team member, the `email` you read comes from their own record, not from the participant, so sending it back can be refused: leave `email` out.","Sending `type` (whatever its value) needs `contact_id`, a contact of your team (otherwise 404). `type: \"guest\"` can't be used here.","The participant's contact can't be switched. `contact_id` may be the current contact (nothing changes) or, only for a guest, a contact of the order's customer (or the purchase order's vendor) whose email is the guest's address: the guest then becomes that contact. Anything else, including a team member, is refused: 422 `participant_destination_immutable`, \"A recipient can't be switched to another contact. Add the contact as a new recipient.\"","A refused change saves nothing, not even `status`."],"side_effects":["Changes what the participant receives from the order's future customer emails and texts. Past messages are unchanged.","People with the order open see the change live."]}}},"/v1/api/store/{team_slug}/product":{"get":{"description":"Lists your own products (simple and variant products), paged. Supplier catalog products are not in this list.\n\nEvery live product by default, or with `status` one sale state or the deleted products (newest delete first). Each row adds `variant_count`, `phased_out_variant_count` and `deleted_variant_count` (variant products; null for simple products), `deleted_at`, and `phased_out_by` and `deleted_by` as `{id, name}` or null.\n\nThe list is paged: `pagination` gives `total`, `count`, `perPage`, `currentPage` and `totalPages`. Ask for the next page with `page`; the page size is the team's setting (50 unless changed), and `per_page` is ignored.","operationId":"v1_public_products_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"Filters the list by sale state. Leave absent for every live product.\n\n- `on_sale`: simple products on sale, and variant products with at least one live size or color on sale.\n- `phased_out`: simple products phased out, and variant products with at least one live size or color phased out. A partly phased-out variant product appears in both `on_sale` and `phased_out`.\n- `deleted`: deleted products only, newest delete first.\n\nA variant product with no live sizes or colors left is in neither `on_sale` nor `phased_out`. Any other value returns 422.","example":"phased_out","in":"query","name":"status","required":false,"schema":{"enum":["on_sale","phased_out","deleted"],"type":"string"}},{"description":"The page to return. Pages hold the team's page size (`pagination_per_page` in team settings: 50 unless changed, 5 to 100). `per_page` is not read here.","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"barcode":null,"brand":"Northwind","color_data":[],"default_price":12500,"deleted_at":null,"deleted_by":null,"deleted_variant_count":null,"description":null,"enable":true,"id":"zSSqymW2yER9jw","phased_out":true,"phased_out_at":"2026-11-01T02:00:00+00:00","phased_out_by":{"id":"lOURnovd3hkIQI","name":"Alex Rivera"},"phased_out_variant_count":null,"price_data":[],"size_data":[],"supplier_id":"MUG-11","taxable":true,"title":"Enamel mug","track_inventory":true,"trashed":false,"type":"simple","variant_count":null,"vendor_id":null,"weight":null},{"brand":"Northwind","color_data":[],"default_price":null,"deleted_at":null,"deleted_by":null,"deleted_variant_count":0,"description":null,"enable":true,"id":"Xe3wCbaZYrxJAI","phased_out_by":null,"phased_out_variant_count":1,"size_data":[{"id":"S","label":"S"},{"id":"M","label":"M"},{"id":"L","label":"L"}],"supplier_id":null,"taxable":true,"title":"Classic Hoodie","trashed":false,"type":"variant","variant_count":3,"variant_type":"size","vendor_id":null}],"pagination":{"count":2,"currentPage":1,"links":[],"perPage":50,"total":2,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A product, plus what the products list shows about it. Counted and loaded in the list query, never one query per row.","properties":{"barcode":{"description":"Simple products only.","type":["string","null"]},"brand":{"type":["string","null"]},"color_data":{"description":"A variant product's colors; `[]` for simple products.","items":{"additionalProperties":true,"properties":{"hex":{"type":["string","null"]},"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"default_price":{"description":"The selling price of a simple product. Variant products price each size and color instead (List a product's variants). Null when not set. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"deleted_at":{"example":null,"format":"date-time","type":["string","null"]},"deleted_by":{"additionalProperties":false,"description":"Who deleted the product; null while live, or when nobody was recorded.","properties":{"id":{"example":"lOURnovd3hkIQI","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name"],"type":["object","null"]},"deleted_variant_count":{"description":"Variant products: sizes and colors deleted on their own, not with the product, which a restore leaves deleted; one per size and color combination, and none for a combination that is live again (added back after its delete). Null for simple products.","example":0,"type":["integer","null"]},"description":{"type":["string","null"]},"enable":{"type":"boolean"},"id":{"example":"zSSqymW2yER9jw","type":"string"},"phased_out":{"description":"Simple products only. Variant products phase out their sizes and colors.","example":true,"type":"boolean"},"phased_out_at":{"description":"Simple products only.","example":"2026-11-01T02:00:00+00:00","format":"date-time","type":["string","null"]},"phased_out_by":{"additionalProperties":false,"description":"Who phased out a simple product; null while on sale, for variant products, or when nobody was recorded. A deleted user keeps their name.","properties":{"id":{"example":"lOURnovd3hkIQI","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name"],"type":["object","null"]},"phased_out_variant_count":{"description":"Variant products: how many of `variant_count` are phased out. Null for simple products.","example":1,"type":["integer","null"]},"price_data":{"additionalProperties":true,"description":"Simple products only. Prices for pricing groups, as saved: keyed by the pricing group's internal number (not its hash id), each `{\"price\": <thousandths>}`. An empty list `[]` when there are none.","type":["object","array"]},"size_data":{"description":"A variant product's sizes; `[]` for simple products.","items":{"additionalProperties":true,"properties":{"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"supplier_id":{"type":["string","null"]},"taxable":{"type":"boolean"},"title":{"example":"Enamel mug","type":"string"},"track_inventory":{"description":"Simple products only.","type":"boolean"},"trashed":{"example":false,"type":"boolean"},"type":{"enum":["simple","variant"],"example":"simple","type":"string"},"variant_count":{"description":"Variant products: their live sizes and colors; for a deleted product, the ones its restore brings back. Null for simple products.","example":3,"type":["integer","null"]},"variant_type":{"description":"Variant products only.","enum":["size","color","size_color"],"type":"string"},"vendor_id":{"description":"The vendor's id, or null.","type":["string","null"]},"weight":{"description":"Simple products only.","type":["number","string","null"]}},"required":["id","type","title","trashed","variant_count","phased_out_variant_count","deleted_variant_count","deleted_at","phased_out_by","deleted_by"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List products","tags":["Products"],"x-yoprint-docs":{"errors":[{"fix":"Leave it out, or use one of the three.","status":422,"when":"`status` is not `on_sale`, `phased_out` or `deleted`. `error.code` is `validation_failed`."}],"group":"Products and catalog","notes":["There is no keyword search on the public API. Page through this list, or keep your own index by product id.","Read a variant product's sizes and colors, with their ids and prices, with List a product's variants or Load a product for a sales order line."],"permission":"Any member of the team.","related":["v1_public_products_show","v1_public_products_store","v1_public_product_variant_index","v1_public_hydrate_imported_product"]}},"post":{"description":"Creates one of your own products and returns it.\n\n- A **simple product** (`type: simple`) is one item with one price: a mug, a setup fee you sell as a product. On sales order lines it is a `user_simple` line.\n- A **variant product** (`type: variant`) comes in sizes, colors or both (`variant_type`). Send the option lists (`size_data`, `color_data`) and one entry in `product` for each size and color combination you sell. Each combination becomes a variant with its own price; on sales order lines it is a `db_variant` line that names the variant id.\n\nCreating a product creates no stock. Amounts here use thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","operationId":"v1_public_products_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"simple":{"summary":"A simple product","value":{"brand":"Northwind","default_price":12500,"supplier_id":"MUG-11","taxable":true,"title":"Enamel mug","type":"simple"},"x-yoprint-variant":"Simple product"},"variant":{"summary":"A T-shirt in two sizes and one color","value":{"brand":"Northwind","color_data":[{"hex":"#000000","id":"black","label":"Black"}],"product":[{"color_hex":"#000000","color_id":"black","color_label":"Black","default_price":9000,"size_id":"S","size_label":"S"},{"color_hex":"#000000","color_id":"black","color_label":"Black","default_price":9000,"size_id":"M","size_label":"M"}],"size_data":[{"id":"S","label":"S"},{"id":"M","label":"M"}],"title":"Classic Tee","type":"variant","variant_type":"size_color"},"x-yoprint-variant":"Variant product"}},"schema":{"discriminator":{"mapping":{"simple":"#/components/schemas/SimpleProductInput","variant":"#/components/schemas/VariantProductInput"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/SimpleProductInput"},{"$ref":"#/components/schemas/VariantProductInput"}],"title":"What kind of product?"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"barcode":null,"brand":"Northwind","color_data":[],"default_price":12500,"deleted_at":null,"deleted_by":null,"deleted_variant_count":null,"description":null,"enable":true,"id":"HuUud6gosvykdV","phased_out":false,"phased_out_at":null,"phased_out_by":null,"phased_out_variant_count":null,"price_data":[],"size_data":[],"supplier_id":"MUG-11","taxable":true,"title":"Enamel mug","track_inventory":true,"trashed":false,"type":"simple","variant_count":null,"vendor_id":null,"weight":null},"status":200,"success":true},"schema":{"properties":{"data":{"discriminator":{"mapping":{"simple":"#/components/schemas/SimpleProduct","variant":"#/components/schemas/VariantProduct"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/SimpleProduct"},{"$ref":"#/components/schemas/VariantProduct"}]},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a product","tags":["Products"],"x-yoprint-docs":{"errors":[{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"`type` or `title` is missing, a simple product has no `default_price`, a variant product is missing `variant_type`, its option lists or `product`, or a price is not a number. `error.code` is `validation_failed`."},{"fix":"Send whole numbers: `12500` for 12.50.","status":500,"when":"A price is not a whole number of thousandths, such as `12.5`."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot create products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Products and catalog","permission":"Needs the Manage Products permission at the level that can create products.","related":["v1_public_product_variant_store","v1_public_products_update_patch","v2_public_order_item_store"],"rules":["Send prices as a whole number of thousandths: `12500` is 12.50.","A variant product needs `variant_type` and at least one entry in `product`; each entry needs `default_price`, plus `size_id` and `size_label` for sizes and `color_id`, `color_label` and `color_hex` for colors.","On create, the entries in `product` are not checked against each other or against `size_data` and `color_data`: send each combination once, with the ids and names your lists use. Adding variants later (Add a variant) does check both.","Titles need not be unique.","`dimension_x`, `dimension_y` and `dimension_z` are saved but not returned by this answer or the products list."]}}},"/v1/api/store/{team_slug}/product/{hash_id}":{"delete":{"description":"Deletes a product that is not in use. Refused with 422 product_in_use, carrying the same report as `delete_check` under `product`, when the product is in use; phase it out instead (a variant product phases out its sizes and colors). Deleting a variant product deletes its live sizes and colors with it, and deleting a product hides its stock rows.\n\nIn use means: ever on a published sales order or quote (removed lines and deleted orders count), stock still incoming on a purchase order, a pending stock operation, or stock a customer owns. A deleted product can be restored.","operationId":"v1_public_products_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a product","tags":["Products"],"x-yoprint-docs":{"errors":[{"fix":"Phase it out instead.","status":422,"when":"The product is in use (`error.code` `product_in_use`); `error.product` holds the delete check report."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot update products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the id.","status":404,"when":"No live product with this id: already deleted, or not the team's. `error.code` is null and `error.message` names the record type."}],"group":"Products and catalog","permission":"Needs the Manage Products permission at the level that can update products.","related":["v1_public_product_delete_check","v1_public_product_phase_out","v1_public_product_restore"],"rules":["Check first with Check whether a product can be deleted; the delete checks again."],"side_effects":["Hides the product's stock rows (a restore brings them back).","For a variant product, deletes its live variants with it."]}},"get":{"description":"One product in the products list row shape, deleted ones included (`trashed`). For a simple product that includes `default_price`, `price_data` and `phased_out`; for a variant product, `variant_type`, `size_data` and `color_data` (its variants are listed by List a product's variants).","operationId":"v1_public_products_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"brand":"Northwind","color_data":[],"default_price":null,"deleted_at":null,"deleted_by":null,"deleted_variant_count":0,"description":null,"enable":true,"id":"Xe3wCbaZYrxJAI","phased_out_by":null,"phased_out_variant_count":1,"size_data":[{"id":"S","label":"S"},{"id":"M","label":"M"},{"id":"L","label":"L"}],"supplier_id":null,"taxable":true,"title":"Classic Hoodie","trashed":false,"type":"variant","variant_count":3,"variant_type":"size","vendor_id":null},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A product, plus what the products list shows about it. Counted and loaded in the list query, never one query per row.","properties":{"barcode":{"description":"Simple products only.","type":["string","null"]},"brand":{"type":["string","null"]},"color_data":{"description":"A variant product's colors; `[]` for simple products.","items":{"additionalProperties":true,"properties":{"hex":{"type":["string","null"]},"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"default_price":{"description":"The selling price of a simple product. Variant products price each size and color instead (List a product's variants). Null when not set. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"deleted_at":{"example":null,"format":"date-time","type":["string","null"]},"deleted_by":{"additionalProperties":false,"description":"Who deleted the product; null while live, or when nobody was recorded.","properties":{"id":{"example":"lOURnovd3hkIQI","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name"],"type":["object","null"]},"deleted_variant_count":{"description":"Variant products: sizes and colors deleted on their own, not with the product, which a restore leaves deleted; one per size and color combination, and none for a combination that is live again (added back after its delete). Null for simple products.","example":0,"type":["integer","null"]},"description":{"type":["string","null"]},"enable":{"type":"boolean"},"id":{"example":"zSSqymW2yER9jw","type":"string"},"phased_out":{"description":"Simple products only. Variant products phase out their sizes and colors.","example":true,"type":"boolean"},"phased_out_at":{"description":"Simple products only.","example":"2026-11-01T02:00:00+00:00","format":"date-time","type":["string","null"]},"phased_out_by":{"additionalProperties":false,"description":"Who phased out a simple product; null while on sale, for variant products, or when nobody was recorded. A deleted user keeps their name.","properties":{"id":{"example":"lOURnovd3hkIQI","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name"],"type":["object","null"]},"phased_out_variant_count":{"description":"Variant products: how many of `variant_count` are phased out. Null for simple products.","example":1,"type":["integer","null"]},"price_data":{"additionalProperties":true,"description":"Simple products only. Prices for pricing groups, as saved: keyed by the pricing group's internal number (not its hash id), each `{\"price\": <thousandths>}`. An empty list `[]` when there are none.","type":["object","array"]},"size_data":{"description":"A variant product's sizes; `[]` for simple products.","items":{"additionalProperties":true,"properties":{"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"supplier_id":{"type":["string","null"]},"taxable":{"type":"boolean"},"title":{"example":"Enamel mug","type":"string"},"track_inventory":{"description":"Simple products only.","type":"boolean"},"trashed":{"example":false,"type":"boolean"},"type":{"enum":["simple","variant"],"example":"simple","type":"string"},"variant_count":{"description":"Variant products: their live sizes and colors; for a deleted product, the ones its restore brings back. Null for simple products.","example":3,"type":["integer","null"]},"variant_type":{"description":"Variant products only.","enum":["size","color","size_color"],"type":"string"},"vendor_id":{"description":"The vendor's id, or null.","type":["string","null"]},"weight":{"description":"Simple products only.","type":["number","string","null"]}},"required":["id","type","title","trashed","variant_count","phased_out_variant_count","deleted_variant_count","deleted_at","phased_out_by","deleted_by"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a product","tags":["Products"],"x-yoprint-docs":{"group":"Products and catalog","notes":["`default_price` is in thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). `price_data` is keyed by the pricing group's internal number, each `{\"price\": <thousandths>}`."],"permission":"Any member of the team.","related":["v1_public_products_update_patch","v1_public_product_variant_index"]}},"patch":{"description":"Updates a product. A custom variant product's `size_data` and `color_data` follow its variants and are not taken here; rename a size or color through `variant/rename_options`. A variant's own price, weight and vendor are changed with Update a variant.\n\nUse `PUT`: it checks the fields, and needs `type` (send the product's type; a product's type never changes). `PATCH` takes the same body but checks nothing.","operationId":"v1_public_products_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"default_price":13500,"title":"Enamel mug, 11 oz","type":"simple","vendor_id":"MFwvMEIK7ud89l"},"schema":{"additionalProperties":false,"properties":{"barcode":{"description":"The product's barcode. Saved as sent.","type":"string"},"brand":{"description":"The product's brand.","type":"string"},"default_price":{"description":"Send a whole number of thousandths: `12500` is 12.50.","type":"integer"},"description":{"description":"A description of the product.","type":"string"},"dimension_x":{"type":"number"},"dimension_y":{"type":"number"},"dimension_z":{"type":"number"},"price_data":{"additionalProperties":{"properties":{"price":{"description":"Send a whole number of thousandths: `11000` is 11.00.","type":"integer"}},"required":["price"],"type":"object"},"description":"Prices for pricing groups, keyed by pricing group id: `{\"<pricing group id>\": {\"price\": 11000}}`. A line priced with that group uses this price instead of `default_price`. Send a whole number of thousandths: `11000` is 11.00.","type":"object"},"supplier_id":{"description":"The supplier's code for the product.","type":"string"},"taxable":{"description":"Whether sales tax applies to it.","type":"boolean"},"title":{"description":"Required on create. The product name shown on orders.","type":"string"},"type":{"description":"Required on `PUT`: `simple` or `variant`. It is not compared with the product and never changes it.","enum":["simple","variant"],"type":"string"},"vendor_id":{"description":"The vendor you buy it from.","type":"string"},"weight":{"description":"The product's weight. Simple products only.","type":"number"}},"required":["type"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"barcode":null,"brand":"Northwind","color_data":[],"default_price":13500,"deleted_at":null,"deleted_by":null,"deleted_variant_count":null,"description":null,"enable":true,"id":"HuUud6gosvykdV","phased_out":false,"phased_out_at":null,"phased_out_by":null,"phased_out_variant_count":null,"price_data":[],"size_data":[],"supplier_id":"MUG-11","taxable":true,"title":"Enamel mug, 11 oz","track_inventory":true,"trashed":false,"type":"simple","variant_count":null,"vendor_id":"MFwvMEIK7ud89l","weight":null},"status":200,"success":true},"schema":{"properties":{"data":{"discriminator":{"mapping":{"simple":"#/components/schemas/SimpleProduct","variant":"#/components/schemas/VariantProduct"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/SimpleProduct"},{"$ref":"#/components/schemas/VariantProduct"}]},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a product (PATCH)","tags":["Products"],"x-yoprint-docs":{"errors":[{"fix":"Send a whole number: `13500` for 13.50.","status":500,"when":"`default_price` is not a whole number of thousandths."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot update products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Restore a deleted product first.","status":404,"when":"No live product with this id. `error.code` is null and `error.message` names the record type."}],"group":"Products and catalog","permission":"Needs the Manage Products permission at the level that can update products.","related":["v1_public_product_variant_rename_options","v1_public_product_variant_update"],"rules":["Send `vendor_id` on every update: leaving it out, or sending an empty string, clears the product's vendor.","Send prices as a whole number of thousandths: `12500` is 12.50.","Existing sales order lines keep the price they were sold at.","Other fields sent as `null` are dropped, as if left out (for `vendor_id` that means the vendor is cleared, as above). Send an empty string to blank a text field."]}},"put":{"description":"Updates a product. A custom variant product's `size_data` and `color_data` follow its variants and are not taken here; rename a size or color through `variant/rename_options`. A variant's own price, weight and vendor are changed with Update a variant.\n\nUse `PUT`: it checks the fields, and needs `type` (send the product's type; a product's type never changes). `PATCH` takes the same body but checks nothing.","operationId":"v1_public_products_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"default_price":13500,"title":"Enamel mug, 11 oz","type":"simple","vendor_id":"MFwvMEIK7ud89l"},"schema":{"additionalProperties":false,"properties":{"barcode":{"description":"The product's barcode. Saved as sent.","type":"string"},"brand":{"description":"The product's brand.","type":"string"},"default_price":{"description":"Send a whole number of thousandths: `12500` is 12.50.","type":"integer"},"description":{"description":"A description of the product.","type":"string"},"dimension_x":{"type":"number"},"dimension_y":{"type":"number"},"dimension_z":{"type":"number"},"price_data":{"additionalProperties":{"properties":{"price":{"description":"Send a whole number of thousandths: `11000` is 11.00.","type":"integer"}},"required":["price"],"type":"object"},"description":"Prices for pricing groups, keyed by pricing group id: `{\"<pricing group id>\": {\"price\": 11000}}`. A line priced with that group uses this price instead of `default_price`. Send a whole number of thousandths: `11000` is 11.00.","type":"object"},"supplier_id":{"description":"The supplier's code for the product.","type":"string"},"taxable":{"description":"Whether sales tax applies to it.","type":"boolean"},"title":{"description":"Required on create. The product name shown on orders.","type":"string"},"type":{"description":"Required on `PUT`: `simple` or `variant`. It is not compared with the product and never changes it.","enum":["simple","variant"],"type":"string"},"vendor_id":{"description":"The vendor you buy it from.","type":"string"},"weight":{"description":"The product's weight. Simple products only.","type":"number"}},"required":["type"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"barcode":null,"brand":"Northwind","color_data":[],"default_price":13500,"deleted_at":null,"deleted_by":null,"deleted_variant_count":null,"description":null,"enable":true,"id":"HuUud6gosvykdV","phased_out":false,"phased_out_at":null,"phased_out_by":null,"phased_out_variant_count":null,"price_data":[],"size_data":[],"supplier_id":"MUG-11","taxable":true,"title":"Enamel mug, 11 oz","track_inventory":true,"trashed":false,"type":"simple","variant_count":null,"vendor_id":"MFwvMEIK7ud89l","weight":null},"status":200,"success":true},"schema":{"properties":{"data":{"discriminator":{"mapping":{"simple":"#/components/schemas/SimpleProduct","variant":"#/components/schemas/VariantProduct"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/SimpleProduct"},{"$ref":"#/components/schemas/VariantProduct"}]},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a product","tags":["Products"],"x-yoprint-docs":{"errors":[{"fix":"Send the product's `type`.","status":422,"when":"`type` is missing on `PUT`, or a field has the wrong type. `error.code` is `validation_failed`."},{"fix":"Send a whole number: `13500` for 13.50.","status":500,"when":"`default_price` is not a whole number of thousandths."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot update products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Restore a deleted product first.","status":404,"when":"No live product with this id. `error.code` is null and `error.message` names the record type."}],"group":"Products and catalog","permission":"Needs the Manage Products permission at the level that can update products.","related":["v1_public_product_variant_rename_options","v1_public_product_variant_update"],"rules":["Send `vendor_id` on every update: leaving it out, or sending an empty string, clears the product's vendor.","Send prices as a whole number of thousandths: `12500` is 12.50.","Existing sales order lines keep the price they were sold at.","Other fields sent as `null` are dropped, as if left out (for `vendor_id` that means the vendor is cleared, as above). Send an empty string to blank a text field."]}}},"/v1/api/store/{team_slug}/product/{hash_id}/delete_check":{"post":{"description":"Checks whether a product can be safely deleted. Returns a report under `product` (`id`, `deletable`, `blockers`, `warnings`, and `phased_out`).\n\nDeleting is blocked (`blockers`) when any of the following apply (for variant products, checked across all sizes and colors, including deleted ones for sales):\n- The product was ever on a published sales order or quote (including removed lines and deleted orders).\n- Stock is still incoming on an open purchase order line.\n- A stock operation (transfer or adjustment) is pending.\n- A customer currently owns stock of the product.\n\nNon-blocking warnings (`warnings`) include:\n- Shop stock currently exists.\n- The product appears on draft sales orders or quotes.\n- Active pricing rules apply to the product.\n\nA reason about documents gives their `count`, their `lines`, and up to five `examples`.","operationId":"v1_public_product_delete_check","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"product":{"blockers":[{"count":2,"examples":[{"document_removed":false,"id":"CiK5Bpj6YC4Cm7","label":"1001","object_type":"sales_order","removed":false}],"lines":3,"reason":"published_order","units":"7"}],"deletable":false,"id":"zSSqymW2yER9jw","phased_out":false,"warnings":[{"count":1,"examples":[{}],"lines":1,"reason":"shop_stock","units":"12.5","warehouses":[{"id":"MB5H7qBH1G60sv","label":"Main warehouse","units":"12.5"}]}]}},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"product":{"additionalProperties":false,"properties":{"blockers":{"items":{"additionalProperties":false,"properties":{"count":{"example":2,"type":"integer"},"examples":{"items":{"additionalProperties":false,"properties":{"document_removed":{"example":false,"type":"boolean"},"id":{"example":"CiK5Bpj6YC4Cm7","type":"string"},"label":{"example":"1001","type":["string","null"]},"object_type":{"example":"sales_order","type":"string"},"removed":{"example":false,"type":"boolean"}},"required":["id","label","object_type","removed","document_removed"],"type":"object"},"type":"array"},"lines":{"example":3,"type":"integer"},"reason":{"enum":["published_order","incoming_purchase_order","pending_stock_operation","customer_stock","last_variant"],"type":"string"},"units":{"example":"7","type":"string"}},"required":["reason"],"type":"object"},"type":"array"},"deletable":{"example":false,"type":"boolean"},"id":{"example":"zSSqymW2yER9jw","type":"string"},"phased_out":{"description":"A simple product that is phased out, or a variant product with no live size or color still on sale (including one with none left at all): \"phase out instead\" has nothing left to do.","example":false,"type":"boolean"},"warnings":{"items":{"additionalProperties":false,"properties":{"count":{"example":1,"type":"integer"},"examples":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"lines":{"example":1,"type":"integer"},"reason":{"enum":["shop_stock","draft_order","pricing_rule"],"type":"string"},"units":{"example":"12.5","type":"string"},"warehouses":{"items":{"additionalProperties":false,"properties":{"id":{"example":"MB5H7qBH1G60sv","type":["string","null"]},"label":{"example":"Main warehouse","type":["string","null"]},"units":{"example":"12.5","type":"string"}},"type":"object"},"type":"array"}},"required":["reason"],"type":"object"},"type":"array"}},"required":["id","deletable","blockers","warnings","phased_out"],"type":"object"}},"required":["product"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Check whether a product can be deleted","tags":["Products"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot update products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the id.","status":404,"when":"No live product with this id. `error.code` is null and `error.message` names the record type."}],"group":"Products and catalog","notes":["When `deletable` is false and `phased_out` is false, phase the product out instead."],"permission":"Needs the Manage Products permission at the level that can update products.","related":["v1_public_products_destroy","v1_public_product_phase_out"]}}},"/v1/api/store/{team_slug}/product/{hash_id}/phase_out":{"post":{"description":"Stops selling a simple product. A phased-out simple product can no longer be added to new sales order or quote lines (422 `product_phased_out`). Existing lines, purchase orders, stock and pricing rules keep working. Repeating the call keeps the original phase-out time and author.\n\nThe answer is the product in the products list row shape with `changed`: true when this request phased it out, false when it already was. A variant product returns 422 product_not_simple: phase out its sizes and colors instead.","operationId":"v1_public_product_phase_out","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"barcode":null,"brand":"Northwind","changed":true,"color_data":[],"default_price":12500,"deleted_at":null,"deleted_by":null,"deleted_variant_count":null,"description":null,"enable":true,"id":"zSSqymW2yER9jw","phased_out":true,"phased_out_at":"2026-11-01T02:00:00+00:00","phased_out_by":{"id":"lOURnovd3hkIQI","name":"Alex Rivera"},"phased_out_variant_count":null,"price_data":[],"size_data":[],"supplier_id":"MUG-11","taxable":true,"title":"Enamel mug","track_inventory":true,"trashed":false,"type":"simple","variant_count":null,"vendor_id":null,"weight":null},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A product, plus what the products list shows about it. Counted and loaded in the list query, never one query per row.","properties":{"barcode":{"description":"Simple products only.","type":["string","null"]},"brand":{"type":["string","null"]},"changed":{"description":"True when this request changed the row's sale state; false when it was already in the requested state and kept its earlier time and author. An undo reverses only the rows marked true.","example":true,"type":"boolean"},"color_data":{"description":"A variant product's colors; `[]` for simple products.","items":{"additionalProperties":true,"properties":{"hex":{"type":["string","null"]},"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"default_price":{"description":"The selling price of a simple product. Variant products price each size and color instead (List a product's variants). Null when not set. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"deleted_at":{"example":null,"format":"date-time","type":["string","null"]},"deleted_by":{"additionalProperties":false,"description":"Who deleted the product; null while live, or when nobody was recorded.","properties":{"id":{"example":"lOURnovd3hkIQI","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name"],"type":["object","null"]},"deleted_variant_count":{"description":"Variant products: sizes and colors deleted on their own, not with the product, which a restore leaves deleted; one per size and color combination, and none for a combination that is live again (added back after its delete). Null for simple products.","example":0,"type":["integer","null"]},"description":{"type":["string","null"]},"enable":{"type":"boolean"},"id":{"example":"zSSqymW2yER9jw","type":"string"},"phased_out":{"description":"Simple products only. Variant products phase out their sizes and colors.","example":true,"type":"boolean"},"phased_out_at":{"description":"Simple products only.","example":"2026-11-01T02:00:00+00:00","format":"date-time","type":["string","null"]},"phased_out_by":{"additionalProperties":false,"description":"Who phased out a simple product; null while on sale, for variant products, or when nobody was recorded. A deleted user keeps their name.","properties":{"id":{"example":"lOURnovd3hkIQI","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name"],"type":["object","null"]},"phased_out_variant_count":{"description":"Variant products: how many of `variant_count` are phased out. Null for simple products.","example":1,"type":["integer","null"]},"price_data":{"additionalProperties":true,"description":"Simple products only. Prices for pricing groups, as saved: keyed by the pricing group's internal number (not its hash id), each `{\"price\": <thousandths>}`. An empty list `[]` when there are none.","type":["object","array"]},"size_data":{"description":"A variant product's sizes; `[]` for simple products.","items":{"additionalProperties":true,"properties":{"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"supplier_id":{"type":["string","null"]},"taxable":{"type":"boolean"},"title":{"example":"Enamel mug","type":"string"},"track_inventory":{"description":"Simple products only.","type":"boolean"},"trashed":{"example":false,"type":"boolean"},"type":{"enum":["simple","variant"],"example":"simple","type":"string"},"variant_count":{"description":"Variant products: their live sizes and colors; for a deleted product, the ones its restore brings back. Null for simple products.","example":3,"type":["integer","null"]},"variant_type":{"description":"Variant products only.","enum":["size","color","size_color"],"type":"string"},"vendor_id":{"description":"The vendor's id, or null.","type":["string","null"]},"weight":{"description":"Simple products only.","type":["number","string","null"]}},"required":["id","type","title","trashed","variant_count","phased_out_variant_count","deleted_variant_count","deleted_at","phased_out_by","deleted_by","changed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Phase out a simple product","tags":["Products"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Use Phase out variants.","status":422,"when":"The product is a variant product (`error.code` `product_not_simple`, \"Only a product without sizes or colors is phased out as a whole. Phase out its sizes and colors instead.\")."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot update products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the id.","status":404,"when":"No live product with this id. `error.code` is null and `error.message` names the record type."}],"group":"Products and catalog","permission":"Needs the Manage Products permission at the level that can update products.","related":["v1_public_product_resume","v1_public_product_variant_phase_out"]}}},"/v1/api/store/{team_slug}/product/{hash_id}/restore":{"patch":{"description":"Restores a deleted product, its stock rows, and its variants that were removed when the product was deleted (variants deleted individually beforehand remain deleted). Phase-out status is preserved. Repeating a restore on a non-deleted product is safe (returns 200 with `restored: false`). No request body.\n\nThe response describes what was restored:\n- `product`: The restored product in the products list row shape.\n- `restored`: `true` when restored by this call; `false` when it was already active.\n- `variants_restored`: All live variants after the restore, in ID order (including variants left active by pre-v3.7.0 deletes).\n- `variants_still_deleted`: Variants that remain deleted because they were deleted individually beforehand.\n- `stock_rows_restored`: Number of stock rows restored.\n- `stock_units_restored`: Total units held in the restored stock rows.\n- `phased_out`: `true` if the restored product is phased out (or all its live variants are phased out).\n- `name_clash`: `true` if another live product of the team shares the same brand, title, and supplier code (a warning, not a refusal).\n\nA product the team does not have, deleted or not, returns 404 `product_not_found`; an ID that cannot be decoded returns generic 404.","operationId":"v1_public_product_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"name_clash":false,"phased_out":false,"product":{"brand":"Northwind","color_data":[],"default_price":null,"deleted_at":null,"deleted_by":null,"deleted_variant_count":0,"description":null,"enable":true,"id":"Xe3wCbaZYrxJAI","phased_out_by":null,"phased_out_variant_count":1,"size_data":[{"id":"S","label":"S"},{"id":"M","label":"M"},{"id":"L","label":"L"}],"supplier_id":null,"taxable":true,"title":"Classic Hoodie","trashed":false,"type":"variant","variant_count":3,"variant_type":"size","vendor_id":null},"restored":true,"stock_rows_restored":2,"stock_units_restored":"12.5","variants_restored":[{"color_label":null,"id":"HcFPJ9RLam4gNE","phased_out":false,"size_label":"S"},{"color_label":null,"id":"yJCzauCZ07rsoS","phased_out":true,"size_label":"M"},{"color_label":null,"id":"JAJVLphHcr9BxT","phased_out":false,"size_label":"L"}],"variants_still_deleted":[{"color_label":null,"id":"oL85v7lFzkPXRi","phased_out":false,"size_label":"XL"}]},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"name_clash":{"example":false,"type":"boolean"},"phased_out":{"example":false,"type":"boolean"},"product":{"additionalProperties":true,"description":"A product, plus what the products list shows about it. Counted and loaded in the list query, never one query per row.","properties":{"barcode":{"description":"Simple products only.","type":["string","null"]},"brand":{"type":["string","null"]},"color_data":{"description":"A variant product's colors; `[]` for simple products.","items":{"additionalProperties":true,"properties":{"hex":{"type":["string","null"]},"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"default_price":{"description":"The selling price of a simple product. Variant products price each size and color instead (List a product's variants). Null when not set. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"deleted_at":{"example":null,"format":"date-time","type":["string","null"]},"deleted_by":{"additionalProperties":false,"description":"Who deleted the product; null while live, or when nobody was recorded.","properties":{"id":{"example":"lOURnovd3hkIQI","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name"],"type":["object","null"]},"deleted_variant_count":{"description":"Variant products: sizes and colors deleted on their own, not with the product, which a restore leaves deleted; one per size and color combination, and none for a combination that is live again (added back after its delete). Null for simple products.","example":0,"type":["integer","null"]},"description":{"type":["string","null"]},"enable":{"type":"boolean"},"id":{"example":"zSSqymW2yER9jw","type":"string"},"phased_out":{"description":"Simple products only. Variant products phase out their sizes and colors.","example":true,"type":"boolean"},"phased_out_at":{"description":"Simple products only.","example":"2026-11-01T02:00:00+00:00","format":"date-time","type":["string","null"]},"phased_out_by":{"additionalProperties":false,"description":"Who phased out a simple product; null while on sale, for variant products, or when nobody was recorded. A deleted user keeps their name.","properties":{"id":{"example":"lOURnovd3hkIQI","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name"],"type":["object","null"]},"phased_out_variant_count":{"description":"Variant products: how many of `variant_count` are phased out. Null for simple products.","example":1,"type":["integer","null"]},"price_data":{"additionalProperties":true,"description":"Simple products only. Prices for pricing groups, as saved: keyed by the pricing group's internal number (not its hash id), each `{\"price\": <thousandths>}`. An empty list `[]` when there are none.","type":["object","array"]},"size_data":{"description":"A variant product's sizes; `[]` for simple products.","items":{"additionalProperties":true,"properties":{"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"supplier_id":{"type":["string","null"]},"taxable":{"type":"boolean"},"title":{"example":"Enamel mug","type":"string"},"track_inventory":{"description":"Simple products only.","type":"boolean"},"trashed":{"example":false,"type":"boolean"},"type":{"enum":["simple","variant"],"example":"simple","type":"string"},"variant_count":{"description":"Variant products: their live sizes and colors; for a deleted product, the ones its restore brings back. Null for simple products.","example":3,"type":["integer","null"]},"variant_type":{"description":"Variant products only.","enum":["size","color","size_color"],"type":"string"},"vendor_id":{"description":"The vendor's id, or null.","type":["string","null"]},"weight":{"description":"Simple products only.","type":["number","string","null"]}},"required":["id","type","title","trashed","variant_count","phased_out_variant_count","deleted_variant_count","deleted_at","phased_out_by","deleted_by"],"type":"object"},"restored":{"example":true,"type":"boolean"},"stock_rows_restored":{"example":2,"type":"integer"},"stock_units_restored":{"description":"A decimal string without trailing zeros, such as `\"12.5\"`.","example":"12.5","type":"string"},"variants_restored":{"items":{"additionalProperties":false,"properties":{"color_label":{"example":null,"type":["string","null"]},"id":{"example":"HcFPJ9RLam4gNE","type":"string"},"phased_out":{"example":false,"type":"boolean"},"size_label":{"example":"M","type":["string","null"]}},"required":["id","size_label","color_label","phased_out"],"type":"object"},"type":"array"},"variants_still_deleted":{"items":{"additionalProperties":false,"properties":{"color_label":{"example":null,"type":["string","null"]},"id":{"example":"HcFPJ9RLam4gNE","type":"string"},"phased_out":{"example":false,"type":"boolean"},"size_label":{"example":"M","type":["string","null"]}},"required":["id","size_label","color_label","phased_out"],"type":"object"},"type":"array"}},"required":["product","restored","variants_restored","variants_still_deleted","stock_rows_restored","stock_units_restored","phased_out","name_clash"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a deleted product","tags":["Products"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Check the id; list deleted products with `status=deleted`.","status":404,"when":"The team has no such product, deleted or not (`error.code` `product_not_found`)."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot update products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Products and catalog","permission":"Needs the Manage Products permission at the level that can update products.","related":["v1_public_products_destroy","v1_public_products_index"],"side_effects":["Brings back the product's stock rows."]}}},"/v1/api/store/{team_slug}/product/{hash_id}/resume":{"post":{"description":"New sales order and quote lines can use it again. The answer is the product in the products list row shape with `changed`: true when this request put it back on sale, false when it was already on sale. A variant product returns 422 product_not_simple.","operationId":"v1_public_product_resume","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"barcode":null,"brand":"Northwind","changed":true,"color_data":[],"default_price":12500,"deleted_at":null,"deleted_by":null,"deleted_variant_count":null,"description":null,"enable":true,"id":"zSSqymW2yER9jw","phased_out":false,"phased_out_at":null,"phased_out_by":null,"phased_out_variant_count":null,"price_data":[],"size_data":[],"supplier_id":"MUG-11","taxable":true,"title":"Enamel mug","track_inventory":true,"trashed":false,"type":"simple","variant_count":null,"vendor_id":null,"weight":null},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A product, plus what the products list shows about it. Counted and loaded in the list query, never one query per row.","properties":{"barcode":{"description":"Simple products only.","type":["string","null"]},"brand":{"type":["string","null"]},"changed":{"description":"True when this request changed the row's sale state; false when it was already in the requested state and kept its earlier time and author. An undo reverses only the rows marked true.","example":true,"type":"boolean"},"color_data":{"description":"A variant product's colors; `[]` for simple products.","items":{"additionalProperties":true,"properties":{"hex":{"type":["string","null"]},"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"default_price":{"description":"The selling price of a simple product. Variant products price each size and color instead (List a product's variants). Null when not set. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"deleted_at":{"example":null,"format":"date-time","type":["string","null"]},"deleted_by":{"additionalProperties":false,"description":"Who deleted the product; null while live, or when nobody was recorded.","properties":{"id":{"example":"lOURnovd3hkIQI","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name"],"type":["object","null"]},"deleted_variant_count":{"description":"Variant products: sizes and colors deleted on their own, not with the product, which a restore leaves deleted; one per size and color combination, and none for a combination that is live again (added back after its delete). Null for simple products.","example":0,"type":["integer","null"]},"description":{"type":["string","null"]},"enable":{"type":"boolean"},"id":{"example":"zSSqymW2yER9jw","type":"string"},"phased_out":{"description":"Simple products only. Variant products phase out their sizes and colors.","example":true,"type":"boolean"},"phased_out_at":{"description":"Simple products only.","example":"2026-11-01T02:00:00+00:00","format":"date-time","type":["string","null"]},"phased_out_by":{"additionalProperties":false,"description":"Who phased out a simple product; null while on sale, for variant products, or when nobody was recorded. A deleted user keeps their name.","properties":{"id":{"example":"lOURnovd3hkIQI","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name"],"type":["object","null"]},"phased_out_variant_count":{"description":"Variant products: how many of `variant_count` are phased out. Null for simple products.","example":1,"type":["integer","null"]},"price_data":{"additionalProperties":true,"description":"Simple products only. Prices for pricing groups, as saved: keyed by the pricing group's internal number (not its hash id), each `{\"price\": <thousandths>}`. An empty list `[]` when there are none.","type":["object","array"]},"size_data":{"description":"A variant product's sizes; `[]` for simple products.","items":{"additionalProperties":true,"properties":{"id":{"type":"string"},"label":{"type":["string","null"]}},"required":["id","label"],"type":"object"},"type":"array"},"supplier_id":{"type":["string","null"]},"taxable":{"type":"boolean"},"title":{"example":"Enamel mug","type":"string"},"track_inventory":{"description":"Simple products only.","type":"boolean"},"trashed":{"example":false,"type":"boolean"},"type":{"enum":["simple","variant"],"example":"simple","type":"string"},"variant_count":{"description":"Variant products: their live sizes and colors; for a deleted product, the ones its restore brings back. Null for simple products.","example":3,"type":["integer","null"]},"variant_type":{"description":"Variant products only.","enum":["size","color","size_color"],"type":"string"},"vendor_id":{"description":"The vendor's id, or null.","type":["string","null"]},"weight":{"description":"Simple products only.","type":["number","string","null"]}},"required":["id","type","title","trashed","variant_count","phased_out_variant_count","deleted_variant_count","deleted_at","phased_out_by","deleted_by","changed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Put a phased-out simple product back on sale","tags":["Products"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Use Put variants back on sale.","status":422,"when":"The product is a variant product (`error.code` `product_not_simple`, \"Only a product without sizes or colors is resumed as a whole. Resume its sizes and colors instead.\")."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot update products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the id.","status":404,"when":"No live product with this id. `error.code` is null and `error.message` names the record type."}],"group":"Products and catalog","permission":"Needs the Manage Products permission at the level that can update products.","related":["v1_public_product_phase_out"]}}},"/v1/api/store/{team_slug}/product/{hash_id}/variant":{"get":{"description":"Lists the live variants (size and color combinations) of a variant product, paged. Each variant has its `id` (use it as the `db_variant` id on sales order lines), `size_id`, `size_label`, `color_id`, `color_label`, `color_hex`, `default_price`, `price_data`, `weight`, `vendor_id` and `supplier_id`.\n\nEach variant has its own `phased_out`, `phased_out_at` and `phased_out_by` (`{id, name}` or null: on sale, or nobody recorded), loaded for the whole list in one query. The list is paged: `pagination` gives `total`, `count`, `perPage`, `currentPage` and `totalPages`. Ask for the next page with `page`; the page size is the team's setting (50 unless changed), and `per_page` is ignored.","operationId":"v1_public_product_variant_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The page to return. Pages hold the team's page size (`pagination_per_page` in team settings: 50 unless changed, 5 to 100). `per_page` is not read here.","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"barcode":null,"brand":"Northwind","color_hex":"#000000","color_id":"black","color_label":"Black","default_price":9000,"description":null,"enable":true,"id":"nFsgC7x4kiFeXu","phased_out":false,"phased_out_at":null,"phased_out_by":null,"price_data":[],"size_id":"M","size_label":"M","supplier_id":null,"taxable":true,"title":"Classic Tee","track_inventory":true,"trashed":false,"type":"variant_option","vendor_id":"","weight":null}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"barcode":{"type":["string","null"]},"brand":{"description":"The parent product's brand.","type":["string","null"]},"color_hex":{"type":["string","null"]},"color_id":{"type":["string","null"]},"color_label":{"type":["string","null"]},"default_price":{"description":"This variant's selling price. Never null. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"description":{"description":"The parent product's description.","type":["string","null"]},"enable":{"type":"boolean"},"id":{"description":"The variant id: the `db_variant` line's product id.","type":"string"},"phased_out":{"type":"boolean"},"phased_out_at":{"format":"date-time","type":["string","null"]},"phased_out_by":{"description":"Who did it, as `{id, name}`; null when on sale or nobody was recorded.","properties":{"id":{"type":"string"},"name":{"type":"string"}},"type":["object","null"]},"price_data":{"additionalProperties":true,"description":"Prices for pricing groups, as saved: keyed by the pricing group's internal number (not its hash id), each `{\"price\": <thousandths>}`. An empty list `[]` when there are none.","type":["object","array"]},"size_id":{"type":["string","null"]},"size_label":{"type":["string","null"]},"supplier_id":{"type":["string","null"]},"taxable":{"description":"The parent product's `taxable`.","type":"boolean"},"title":{"description":"The parent product's title.","type":["string","null"]},"track_inventory":{"type":"boolean"},"trashed":{"type":"boolean"},"type":{"const":"variant_option","type":"string"},"vendor_id":{"description":"The vendor id, or an empty string when none.","type":"string"},"weight":{"type":["number","string","null"]}},"required":["id","type","default_price","trashed","phased_out"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a product's variants","tags":["Product variants"],"x-yoprint-docs":{"group":"Products and catalog","notes":["Amounts here use thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/)."],"permission":"Any member of the team.","related":["v1_public_product_variant_store","v1_public_product_variant_phase_out","v2_public_order_item_store"]}},"post":{"description":"Adds one size and color combination to a variant product, returns it, and updates the product's `size_data` and `color_data`.\n\nSend the options the product's `variant_type` uses: `size_id` and `size_label` for sizes, `color_id`, `color_label` and `color_hex` for colors.\n\nA size or color the product already has keeps its current name, and a color its hex; the names sent for it are ignored. A new size or color whose name another size, or another color, of the product already has returns 422 option_label_taken. Case and surrounding spaces are ignored.","operationId":"v1_public_product_variant_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"color_hex":"#000000","color_id":"black","color_label":"Black","default_price":9500,"size_id":"L","size_label":"L"},"schema":{"additionalProperties":false,"properties":{"barcode":{"description":"Saved as sent; not checked.","type":"string"},"color_hex":{"description":"For products with colors, such as `#1F2937`.","type":"string"},"color_id":{"description":"For products with colors: your id for the color. The rule depends on the case:\n- When creating a product: use an id from `color_data`.\n- When adding a variant to a color-only product: send a new id to add a color. Reusing an existing id is a duplicate (422).\n- When adding a variant to a size-and-color product: reuse an id from `color_data` to add a new size in an existing color, or send a new id to add a color.","type":"string"},"color_label":{"description":"For products with colors. For a color the product already has, its current name is kept.","type":"string"},"default_price":{"description":"Required. This variant's selling price. Send a whole number of thousandths: `9000` is 9.00.","type":"integer"},"enable":{"description":"Saved as sent (default true); returned as `enable`. Nothing enforces it: phase a variant out to stop selling it.","type":"boolean"},"price_data":{"additionalProperties":{"properties":{"price":{"description":"Send a whole number of thousandths: `11000` is 11.00.","type":"integer"}},"required":["price"],"type":"object"},"description":"Prices for pricing groups, keyed by pricing group id: `{\"<pricing group id>\": {\"price\": 11000}}`. A line priced with that group uses this price instead of `default_price`. Send a whole number of thousandths: `11000` is 11.00.","type":"object"},"size_id":{"description":"For products with sizes: your id for the size. The rule depends on the case:\n- When creating a product: use an id from `size_data`.\n- When adding a variant to a size-only product: send a new id to add a size. Reusing an existing id is a duplicate (422).\n- When adding a variant to a size-and-color product: reuse an id from `size_data` to add a new color for an existing size, or send a new id to add a size.","type":"string"},"size_label":{"description":"For products with sizes. For a size the product already has, its current name is kept.","type":"string"},"supplier_id":{"description":"The supplier's code for this variant.","type":"string"},"track_inventory":{"description":"Saved as sent (default true); not checked.","type":"boolean"},"vendor_id":{"type":"string"},"weight":{"description":"The variant's weight.","type":"number"}},"required":["default_price"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"barcode":null,"brand":"Northwind","color_hex":"#000000","color_id":"black","color_label":"Black","default_price":9500,"description":null,"enable":true,"id":"AcFtx9EgT0KtCW","phased_out":false,"phased_out_at":null,"phased_out_by":null,"price_data":[],"size_id":"L","size_label":"L","supplier_id":null,"taxable":true,"title":"Classic Tee","track_inventory":true,"trashed":false,"type":"variant_option","vendor_id":"","weight":null},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"barcode":{"type":["string","null"]},"brand":{"description":"The parent product's brand.","type":["string","null"]},"color_hex":{"type":["string","null"]},"color_id":{"type":["string","null"]},"color_label":{"type":["string","null"]},"default_price":{"description":"This variant's selling price. Never null. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"description":{"description":"The parent product's description.","type":["string","null"]},"enable":{"type":"boolean"},"id":{"description":"The variant id: the `db_variant` line's product id.","type":"string"},"phased_out":{"type":"boolean"},"phased_out_at":{"format":"date-time","type":["string","null"]},"phased_out_by":{"description":"Who did it, as `{id, name}`; null when on sale or nobody was recorded.","properties":{"id":{"type":"string"},"name":{"type":"string"}},"type":["object","null"]},"price_data":{"additionalProperties":true,"description":"Prices for pricing groups, as saved: keyed by the pricing group's internal number (not its hash id), each `{\"price\": <thousandths>}`. An empty list `[]` when there are none.","type":["object","array"]},"size_id":{"type":["string","null"]},"size_label":{"type":["string","null"]},"supplier_id":{"type":["string","null"]},"taxable":{"description":"The parent product's `taxable`.","type":"boolean"},"title":{"description":"The parent product's title.","type":["string","null"]},"track_inventory":{"type":"boolean"},"trashed":{"type":"boolean"},"type":{"const":"variant_option","type":"string"},"vendor_id":{"description":"The vendor id, or an empty string when none.","type":"string"},"weight":{"type":["number","string","null"]}},"required":["id","type","default_price","trashed","phased_out"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add a variant to a product","tags":["Product variants"],"x-yoprint-docs":{"errors":[{"fix":"Send exactly the options the product uses.","status":422,"when":"The options you sent don't match the product's `variant_type` (`error.code` `variant_type_mismatch`)."},{"fix":"List the variants to see what exists.","status":422,"when":"The size and color combination already exists. `error.code` and `error.message` are null; `error.size_id` and/or `error.color_id` say `unique.error` or `size_color.unique.error`."},{"fix":"Pick another name.","status":422,"when":"A new size or color takes a name another option already has (`error.code` `option_label_taken`; `error.options` lists them)."},{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"`default_price` is missing, or a size or color field is missing. `error.code` is `validation_failed`."},{"fix":"Send a whole number: `9500` for 9.50.","status":500,"when":"`default_price` is not a whole number of thousandths, such as `9.5`. Nothing is saved."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot create products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the product id.","status":404,"when":"No live variant product with this id. `error.code` is null and `error.message` names the record type."}],"group":"Products and catalog","permission":"Needs the Manage Products permission at the level that can create products.","related":["v1_public_product_variant_index","v1_public_product_variant_rename_options"],"rules":["The options you send must match the product's `variant_type` (422 `variant_type_mismatch`).","Each size and color combination exists once (422; `error.size_id` / `error.color_id` name the clash).","Adds no stock."]}}},"/v1/api/store/{team_slug}/product/{hash_id}/variant/delete_check":{"post":{"description":"Read-only. For each variant, reports whether delete is allowed now and why not: ever sold, incoming stock, a pending stock operation, customer-owned stock, or the last variant. Shop stock, drafts and pricing rules are reported as warnings. A reason about documents gives their `count`, their `lines`, and up to five `examples`, live ones first: each has an `id`, its number as `label`, an `object_type`, `removed` (the document or its line was deleted) and `document_removed` (the document itself was). The `object_type` is `sales_order` or `quote` for published orders and drafts, and `purchase_order` for incoming stock. For a pending stock operation it is the stored type: `transfer`, `adjustment`, `general_defect`, `production_defect`, or `purchase_order` for a receipt, whose `id` is the receipt's. A blocked delete returns 422 variant_in_use with the same report.","operationId":"v1_public_product_variant_delete_check","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"ids":["HcFPJ9RLam4gNE","yJCzauCZ07rsoS"]},"schema":{"additionalProperties":false,"properties":{"ids":{"items":{"description":"A variant id of this product. No repeats.","type":"string"},"maxItems":500,"minItems":1,"type":"array"}},"required":["ids"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"variants":[{"blockers":[{"count":2,"examples":[{"document_removed":false,"id":"CiK5Bpj6YC4Cm7","label":"1001","object_type":"sales_order","removed":false}],"lines":3,"reason":"published_order","units":"7"}],"deletable":false,"id":"zSSqymW2yER9jw","warnings":[{"count":1,"examples":[{}],"lines":1,"reason":"shop_stock","units":"12.5","warehouses":[{"id":"MB5H7qBH1G60sv","label":"Main warehouse","units":"12.5"}]}]}]},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"variants":{"items":{"additionalProperties":false,"properties":{"blockers":{"items":{"additionalProperties":false,"properties":{"count":{"example":2,"type":"integer"},"examples":{"items":{"additionalProperties":false,"properties":{"document_removed":{"example":false,"type":"boolean"},"id":{"example":"CiK5Bpj6YC4Cm7","type":"string"},"label":{"example":"1001","type":["string","null"]},"object_type":{"example":"sales_order","type":"string"},"removed":{"example":false,"type":"boolean"}},"required":["id","label","object_type","removed","document_removed"],"type":"object"},"type":"array"},"lines":{"example":3,"type":"integer"},"reason":{"enum":["published_order","incoming_purchase_order","pending_stock_operation","customer_stock","last_variant"],"type":"string"},"units":{"example":"7","type":"string"}},"required":["reason"],"type":"object"},"type":"array"},"deletable":{"example":false,"type":"boolean"},"id":{"example":"zSSqymW2yER9jw","type":"string"},"warnings":{"items":{"additionalProperties":false,"properties":{"count":{"example":1,"type":"integer"},"examples":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"lines":{"example":1,"type":"integer"},"reason":{"enum":["shop_stock","draft_order","pricing_rule"],"type":"string"},"units":{"example":"12.5","type":"string"},"warehouses":{"items":{"additionalProperties":false,"properties":{"id":{"example":"MB5H7qBH1G60sv","type":["string","null"]},"label":{"example":"Main warehouse","type":["string","null"]},"units":{"example":"12.5","type":"string"}},"type":"object"},"type":"array"}},"required":["reason"],"type":"object"},"type":"array"}},"required":["id","deletable","blockers","warnings"],"type":"object"},"type":"array"}},"required":["variants"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Check whether variants can be deleted","tags":["Product variants"],"x-yoprint-docs":{"errors":[{"fix":"List the product's variants first.","status":404,"when":"An id is not a live variant of this product (`error.code` `page_not_found`), or the product is not a live variant product (`error.code` null)."},{"fix":"Send 1 to 500 distinct ids.","status":422,"when":"`ids` is empty, has more than 500 or repeated ids. `error.code` is `validation_failed`."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot update products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Products and catalog","permission":"Needs the Manage Products permission at the level that can update products.","related":["v1_public_product_variant_destroy","v1_public_product_variant_phase_out"]}}},"/v1/api/store/{team_slug}/product/{hash_id}/variant/phase_out":{"post":{"description":"Phased-out variants can no longer be added to new sales order or quote lines (422 `variant_phased_out`). Existing lines, purchase orders, stock and pricing rules keep working. Repeating the call keeps the original phase-out time. Send `ids`, or `all: true` to phase out every live variant of the product as it is when the request runs (a variant added meanwhile is included, one deleted meanwhile is skipped); not both. The response lists the requested rows in id order, with `all: true` every live one, each with `changed`: true when this request phased it out, false when it was already phased out (its time and author unchanged). To undo, resume the rows marked true.","operationId":"v1_public_product_variant_phase_out","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"all":{"summary":"The whole product","value":{"all":true},"x-yoprint-variant":"Every variant"},"ids":{"summary":"Two variants","value":{"ids":["HcFPJ9RLam4gNE","yJCzauCZ07rsoS"]},"x-yoprint-variant":"Listed variants"}},"schema":{"oneOf":[{"additionalProperties":false,"description":"Up to 500 variant ids of this product.","properties":{"ids":{"items":{"description":"A variant id of this product. No repeats.","type":"string"},"maxItems":500,"minItems":1,"type":"array"}},"required":["ids"],"title":"Listed variants","type":"object"},{"additionalProperties":false,"description":"Every live variant of the product when the request runs.","properties":{"all":{"enum":[true],"type":"boolean"}},"required":["all"],"title":"Every variant","type":"object"}],"title":"Which variants?"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"changed":true,"color_label":null,"id":"HcFPJ9RLam4gNE","phased_out":true,"phased_out_at":"2026-11-01T02:00:00+00:00","phased_out_by":{"id":"lOURnovd3hkIQI","name":"Alex Rivera"},"size_label":"S"},{"changed":false,"color_label":null,"id":"yJCzauCZ07rsoS","phased_out":true,"phased_out_at":"2026-10-30T01:00:00+00:00","phased_out_by":{"id":"lOURnovd3hkIQI","name":"Alex Rivera"},"size_label":"M"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"changed":{"description":"True when this request changed the row's sale state; false when it was already in the requested state and kept its earlier time and author. An undo reverses only the rows marked true.","example":true,"type":"boolean"},"color_label":{"example":null,"type":["string","null"]},"id":{"example":"HcFPJ9RLam4gNE","type":"string"},"phased_out":{"example":true,"type":"boolean"},"phased_out_at":{"example":"2026-11-01T02:00:00+00:00","format":"date-time","type":["string","null"]},"phased_out_by":{"additionalProperties":false,"description":"Who phased it out; null while on sale, or when nobody was recorded.","properties":{"id":{"example":"lOURnovd3hkIQI","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name"],"type":["object","null"]},"size_label":{"example":"M","type":["string","null"]}},"required":["id","phased_out","phased_out_at","phased_out_by","changed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Phase out variants (stop selling them)","tags":["Product variants"],"x-yoprint-docs":{"errors":[{"fix":"Send one of them.","status":422,"when":"Both `ids` and `all` are sent, or `ids` is empty or has more than 500 or repeated ids. `error.code` is `validation_failed`."},{"fix":"List the variants first.","status":404,"when":"An id is not a live variant of this product, or the product is not a live variant product. Nothing is changed. `error.code` is null and `error.message` names the record type."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot update products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Products and catalog","permission":"Needs the Manage Products permission at the level that can update products.","related":["v1_public_product_variant_resume"]}}},"/v1/api/store/{team_slug}/product/{hash_id}/variant/rename_options":{"post":{"description":"Each size or color keeps its id and takes the new label, and a color may take a new hex, on every variant of the product, deleted copies included. A color sent with only a hex keeps its current name. Orders, quotes and invoices show the new name; purchase order lines keep the name they were created with. A label another size, or another color, of the product already has returns 422 option_label_taken; an option the product does not use returns 422 option_unknown. Returns the product's live variants.","operationId":"v1_public_product_variant_rename_options","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"options":[{"id":"M","label":"Medium","type":"size"},{"hex":"#111111","id":"black","type":"color"}]},"schema":{"additionalProperties":false,"properties":{"options":{"items":{"additionalProperties":false,"properties":{"hex":{"description":"Colors: the new hex color, `#` and 6 or 3 hex digits, such as `#1F2937`.","type":["string","null"]},"id":{"description":"The size or color id, as in `size_data` or `color_data`.","maxLength":191,"type":"string"},"label":{"description":"The new name. Required for sizes, and for colors sent without `hex`.","maxLength":191,"type":["string","null"]},"type":{"enum":["size","color"],"type":"string"}},"required":["type","id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}},"required":["options"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"barcode":null,"brand":"Northwind","color_hex":"#111111","color_id":"black","color_label":"Black","default_price":9000,"description":null,"enable":true,"id":"nFsgC7x4kiFeXu","phased_out":false,"phased_out_at":null,"phased_out_by":null,"price_data":[],"size_id":"M","size_label":"Medium","supplier_id":null,"taxable":true,"title":"Classic Tee","track_inventory":true,"trashed":false,"type":"variant_option","vendor_id":"","weight":null}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"Every live variant of the product, in id order.","items":{"additionalProperties":true,"properties":{"barcode":{"type":["string","null"]},"brand":{"description":"The parent product's brand.","type":["string","null"]},"color_hex":{"type":["string","null"]},"color_id":{"type":["string","null"]},"color_label":{"type":["string","null"]},"default_price":{"description":"This variant's selling price. Never null. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"description":{"description":"The parent product's description.","type":["string","null"]},"enable":{"type":"boolean"},"id":{"description":"The variant id: the `db_variant` line's product id.","type":"string"},"phased_out":{"type":"boolean"},"phased_out_at":{"format":"date-time","type":["string","null"]},"phased_out_by":{"description":"Who did it, as `{id, name}`; null when on sale or nobody was recorded.","properties":{"id":{"type":"string"},"name":{"type":"string"}},"type":["object","null"]},"price_data":{"additionalProperties":true,"description":"Prices for pricing groups, as saved: keyed by the pricing group's internal number (not its hash id), each `{\"price\": <thousandths>}`. An empty list `[]` when there are none.","type":["object","array"]},"size_id":{"type":["string","null"]},"size_label":{"type":["string","null"]},"supplier_id":{"type":["string","null"]},"taxable":{"description":"The parent product's `taxable`.","type":"boolean"},"title":{"description":"The parent product's title.","type":["string","null"]},"track_inventory":{"type":"boolean"},"trashed":{"type":"boolean"},"type":{"const":"variant_option","type":"string"},"vendor_id":{"description":"The vendor id, or an empty string when none.","type":"string"},"weight":{"type":["number","string","null"]}},"required":["id","type","default_price","trashed","phased_out"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Rename sizes and colors of a product","tags":["Product variants"],"x-yoprint-docs":{"errors":[{"fix":"Pick another name; reload the product's options.","status":422,"when":"The new name is taken by another option of the product (`error.code` `option_label_taken`), or the option is not on the product (`option_unknown`)."},{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"`options` is empty or has more than 100 items, an item is missing `type`, `id` or a `label`, or a `hex` is not a hex color. `error.code` is `validation_failed`."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot update products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the product id.","status":404,"when":"No live variant product with this id. `error.code` is null and `error.message` names the record type."}],"group":"Products and catalog","notes":["Pricing rules match a line's saved size name. Renaming a size can change which product rules apply to new lines."],"permission":"Needs the Manage Products permission at the level that can update products.","related":["v1_public_product_variant_index","v1_public_products_update_patch"]}}},"/v1/api/store/{team_slug}/product/{hash_id}/variant/resume":{"post":{"description":"New sales order and quote lines can use them again. The response lists the requested rows in id order, each with `changed`: true when this request put it back on sale, false when it was already on sale.","operationId":"v1_public_product_variant_resume","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"ids":["HcFPJ9RLam4gNE"]},"schema":{"additionalProperties":false,"properties":{"ids":{"items":{"description":"A variant id of this product. No repeats.","type":"string"},"maxItems":500,"minItems":1,"type":"array"}},"required":["ids"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"changed":true,"color_label":null,"id":"HcFPJ9RLam4gNE","phased_out":false,"phased_out_at":null,"phased_out_by":null,"size_label":"S"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"changed":{"description":"True when this request changed the row's sale state; false when it was already in the requested state and kept its earlier time and author. An undo reverses only the rows marked true.","example":true,"type":"boolean"},"color_label":{"example":null,"type":["string","null"]},"id":{"example":"HcFPJ9RLam4gNE","type":"string"},"phased_out":{"example":true,"type":"boolean"},"phased_out_at":{"example":"2026-11-01T02:00:00+00:00","format":"date-time","type":["string","null"]},"phased_out_by":{"additionalProperties":false,"description":"Who phased it out; null while on sale, or when nobody was recorded.","properties":{"id":{"example":"lOURnovd3hkIQI","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name"],"type":["object","null"]},"size_label":{"example":"M","type":["string","null"]}},"required":["id","phased_out","phased_out_at","phased_out_by","changed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Put phased-out variants back on sale","tags":["Product variants"],"x-yoprint-docs":{"errors":[{"fix":"Send 1 to 500 distinct ids.","status":422,"when":"`ids` is empty, has more than 500 or repeated ids. `error.code` is `validation_failed`."},{"fix":"List the variants first.","status":404,"when":"An id is not a live variant of this product, or the product is not a live variant product. Nothing is changed. `error.code` is null and `error.message` names the record type."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot update products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Products and catalog","permission":"Needs the Manage Products permission at the level that can update products.","related":["v1_public_product_variant_phase_out"]}}},"/v1/api/store/{team_slug}/product/{hash_id}/variant/{id}":{"delete":{"description":"Deletes one variant unless it is in use, hides its stock rows and updates the product's `size_data` and `color_data`. A variant that was ever sold, has incoming or pending stock, or customer-owned stock, or is the product's last variant, is refused with 422 `variant_in_use` and the delete check report under `variants`: phase it out instead.","operationId":"v1_public_product_variant_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The variant's id (`id` from List a product's variants, or `attr_data[].id` from Load a product for a sales order line). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a variant","tags":["Product variants"],"x-yoprint-docs":{"errors":[{"fix":"Phase it out instead, or delete the whole product.","status":422,"when":"The variant is in use or is the last one (`error.code` `variant_in_use`; `error.variants` holds the delete check report)."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot update products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the id.","status":404,"when":"No live variant with this id. The product id in the path is not checked: the variant is found by its own id. `error.code` is null and `error.message` names the record type."}],"group":"Products and catalog","permission":"Needs the Manage Products permission at the level that can update products.","related":["v1_public_product_variant_delete_check","v1_public_product_variant_phase_out"],"side_effects":["Hides the variant's stock rows.","Rebuilds the product's size and color lists."]}},"get":{"description":"Returns one live variant by its id, with its own sale state (`phased_out`, `phased_out_at`, `phased_out_by`).","operationId":"v1_public_product_variant_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The variant's id (`id` from List a product's variants, or `attr_data[].id` from Load a product for a sales order line). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"barcode":null,"brand":"Northwind","color_hex":"#000000","color_id":"black","color_label":"Black","default_price":9000,"description":null,"enable":true,"id":"nFsgC7x4kiFeXu","phased_out":false,"phased_out_at":null,"phased_out_by":null,"price_data":[],"size_id":"M","size_label":"M","supplier_id":null,"taxable":true,"title":"Classic Tee","track_inventory":true,"trashed":false,"type":"variant_option","vendor_id":"","weight":null},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"barcode":{"type":["string","null"]},"brand":{"description":"The parent product's brand.","type":["string","null"]},"color_hex":{"type":["string","null"]},"color_id":{"type":["string","null"]},"color_label":{"type":["string","null"]},"default_price":{"description":"This variant's selling price. Never null. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"description":{"description":"The parent product's description.","type":["string","null"]},"enable":{"type":"boolean"},"id":{"description":"The variant id: the `db_variant` line's product id.","type":"string"},"phased_out":{"type":"boolean"},"phased_out_at":{"format":"date-time","type":["string","null"]},"phased_out_by":{"description":"Who did it, as `{id, name}`; null when on sale or nobody was recorded.","properties":{"id":{"type":"string"},"name":{"type":"string"}},"type":["object","null"]},"price_data":{"additionalProperties":true,"description":"Prices for pricing groups, as saved: keyed by the pricing group's internal number (not its hash id), each `{\"price\": <thousandths>}`. An empty list `[]` when there are none.","type":["object","array"]},"size_id":{"type":["string","null"]},"size_label":{"type":["string","null"]},"supplier_id":{"type":["string","null"]},"taxable":{"description":"The parent product's `taxable`.","type":"boolean"},"title":{"description":"The parent product's title.","type":["string","null"]},"track_inventory":{"type":"boolean"},"trashed":{"type":"boolean"},"type":{"const":"variant_option","type":"string"},"vendor_id":{"description":"The vendor id, or an empty string when none.","type":"string"},"weight":{"type":["number","string","null"]}},"required":["id","type","default_price","trashed","phased_out"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a variant","tags":["Product variants"],"x-yoprint-docs":{"errors":[{"fix":"Check the id; deleted variants are not returned.","status":404,"when":"No live variant with this id. `error.code` is null and `error.message` names the record type."}],"group":"Products and catalog","permission":"Any member of the team.","related":["v1_public_product_variant_update"],"rules":["The product id in the path is not checked: any live variant of the team is returned, whichever product it belongs to."]}},"put":{"description":"Changes one variant's price, pricing group prices, weight, supplier code and vendor, and returns it. Its size and color are renamed with Rename sizes and colors.","operationId":"v1_public_product_variant_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The product's id (`id` from List products). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The variant's id (`id` from List a product's variants, or `attr_data[].id` from Load a product for a sales order line). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"default_price":9500,"vendor_id":"MFwvMEIK7ud89l"},"schema":{"additionalProperties":false,"properties":{"default_price":{"description":"Send a whole number of thousandths: `9500` is 9.50.","type":"integer"},"price_data":{"additionalProperties":{"properties":{"price":{"description":"Send a whole number of thousandths: `11000` is 11.00.","type":"integer"}},"required":["price"],"type":"object"},"description":"Prices for pricing groups, keyed by pricing group id: `{\"<pricing group id>\": {\"price\": 11000}}`. A line priced with that group uses this price instead of `default_price`. Send a whole number of thousandths: `11000` is 11.00.","type":"object"},"supplier_id":{"description":"The supplier's code for this variant.","type":"string"},"vendor_id":{"description":"The vendor id. Send it every time: leaving it out clears the vendor.","type":"string"},"weight":{"type":"number"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"barcode":null,"brand":"Northwind","color_hex":"#000000","color_id":"black","color_label":"Black","default_price":9500,"description":null,"enable":true,"id":"nFsgC7x4kiFeXu","phased_out":false,"phased_out_at":null,"phased_out_by":null,"price_data":[],"size_id":"M","size_label":"M","supplier_id":null,"taxable":true,"title":"Classic Tee","track_inventory":true,"trashed":false,"type":"variant_option","vendor_id":"MFwvMEIK7ud89l","weight":null},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"barcode":{"type":["string","null"]},"brand":{"description":"The parent product's brand.","type":["string","null"]},"color_hex":{"type":["string","null"]},"color_id":{"type":["string","null"]},"color_label":{"type":["string","null"]},"default_price":{"description":"This variant's selling price. Never null. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string"]},"description":{"description":"The parent product's description.","type":["string","null"]},"enable":{"type":"boolean"},"id":{"description":"The variant id: the `db_variant` line's product id.","type":"string"},"phased_out":{"type":"boolean"},"phased_out_at":{"format":"date-time","type":["string","null"]},"phased_out_by":{"description":"Who did it, as `{id, name}`; null when on sale or nobody was recorded.","properties":{"id":{"type":"string"},"name":{"type":"string"}},"type":["object","null"]},"price_data":{"additionalProperties":true,"description":"Prices for pricing groups, as saved: keyed by the pricing group's internal number (not its hash id), each `{\"price\": <thousandths>}`. An empty list `[]` when there are none.","type":["object","array"]},"size_id":{"type":["string","null"]},"size_label":{"type":["string","null"]},"supplier_id":{"type":["string","null"]},"taxable":{"description":"The parent product's `taxable`.","type":"boolean"},"title":{"description":"The parent product's title.","type":["string","null"]},"track_inventory":{"type":"boolean"},"trashed":{"type":"boolean"},"type":{"const":"variant_option","type":"string"},"vendor_id":{"description":"The vendor id, or an empty string when none.","type":"string"},"weight":{"type":["number","string","null"]}},"required":["id","type","default_price","trashed","phased_out"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a variant","tags":["Product variants"],"x-yoprint-docs":{"errors":[{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"A price, `weight` or a `price_data` price is not a number, or `vendor_id` or a `price_data` key is not a valid id. `error.code` is `validation_failed`."},{"fix":"Send a whole number: `9500` for 9.50.","status":500,"when":"`default_price` is not a whole number of thousandths, such as `9.5`. Nothing is saved."},{"fix":"Check the id.","status":404,"when":"No live variant with this id. `error.code` is null and `error.message` names the record type."},{"fix":"Ask a team owner to set Manage Products to \"Users CAN view, update and create products\".","status":403,"when":"Your role cannot update products. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Products and catalog","permission":"Needs the Manage Products permission at the level that can update products.","related":["v1_public_product_variant_show"],"rules":["Send `vendor_id` on every update: leaving it out, or sending an empty string, clears the variant's vendor.","The product id in the path is not checked: the variant is found by its own id within the team.","`supplier_id` is saved as sent; other fields, such as `barcode`, are not changed here."]}}},"/v1/api/store/{team_slug}/product_stock":{"post":{"description":"Read-only: returns the shop stock you hold for each product you list. Nothing is reserved or moved. Stock adjustments, stock takes and transfers are not part of the public API.\n\nFor each product the answer has `id`, `type` and `total`: `stock_on_hand`, `stock_incoming` (on purchase orders not yet received), `stock_not_usable` and `qty_need_ordering`, as decimal strings with eight decimal places, such as `\"24.00000000\"` (`\"0\"` when no stock row or aggregate matches; parse them as decimals), summed over your warehouses or, with `warehouse_id`, for that warehouse only. `inventories` lists the stock rows behind the totals, one per warehouse.\n\nCustomer-owned stock and hidden or deleted stock rows are left out. `custom` items are skipped, so the answer can be shorter than the list you sent.\n\nType names differ by operation. Here and on Load a product for a sales order line, your own simple product is `db_simple`; on sales order lines the same product is `user_simple`. A variant is `db_variant` and a catalog product `db_catalog` everywhere.","operationId":"v1_public_misc_product_stock","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"product":[{"id":"nFsgC7x4kiFeXu","type":"db_variant"},{"id":"ssa-B00000001","type":"db_catalog"}],"warehouse_id":"ILBTtiKrRcSSGA"},"schema":{"additionalProperties":false,"properties":{"product":{"items":{"additionalProperties":false,"properties":{"id":{"description":"Required unless `type` is `custom`. A product or variant hash id, or a catalog product id such as `ssa-B00000001`.","type":"string"},"type":{"description":"A simple product, a variant, a catalog product, or a custom line (skipped).","enum":["db_simple","db_variant","db_catalog","custom"],"type":"string"}},"required":["type"],"type":"object"},"minItems":1,"type":"array"},"warehouse_id":{"description":"A company location that holds stock. Leave it out to sum all of them.","type":"string"}},"required":["product"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"id":"nFsgC7x4kiFeXu","inventories":[{"id":"XBJYHgQMugO9Kv","stock_incoming":"48.00000000","stock_on_hand":"24.00000000","trashed":false,"warehouse_id":"ILBTtiKrRcSSGA"}],"total":{"qty_need_ordering":"0.00000000","stock_incoming":"48.00000000","stock_not_usable":"0.00000000","stock_on_hand":"24.00000000"},"type":"db_variant"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"id":{"type":"string"},"inventories":{"items":{"additionalProperties":true,"properties":{"id":{"type":"string"},"stock_incoming":{"description":"A decimal string, such as `\"24.00000000\"`; parse it as a decimal.","type":["string","null"]},"stock_on_hand":{"description":"A decimal string, such as `\"24.00000000\"`; parse it as a decimal.","type":["string","null"]},"trashed":{"type":"boolean"},"warehouse_id":{"type":"string"}},"type":"object"},"type":"array"},"total":{"properties":{"qty_need_ordering":{"description":"How many sales orders need that stock does not cover. A decimal string, such as `\"24.00000000\"`; parse it as a decimal (`\"0\"` when there is no aggregate).","type":"string"},"stock_incoming":{"description":"A decimal string, such as `\"24.00000000\"`; parse it as a decimal.","type":"string"},"stock_not_usable":{"description":"A decimal string, such as `\"24.00000000\"`; parse it as a decimal.","type":"string"},"stock_on_hand":{"description":"A decimal string, such as `\"24.00000000\"`; parse it as a decimal (`\"0\"` when there is no stock row).","type":"string"}},"required":["stock_on_hand","stock_incoming","stock_not_usable","qty_need_ordering"],"type":"object"},"type":{"description":"The line type: `db_simple`, `db_variant` or `db_catalog`.","type":"string"}},"required":["id","type","total"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get stock levels for products","tags":["Product stock"],"x-yoprint-docs":{"errors":[{"fix":"Check each id and type.","status":404,"when":"An id does not exist for its `type`. Nothing is returned for the others. `error.code` is null and `error.message` names the record type."},{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"`product` is empty, a `type` is not allowed, or an `id` is missing. `error.code` is `validation_failed`."}],"group":"Products and catalog","notes":["This is your own stock. A supplier's stock comes from Get live supplier inventory."],"permission":"Any member of the team.","related":["v1_public_real_time_data_fetcher_inventory","v1_public_hydrate_imported_product","v1_public_location_index"],"rules":["Deleted simple products and variants are still answered; an id that does not exist fails the whole request with 404."]}}},"/v1/api/store/{team_slug}/production_control/filter":{"post":{"description":"Returns the orders scheduled in a date range, each with its jobs and their tasks: the data behind the Production Control page.\n\nAn order is included when its own production dates, or one of its jobs' dates, fall in the range or span it. Quotes are left out unless `show_quote` is true. Drafts are always left out. The whole range comes back at once, without paging.\n\nFilters use dotted keys, one level each. Order filters choose orders; job and task filters also choose which jobs and tasks are listed inside each order.\n\n| `key` | `operator` | `value` |\n| --- | --- | --- |\n| `order.status_id`, `job.status_id`, `task.status_id` | `in`, `nin` | Status hash ids |\n| `order.status_type`, `job.status_type`, `task.status_type` | `in`, `nin` | `start`, `pre_production`, `in_progress`, `end` |\n| `order.customer_id` | `in`, `nin` | Customer hash ids |\n| `order.assigned_users`, `job.assigned_users`, `task.assigned_users` | `in`, `nin` | User hash ids |\n| `order.tag` | `in`, `nin` | Tag hash ids |\n| `task.pipeline_id` | `in`, `nin`, `eq` | Task preset hash ids |\n| `order.is_rush`, `job.is_rush` | `eq`, `neq` | `true` or `false` |\n| `order.due_date`, `order.created_date`, `job.start_date`, `job.due_date`, `task.start_date`, `task.due_date` | `eq`, `neq`, `gt`, `gte`, `lt`, `lte` | Days from today (UTC): 0 today, 7 a week ahead, -7 a week ago. Compared by date. |\n\n`order.due_date` compares the order's customer due (in-hand) date; `order.created_date` compares when it was created.\n\nFor non-rush jobs send `job.is_rush` `neq` `true`: `eq` `false` returns the orders with empty `jobs`. Unknown `order.*` keys are ignored. Unknown `job.*` and `task.*` keys don't change which orders come back, but still filter the listed jobs or tasks (a field that doesn't exist empties the list unless the operator is `neq` or `nin`). Send real user hash ids: `system-current-user` is not understood when the listed jobs and tasks are filtered.","operationId":"v1_public_production_control_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-11-30T00:00:00Z","filters":[{"key":"job.status_type","operator":"in","value":["start","in_progress"]},{"key":"task.pipeline_id","operator":"in","value":["SE3SfXjt6dPfnH"]}],"show_quote":false,"start_date":"2026-11-01T00:00:00Z"},"schema":{"properties":{"end_date":{"description":"The last day of the range (ISO 8601). Counted to the end of that day, in UTC like `start_date`.","format":"date-time","type":"string"},"filters":{"items":{"properties":{"key":{"description":"A dotted key from the table.","type":"string"},"operator":{"enum":["eq","neq","gt","gte","lt","lte","in","nin"],"type":"string"},"value":{"items":{"type":"string"},"type":["string","number","boolean","array"]}},"required":["key","operator"],"type":"object"},"type":"array"},"show_quote":{"default":false,"description":"Include quotes.","type":"boolean"},"start_date":{"description":"The first day of the range (ISO 8601). Counted from the start of that day. Send UTC (`Z`): the day is taken from the date as written and any offset is dropped.","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"approval_status":null,"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"calc_deposit_total":169880,"calc_discount":0,"calc_subtotal":315000,"calc_tax":24750,"calc_total":339750,"created_at":"2026-11-02T15:00:00+00:00","created_by":"4mdDkMg3dgQOa3","cust_due_date":"2026-11-10T00:00:00+00:00","customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"customer_id":"ifAHmADekGZ6id","customer_po_number":null,"customer_portal_order_link":"https://example.com/portal/order","customer_portal_payment_link":"https://example.com/portal/pay","deposit_due":"2026-11-05T00:00:00+00:00","deposit_required":true,"deposit_total":50000,"due_date":"2026-11-06T17:00:00+00:00","full_amount_due":"2026-11-20T00:00:00+00:00","id":"sFbALVSYD55eXe","is_quote":false,"is_rush":false,"issue_date":"2026-11-02T00:00:00+00:00","jobs":[{"assigned_users":[],"due_date":"2026-11-06T17:00:00+00:00","id":"WaGvtaWsx7Kcn4","item_count":48,"name":"Front print","pipelines":[{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"due_date":"2026-11-05T17:00:00+00:00","id":"hpioY1gDBQZdbI","name":"Burn screens","pipeline_id":"SE3SfXjt6dPfnH","start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_id":"hTFITko5Q0R83y"}],"scoped_id":"JOB-2419","start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"scaWHQnPLtqMPT","label":"Printing","position":3,"role":"job","trashed":false,"type":"in_progress"},"status_id":"scaWHQnPLtqMPT"}],"name":"Team shirts","object_type":"sales_order","paid_amount":100000,"payment_term_id":null,"scoped_id":"SO1001","ship_due_date":"2026-11-08T00:00:00+00:00","start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"wgbOT87gGZvhgy","label":"In production","position":2,"role":"order","trashed":false,"type":"in_progress"},"status_id":"wgbOT87gGZvhgy","unique_key":"ord_EXAMPLEuniqueKey","warehouse_id":null}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"An order (v1 order shape, amounts in thousandths) with its `status`, `customer`, `assigned_users` and matching `jobs` (no `tags`).","properties":{"approval_status":{"description":"`requested`, `need-changes`, `approved`, or null.","type":["string","null"]},"assigned_users":{"description":"People on the order.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"calc_deposit_total":{"description":"Deposit amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_discount":{"description":"Invoiced discount; 0 until invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_subtotal":{"description":"Invoiced line and shipping subtotal; 0 until the order is invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_tax":{"description":"Invoiced tax; 0 until invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_total":{"description":"Invoiced total; 0 until the order is invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"created_by":{"description":"Who created it.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Customer due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer":{"oneOf":[{"additionalProperties":true,"description":"The customer, as in Get a customer.","properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":"string"},"name":{"example":"Northwind Apparel","type":["string","null"]}},"type":"object"},{"type":"null"}]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_po_number":{"type":["string","null"]},"customer_portal_order_link":{"description":"Customer portal link. It carries the customer's portal access: don't publish it.","type":["string","null"]},"customer_portal_payment_link":{"description":"Customer portal payment page link, with the same access.","type":["string","null"]},"deposit_due":{"description":"Deposit due. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"deposit_required":{"type":"boolean"},"deposit_total":{"description":"The deposit **percentage** ×1000: `50000` is 50%. Not an amount.","example":50000,"type":["integer","number","string","null"]},"due_date":{"description":"Production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"full_amount_due":{"description":"Full amount due. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"is_quote":{"type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"jobs":{"description":"The order's jobs that match the `job.*` filters.","items":{"additionalProperties":true,"properties":{"assigned_users":{"items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"due_date":{"description":"Job due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"item_count":{"type":["number","null"]},"name":{"type":["string","null"]},"pipelines":{"description":"Its tasks that match the `task.*` filters.","items":{"additionalProperties":true,"properties":{"assigned_users":{"items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"name":{"type":"string"},"pipeline_id":{"description":"The task preset.","example":"SE3SfXjt6dPfnH","type":"string"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_id":{"description":"The task status.","example":"hTFITko5Q0R83y","type":"string"}},"type":"object"},"type":"array"},"scoped_id":{"example":"JOB-2419","type":"string"},"start_date":{"description":"Job start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_id":{"description":"The job status.","example":"scaWHQnPLtqMPT","type":"string"}},"type":"object"},"type":"array"},"name":{"type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"paid_amount":{"description":"Paid so far. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"payment_term_id":{"description":"Payment term.","example":null,"type":["string","null"]},"scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"ship_due_date":{"description":"Ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]},"unique_key":{"example":"ord_EXAMPLEuniqueKey","type":["string","null"]},"warehouse_id":{"description":"Warehouse.","example":null,"type":["string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Read the production control calendar","tags":["Production control"],"x-yoprint-docs":{"errors":[{"fix":"Send both dates and complete filters.","status":422,"when":"A date is missing or not ISO 8601, `show_quote` isn't a boolean, or a filter lacks `key` or `operator`."}],"group":"Production","notes":["A wide range returns every matching order with all its jobs and tasks in one response. Keep ranges to a few weeks."],"permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_job_calendar","v1_public_work_pipeline_calendar"],"rules":["`start_date` and `end_date` are required ISO 8601 dates; every filter needs a `key` and an `operator`."]}}},"/v1/api/store/{team_slug}/purchase_order/bulk_action/mark_quickbook/{on_or_off}":{"put":{"description":"Sets whether up to 50 purchase orders sync to QuickBooks Online. End the path with `on` to let them sync, or `off` (any other word) to stop them syncing. The body is a JSON array of `{id}`.\n\nIds that are not purchase orders of the team are skipped. Answers `success: true` with `data: null`.","operationId":"v1_public_purchase_order_bulk_action_mark_quickbook","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"`on` lets the purchase orders sync to QuickBooks Online; `off` stops them. Any word other than `on` counts as `off`.","example":"on","in":"path","name":"on_or_off","required":true,"schema":{"enum":["on","off"],"type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"12vR7n9WUYn1CJ"},{"id":"YJqSDANMFIj4p4"}],"schema":{"items":{"additionalProperties":false,"properties":{"id":{"description":"A purchase order id.","type":"string"}},"required":["id"],"type":"object"},"maxItems":50,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Turn QuickBooks sync on or off for purchase orders","tags":["Purchase orders"],"x-yoprint-docs":{"errors":[{"fix":"Send at most 50 per call.","status":422,"when":"More than 50 ids (`error.code` `limit_reached`). Nothing is changed."},{"fix":"Send `[{\"id\": \"...\"}]`.","status":422,"when":"An item has no `id`, or an id doesn't decode. `error.code` is `validation_failed`."}],"group":"Purchasing","permission":"Any member of the team.","related":["v1_public_purchase_order_export"],"rules":["At most 50 ids per request (422 `limit_reached`)."],"side_effects":["Changes only the sync flag. Nothing is sent to QuickBooks by this call; the next sync follows the flag."]}}},"/v1/api/store/{team_slug}/purchase_order/export":{"post":{"description":"Exports the team's purchase orders whose issue date falls between `start_date` and `end_date`.\n\n- By default the answer is a CSV file (`purchase_order_export_<time>.csv`) with these columns: `purchase_order_id`, `issue_date`, `due_date`, `vendor`, `billing_address_label`, `warehouse_label`, `creator`, `status`, `received_subtotal`, `received_tax`, `received_total`, `ordered_subtotal`, `ordered_tax`, `ordered_total`, `related_orders`, `related_customers`, `internal_note`, `vendor_note`.\n- With `list_only: true` the same purchase orders come back as JSON rows instead.\n\nFor the CSV, no purchase order in the range is a 422; with `list_only: true` it is an empty `data` list. The Download Center export (`data_export/export_purchase_order_list`) builds the same kind of file in the background.","operationId":"v1_public_purchase_order_export","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-10-31T23:59:59+00:00","list_only":true,"start_date":"2026-10-01T00:00:00+00:00"},"schema":{"additionalProperties":false,"properties":{"end_date":{"description":"ISO 8601 date and time. Issue dates on or before it, compared the same way.","format":"date-time","type":"string"},"list_only":{"default":false,"description":"True for JSON rows instead of a CSV file.","type":"boolean"},"start_date":{"description":"ISO 8601 date and time. Issue dates on or after it. The offset is not applied: the date and time are compared as written with issue dates kept in UTC, so send UTC times.","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"billing_address_label":"Head office","creator":"Alex Rivera","due_date":"2026-10-19","internal_note":null,"issue_date":"2026-10-05","name":null,"ordered_subtotal":"120.00","ordered_tax":"0.00","ordered_total":"120.00","purchase_order_id":"PO0042","received_subtotal":"120.00","received_tax":"0.00","received_total":"120.00","related_customers":"Northwind Apparel","related_orders":"SO1001","status":"Received","vendor":"Example Blanks Co","vendor_note":null,"warehouse_label":"Main warehouse"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"billing_address_label":{"type":["string","null"]},"creator":{"description":"Who created it, or an empty string.","type":"string"},"due_date":{"description":"`YYYY-MM-DD` in the team's time zone, or an empty string.","type":"string"},"internal_note":{"type":["string","null"]},"issue_date":{"description":"`YYYY-MM-DD` in the team's time zone, or an empty string.","type":"string"},"name":{"type":["string","null"]},"ordered_subtotal":{"description":"A decimal string with two decimals, such as `\"120.00\"`; parse it as a decimal.","type":"string"},"ordered_tax":{"type":"string"},"ordered_total":{"type":"string"},"purchase_order_id":{"description":"The purchase order number people see, not its id.","type":["string","integer"]},"received_subtotal":{"description":"A decimal string with two decimals, such as `\"125.00\"`; parse it as a decimal.","type":"string"},"received_tax":{"type":"string"},"received_total":{"type":"string"},"related_customers":{"description":"Their customers, one per line.","type":["string","null"]},"related_orders":{"description":"Linked sales order numbers, one per line.","type":["string","null"]},"status":{"type":["string","null"]},"vendor":{"description":"The vendor's name.","type":["string","null"]},"vendor_note":{"type":["string","null"]},"warehouse_label":{"type":["string","null"]}},"required":["purchase_order_id","vendor","status","ordered_total"],"type":"object"},"type":"array"},"status":{"type":"integer"},"success":{"type":"boolean"}},"required":["success","status","data"],"type":"object"}},"text/csv":{"schema":{"description":"One row per purchase order, with the columns listed above. The file name is `purchase_order_export_<unix time>.csv`.","format":"binary","type":"string"}}},"description":"A CSV file by default; JSON rows with `list_only: true`."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Export purchase orders by issue date","tags":["Purchase orders"],"x-yoprint-docs":{"errors":[{"fix":"Widen the range.","status":422,"when":"CSV only: no purchase order has an issue date in the range (`error.code` `purchase_order_export_error`, \"Purchase Order not found\"). With `list_only: true` the answer is an empty list instead."},{"fix":"Send both dates.","status":422,"when":"A date is missing or not ISO 8601. `error.code` is `validation_failed`."},{"fix":"Ask a team owner for View Reports.","status":403,"when":"Your role cannot view reports. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Purchasing","permission":"Needs the View Reports permission.","related":["v1_public_data_export_export_purchase_order_list","v1_public_purchase_order_history"],"rules":["Covers every purchase order of the team in the range, whoever it is assigned to."]}}},"/v1/api/store/{team_slug}/purchase_order/{hash_id}":{"get":{"description":"Returns one purchase order with its lines, status, vendor, delivery and billing addresses, creator and tags.\n\nThis operation is kept for YoPrint's Zapier app, which uses this path, and its answer keeps the flat line fields Zapier reads: each line in `items` has `product` (`type`, with `id` or `name`), `quantity`, `price` and totals as plain values. The public API has no newer purchase order operations to use instead: creating, editing and receiving purchase orders are not part of it.\n\nMoney in this answer is in **thousandths**, an older encoding (`10800` is 10.80): `calc_subtotal`, `calc_tax` and `calc_total` on the purchase order and on each line, and each line's `price`. A whole number of thousandths is a JSON integer; an amount finer than a thousandth comes back as a decimal string such as `\"12656.3\"`, whatever headers you send, so parse these as decimals. See [Money and quantities](/concepts/money-and-quantities/). A line's `quantity` is what is **still to receive**, not what was ordered; `received_total` is what has arrived. `items` lists every line, deleted and voided ones included, and the rows don't say which.\n\n`{hash_id}` is the purchase order's `id`, not its number (`PO0042`). Deleted purchase orders are not found.","operationId":"v1_public_purchase_order_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The purchase order's id (not its number, such as `PO0042`). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"billing_address":{"address1":"100 Example Street","address2":null,"address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"GXCU6IMtXEV9Qn","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main warehouse","nexus":true,"note":null,"owner_id":"g9NXwcqzTRIABH","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"billing_address_id":"GXCU6IMtXEV9Qn","calc_subtotal":120000,"calc_tax":9600,"calc_total":129600,"created_at":"2026-11-02T09:00:00+00:00","created_by":"lOURnovd3hkIQI","creator":{"avatar_url":null,"email":"alex@example.com","id":"lOURnovd3hkIQI","name":"Alex Rivera","timezone":"America/Chicago"},"doc_viewer_url":"https://example.com/documents/purchase-order","due_date":"2026-11-09T00:00:00+00:00","id":"12vR7n9WUYn1CJ","internal_note":null,"is_custom_warehouse":false,"issue_date":"2026-11-02T00:00:00+00:00","items":[{"calc_subtotal":108000,"calc_tax":8640,"calc_total":116640,"id":"szhbjt6FGUoOcW","non_inventory":false,"position":1,"price":4500,"product":{"color":"Black","id":"smr-10001","size":"L","type":"db_catalog"},"quantity":24,"received_total":0,"tax_total":0},{"calc_subtotal":12000,"calc_tax":960,"calc_total":12960,"id":"gJn3IswvuEsoUd","non_inventory":false,"position":2,"price":12000,"product":{"name":"Freight","type":"fee"},"quantity":1,"received_total":0,"tax_total":0}],"name":"Fall restock","pdf":[{"description":"Purchase Order Detail","label":"Purchase Order Detail","url":"https://example.com/pdf/purchase-order.pdf"},{"description":"Purchase Order Label","label":"Purchase Order Label (4\" x 6\")","url":"https://example.com/pdf/purchase-order-label.pdf"}],"pdf_url":"https://example.com/pdf/purchase-order.pdf","quickbook_disable_sync":false,"quickbook_last_error_sync":null,"quickbook_last_success_sync":null,"scoped_id":"PO0042","status":{"color":"#2196f3","customer_label":"In Progress","id":"pBxSsJQFExGsC5","label":"Ordered","position":2,"role":"purchase_order","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"pBxSsJQFExGsC5","status_last_change_date":"2026-11-03T09:00:00+00:00","tags":[],"tax_mode":"order_level","tax_rate":"0.080000","team":{"id":"g9NXwcqzTRIABH","name":"Example Print Shop","payment_gateway":[],"slug":"your-team","timezone":"America/Chicago"},"trashed":false,"updated_at":"2026-11-03T09:00:00+00:00","vendor":{"account_number":"ACCT-1001","contacts":[{"created_at":"2026-11-01T09:00:00+00:00","default_receive_sms":false,"email":"sam@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Sam","id":"fopJXRDkZ8Qk7S","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","trashed":false,"updated_at":"2026-11-01T09:00:00+00:00","vendor_id":"MFwvMEIK7ud89l"}],"default_vendor_note":null,"id":"MFwvMEIK7ud89l","internal_notes":null,"name":"Example Blanks Co","trashed":false,"website":"https://example.com"},"vendor_id":"MFwvMEIK7ud89l","vendor_note":"Deliver to the back dock.","version":2,"warehouse":{"address1":"100 Example Street","address2":null,"address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"GXCU6IMtXEV9Qn","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main warehouse","nexus":true,"note":null,"owner_id":"g9NXwcqzTRIABH","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"warehouse_can_hold_stock":true,"warehouse_id":"GXCU6IMtXEV9Qn"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"billing_address":{"additionalProperties":true,"description":"The billing address.","properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":["object","null"]},"billing_address_id":{"type":["string","null"]},"calc_subtotal":{"description":"The purchase order's subtotal. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"calc_tax":{"description":"Its tax. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"calc_total":{"description":"Its total. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"created_at":{"format":"date-time","type":["string","null"]},"created_by":{"description":"The team member who created it.","type":["string","null"]},"creator":{"additionalProperties":true,"description":"The team member who created it: `id`, `name`, `email`, `avatar_url`, `timezone` and a few profile flags.","properties":{"email":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]}},"type":["object","null"]},"doc_viewer_url":{"description":"A link that opens the purchase order in the document viewer, with the same kind of token.","type":"string"},"due_date":{"format":"date-time","type":["string","null"]},"id":{"description":"The purchase order's id: use it in the path.","type":"string"},"internal_note":{"type":["string","null"]},"is_custom_warehouse":{"description":"true when the delivery address is not one of the team's company locations.","type":"boolean"},"issue_date":{"format":"date-time","type":["string","null"]},"items":{"description":"Every line of the purchase order, including deleted and voided ones: the rows don't say which.","items":{"additionalProperties":false,"properties":{"calc_subtotal":{"description":"The line's subtotal as YoPrint stores it: usually `price` times the quantity ordered; on some older lines, times the quantity still to receive. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"calc_tax":{"description":"The line's tax. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"calc_total":{"description":"`calc_subtotal` plus `calc_tax`. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"id":{"description":"The line's id.","type":"string"},"non_inventory":{"description":"true for a line that doesn't track stock.","type":"boolean"},"position":{"description":"The line's place on the purchase order, or null. A whole number is a JSON integer; a fraction is a decimal string, such as `\"1.25\"`.","type":["integer","string","null"]},"price":{"description":"The unit price. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"product":{"additionalProperties":false,"description":"What the line buys, flat. `id` is a catalog item id such as `smr-10001` for `db_catalog`, or the hash id of your product or variant for `db_simple`, `user_simple` and `db_variant`; `name` is the line's own name for `custom`, `fee`, `fees` and `customer_provide_product`. Older lines can have `cart_item` or `order_item`, with that record's id. `size` and `color` appear only when the line has them.","properties":{"color":{"type":"string"},"id":{"type":"string"},"name":{"type":["string","null"]},"size":{"type":"string"},"type":{"description":"The product kind, such as `db_catalog`, `user_simple`, `db_variant`, `custom` or `fee`.","type":"string"}},"required":["type"],"type":"object"},"quantity":{"description":"The quantity **still to receive** (ordered minus received), not the quantity ordered. A whole number is a JSON integer; a fraction is a decimal string, such as `\"1.25\"`.","type":["integer","string"]},"received_total":{"description":"The quantity received so far. A whole number is a JSON integer; a fraction is a decimal string, such as `\"1.25\"`.","type":["integer","string"]},"tax_total":{"description":"The line's own tax rate, used when `tax_mode` is `line_level`, as a percentage ×1000: `8000` is 8% (0 when the line has none). A rate that is not a whole number comes back as a decimal string.","type":["integer","string"]}},"required":["id","product","price","tax_total","quantity","received_total","calc_subtotal","calc_tax","calc_total","non_inventory"],"type":"object"},"type":"array"},"name":{"type":["string","null"]},"pdf":{"description":"PDF links: the purchase order detail, its 4\" x 6\" label, and the team's custom purchase order templates. Each `url` carries a token like `pdf_url`.","items":{"additionalProperties":true,"properties":{"description":{"type":["string","null"]},"label":{"type":"string"},"url":{"type":"string"}},"type":"object"},"type":"array"},"pdf_url":{"description":"A link that downloads the purchase order PDF. Its token stops working 9,000 hours (about a year) after the answer was made, and anyone with the link can open the PDF: don't share it.","type":"string"},"quickbook_disable_sync":{"description":"true when QuickBooks sync is off for this purchase order.","type":"boolean"},"quickbook_last_error_sync":{"format":"date-time","type":["string","null"]},"quickbook_last_success_sync":{"format":"date-time","type":["string","null"]},"scoped_id":{"description":"The purchase order number people see, such as `PO0042`. Not an id.","type":"string"},"status":{"additionalProperties":true,"description":"The purchase order's status, as List purchase order statuses returns it: `id`, `role` (`purchase_order`), `type` (`start`, `pre_production`, `in_progress` or `end`), `label`, `customer_label`, `color`, `position` and `trashed`.","properties":{"id":{"type":"string"},"label":{"type":"string"},"role":{"type":"string"},"type":{"enum":["start","pre_production","in_progress","end"],"type":"string"}},"type":["object","null"]},"status_completion_date":{"description":"When it was moved to its final (`end`) status; null otherwise.","format":"date-time","type":["string","null"]},"status_id":{"type":["string","null"]},"status_last_change_date":{"format":"date-time","type":["string","null"]},"tags":{"items":{"additionalProperties":false,"properties":{"color_hex":{"description":"Such as `#2563EB`. Null for a tag saved without a color.","type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"tax_mode":{"description":"`order_level`: one `tax_rate` for the purchase order, and each line is taxable or not. `line_level`: each line has its own rate (`tax_total`).","type":["string","null"]},"tax_rate":{"description":"For `order_level`: the rate as a decimal string fraction with 6 decimals, `\"0.080000\"` is 8%. Null when not set.","type":["string","null"]},"team":{"additionalProperties":true,"description":"Your team, as the shared purchase order answer carries it: `id`, `name`, `slug`, contact details, the public ids of its enabled payment gateways, and `plan`. Nothing here is specific to the purchase order.","type":"object"},"trashed":{"type":"boolean"},"updated_at":{"format":"date-time","type":["string","null"]},"vendor":{"additionalProperties":true,"description":"The vendor with its contacts, as Get a vendor returns it.","properties":{"account_number":{"type":["string","null"]},"contacts":{"description":"Every contact, deleted ones included.","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"default_vendor_note":{"type":["string","null"]},"id":{"type":"string"},"internal_notes":{"type":["string","null"]},"name":{"type":["string","null"]},"trashed":{"description":"True when the vendor is deleted.","type":"boolean"},"website":{"type":["string","null"]}},"required":["id","name","trashed"],"type":["object","null"]},"vendor_id":{"type":["string","null"]},"vendor_note":{"description":"The note printed for the vendor.","type":["string","null"]},"version":{"description":"2 for purchase orders made in the current editor; 1 for older ones.","type":"integer"},"warehouse":{"additionalProperties":true,"description":"The delivery address, usually one of the team's company locations.","properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":["object","null"]},"warehouse_can_hold_stock":{"description":"true when the delivery address is set and holds stock, so receiving adds stock there.","type":"boolean"},"warehouse_id":{"description":"Where the goods are delivered.","type":["string","null"]}},"required":["id","scoped_id","status_id","trashed","calc_subtotal","calc_tax","calc_total","items"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a purchase order","tags":["Purchase orders"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team owner to give your role a Manage Purchase Order level.","status":403,"when":"Your role has no Manage Purchase Order permission to view. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the id, or ask to be assigned to the purchase order.","status":404,"when":"No live purchase order with this id in the team, or your role sees only purchase orders you created or are assigned to and this is not one of them. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","notes":["A line's `quantity` is the quantity still to receive. To get the quantity ordered, add `received_total`.","Read `status.type`: `end` means the purchase order is complete."],"permission":"Who can read it: the team owner; a role whose Manage Purchase Order level includes `view_all_po`, for any of the team's purchase orders; or one with `view_self_po`, only for purchase orders the API key's user created or is assigned to (any other purchase order answers 404).","related":["v1_public_purchase_order_change_status","v1_public_purchase_order_history","v1_public_status_list_purchase_order"]}}},"/v1/api/store/{team_slug}/purchase_order/{hash_id}/history":{"get":{"description":"Lists the activity recorded on a purchase order, newest first: who changed what, and when. The list is paged: `pagination` gives `total`, `count`, `perPage`, `currentPage` and `totalPages`. Ask for the next page with `page`; the page size is the team's setting (50 unless changed), and `per_page` is ignored.","operationId":"v1_public_purchase_order_history","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The purchase order's id (not its number, such as `PO0042`). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The page to return. Pages hold the team's page size (`pagination_per_page` in team settings: 50 unless changed, 5 to 100). `per_page` is not read here.","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"action":"purchase_order_changes","created_at":"2026-11-01T09:00:00+00:00","id":"31fxd6nKDhY683","message_key":"purchase_order.purchase_order_changes","object":{"changes":[{"key":"name","new":"Fall restock","old":null,"type":"string"}],"purchase_order":{"id":"12vR7n9WUYn1CJ","scoped_id":"PO0042"},"team":{"id":"GxZz8zgogK5dkh","name":"Example Print Shop"},"user":{"avatar_url":"https://example.com/avatars/alex.png","id":"lOURnovd3hkIQI","name":"Alex Rivera"}},"team":{"id":"g9NXwcqzTRIABH","name":"Example Print Shop","slug":"your-team"},"type":"purchase_order"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"action":{"description":"What happened to it.","type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"message_key":{"description":"The key of the sentence the web app shows for it.","type":["string","null"]},"object":{"additionalProperties":true,"description":"The details recorded for this change, free-form by `type` and `action`, plus `user` (`id`, `name`, `avatar_url`) when a person made it.","type":["object","array","null"]},"team":{"properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"}},"type":"object"},"type":{"description":"What kind of record changed.","type":["string","null"]}},"required":["id","type","action","created_at","object"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a purchase order's history","tags":["Purchase orders"],"x-yoprint-docs":{"errors":[{"fix":"Check the id.","status":404,"when":"No purchase order with this id in the team. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Any member of the team.","related":["v1_public_purchase_order_export"]}}},"/v1/api/store/{team_slug}/purchase_order/{hash_id}/status":{"put":{"description":"Moves a purchase order to another of the team's purchase order statuses and returns the purchase order, in the same shape as Get a purchase order.\n\nThis operation is kept for YoPrint's Zapier app, which uses this path, and its answer keeps the flat line fields Zapier reads: each line in `items` has `product` (`type`, with `id` or `name`), `quantity`, `price` and totals as plain values. The public API has no newer purchase order operations to use instead: creating, editing and receiving purchase orders are not part of it.\n\nMoving it to the final status (`type` `end`) marks it complete. When it is delivered to a company location that holds stock, every line except fees must be fully received first: this operation does not receive anything. Any other status clears the completion date.\n\n`{hash_id}` is the purchase order's `id`, not its number (`PO0042`).","operationId":"v1_public_purchase_order_change_status","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The purchase order's id (not its number, such as `PO0042`). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"status_id":"mOR2M727uLiHaX"},"schema":{"properties":{"status_id":{"description":"The `id` of one of the team's purchase order statuses, from List purchase order statuses.","type":"string"}},"required":["status_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"billing_address":{"address1":"100 Example Street","address2":null,"address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"GXCU6IMtXEV9Qn","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main warehouse","nexus":true,"note":null,"owner_id":"g9NXwcqzTRIABH","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"billing_address_id":"GXCU6IMtXEV9Qn","calc_subtotal":120000,"calc_tax":9600,"calc_total":129600,"created_at":"2026-11-02T09:00:00+00:00","created_by":"lOURnovd3hkIQI","creator":{"avatar_url":null,"email":"alex@example.com","id":"lOURnovd3hkIQI","name":"Alex Rivera","timezone":"America/Chicago"},"doc_viewer_url":"https://example.com/documents/purchase-order","due_date":"2026-11-09T00:00:00+00:00","id":"12vR7n9WUYn1CJ","internal_note":null,"is_custom_warehouse":false,"issue_date":"2026-11-02T00:00:00+00:00","items":[{"calc_subtotal":108000,"calc_tax":8640,"calc_total":116640,"id":"szhbjt6FGUoOcW","non_inventory":false,"position":1,"price":4500,"product":{"color":"Black","id":"smr-10001","size":"L","type":"db_catalog"},"quantity":0,"received_total":24,"tax_total":0},{"calc_subtotal":12000,"calc_tax":960,"calc_total":12960,"id":"gJn3IswvuEsoUd","non_inventory":false,"position":2,"price":12000,"product":{"name":"Freight","type":"fee"},"quantity":1,"received_total":0,"tax_total":0}],"name":"Fall restock","pdf":[{"description":"Purchase Order Detail","label":"Purchase Order Detail","url":"https://example.com/pdf/purchase-order.pdf"},{"description":"Purchase Order Label","label":"Purchase Order Label (4\" x 6\")","url":"https://example.com/pdf/purchase-order-label.pdf"}],"pdf_url":"https://example.com/pdf/purchase-order.pdf","quickbook_disable_sync":false,"quickbook_last_error_sync":null,"quickbook_last_success_sync":null,"scoped_id":"PO0042","status":{"color":"#4caf50","customer_label":"Completed","id":"mOR2M727uLiHaX","label":"Received","position":3,"role":"purchase_order","trashed":false,"type":"end"},"status_completion_date":"2026-11-06T09:00:00+00:00","status_id":"mOR2M727uLiHaX","status_last_change_date":"2026-11-06T09:00:00+00:00","tags":[],"tax_mode":"order_level","tax_rate":"0.080000","team":{"id":"g9NXwcqzTRIABH","name":"Example Print Shop","payment_gateway":[],"slug":"your-team","timezone":"America/Chicago"},"trashed":false,"updated_at":"2026-11-06T09:00:00+00:00","vendor":{"account_number":"ACCT-1001","contacts":[{"created_at":"2026-11-01T09:00:00+00:00","default_receive_sms":false,"email":"sam@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Sam","id":"fopJXRDkZ8Qk7S","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","trashed":false,"updated_at":"2026-11-01T09:00:00+00:00","vendor_id":"MFwvMEIK7ud89l"}],"default_vendor_note":null,"id":"MFwvMEIK7ud89l","internal_notes":null,"name":"Example Blanks Co","trashed":false,"website":"https://example.com"},"vendor_id":"MFwvMEIK7ud89l","vendor_note":"Deliver to the back dock.","version":2,"warehouse":{"address1":"100 Example Street","address2":null,"address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"GXCU6IMtXEV9Qn","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main warehouse","nexus":true,"note":null,"owner_id":"g9NXwcqzTRIABH","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"warehouse_can_hold_stock":true,"warehouse_id":"GXCU6IMtXEV9Qn"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"billing_address":{"additionalProperties":true,"description":"The billing address.","properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":["object","null"]},"billing_address_id":{"type":["string","null"]},"calc_subtotal":{"description":"The purchase order's subtotal. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"calc_tax":{"description":"Its tax. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"calc_total":{"description":"Its total. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"created_at":{"format":"date-time","type":["string","null"]},"created_by":{"description":"The team member who created it.","type":["string","null"]},"creator":{"additionalProperties":true,"description":"The team member who created it: `id`, `name`, `email`, `avatar_url`, `timezone` and a few profile flags.","properties":{"email":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":["string","null"]}},"type":["object","null"]},"doc_viewer_url":{"description":"A link that opens the purchase order in the document viewer, with the same kind of token.","type":"string"},"due_date":{"format":"date-time","type":["string","null"]},"id":{"description":"The purchase order's id: use it in the path.","type":"string"},"internal_note":{"type":["string","null"]},"is_custom_warehouse":{"description":"true when the delivery address is not one of the team's company locations.","type":"boolean"},"issue_date":{"format":"date-time","type":["string","null"]},"items":{"description":"Every line of the purchase order, including deleted and voided ones: the rows don't say which.","items":{"additionalProperties":false,"properties":{"calc_subtotal":{"description":"The line's subtotal as YoPrint stores it: usually `price` times the quantity ordered; on some older lines, times the quantity still to receive. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"calc_tax":{"description":"The line's tax. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"calc_total":{"description":"`calc_subtotal` plus `calc_tax`. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"id":{"description":"The line's id.","type":"string"},"non_inventory":{"description":"true for a line that doesn't track stock.","type":"boolean"},"position":{"description":"The line's place on the purchase order, or null. A whole number is a JSON integer; a fraction is a decimal string, such as `\"1.25\"`.","type":["integer","string","null"]},"price":{"description":"The unit price. Thousandths, an older encoding: `10800` is 10.80. A whole number of thousandths comes back as a JSON integer; an amount finer than a thousandth comes back as a decimal string, such as `\"12656.3\"`, whatever headers you send. Parse it as a decimal. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","string"]},"product":{"additionalProperties":false,"description":"What the line buys, flat. `id` is a catalog item id such as `smr-10001` for `db_catalog`, or the hash id of your product or variant for `db_simple`, `user_simple` and `db_variant`; `name` is the line's own name for `custom`, `fee`, `fees` and `customer_provide_product`. Older lines can have `cart_item` or `order_item`, with that record's id. `size` and `color` appear only when the line has them.","properties":{"color":{"type":"string"},"id":{"type":"string"},"name":{"type":["string","null"]},"size":{"type":"string"},"type":{"description":"The product kind, such as `db_catalog`, `user_simple`, `db_variant`, `custom` or `fee`.","type":"string"}},"required":["type"],"type":"object"},"quantity":{"description":"The quantity **still to receive** (ordered minus received), not the quantity ordered. A whole number is a JSON integer; a fraction is a decimal string, such as `\"1.25\"`.","type":["integer","string"]},"received_total":{"description":"The quantity received so far. A whole number is a JSON integer; a fraction is a decimal string, such as `\"1.25\"`.","type":["integer","string"]},"tax_total":{"description":"The line's own tax rate, used when `tax_mode` is `line_level`, as a percentage ×1000: `8000` is 8% (0 when the line has none). A rate that is not a whole number comes back as a decimal string.","type":["integer","string"]}},"required":["id","product","price","tax_total","quantity","received_total","calc_subtotal","calc_tax","calc_total","non_inventory"],"type":"object"},"type":"array"},"name":{"type":["string","null"]},"pdf":{"description":"PDF links: the purchase order detail, its 4\" x 6\" label, and the team's custom purchase order templates. Each `url` carries a token like `pdf_url`.","items":{"additionalProperties":true,"properties":{"description":{"type":["string","null"]},"label":{"type":"string"},"url":{"type":"string"}},"type":"object"},"type":"array"},"pdf_url":{"description":"A link that downloads the purchase order PDF. Its token stops working 9,000 hours (about a year) after the answer was made, and anyone with the link can open the PDF: don't share it.","type":"string"},"quickbook_disable_sync":{"description":"true when QuickBooks sync is off for this purchase order.","type":"boolean"},"quickbook_last_error_sync":{"format":"date-time","type":["string","null"]},"quickbook_last_success_sync":{"format":"date-time","type":["string","null"]},"scoped_id":{"description":"The purchase order number people see, such as `PO0042`. Not an id.","type":"string"},"status":{"additionalProperties":true,"description":"The purchase order's status, as List purchase order statuses returns it: `id`, `role` (`purchase_order`), `type` (`start`, `pre_production`, `in_progress` or `end`), `label`, `customer_label`, `color`, `position` and `trashed`.","properties":{"id":{"type":"string"},"label":{"type":"string"},"role":{"type":"string"},"type":{"enum":["start","pre_production","in_progress","end"],"type":"string"}},"type":["object","null"]},"status_completion_date":{"description":"When it was moved to its final (`end`) status; null otherwise.","format":"date-time","type":["string","null"]},"status_id":{"type":["string","null"]},"status_last_change_date":{"format":"date-time","type":["string","null"]},"tags":{"items":{"additionalProperties":false,"properties":{"color_hex":{"description":"Such as `#2563EB`. Null for a tag saved without a color.","type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"tax_mode":{"description":"`order_level`: one `tax_rate` for the purchase order, and each line is taxable or not. `line_level`: each line has its own rate (`tax_total`).","type":["string","null"]},"tax_rate":{"description":"For `order_level`: the rate as a decimal string fraction with 6 decimals, `\"0.080000\"` is 8%. Null when not set.","type":["string","null"]},"team":{"additionalProperties":true,"description":"Your team, as the shared purchase order answer carries it: `id`, `name`, `slug`, contact details, the public ids of its enabled payment gateways, and `plan`. Nothing here is specific to the purchase order.","type":"object"},"trashed":{"type":"boolean"},"updated_at":{"format":"date-time","type":["string","null"]},"vendor":{"additionalProperties":true,"description":"The vendor with its contacts, as Get a vendor returns it.","properties":{"account_number":{"type":["string","null"]},"contacts":{"description":"Every contact, deleted ones included.","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"default_vendor_note":{"type":["string","null"]},"id":{"type":"string"},"internal_notes":{"type":["string","null"]},"name":{"type":["string","null"]},"trashed":{"description":"True when the vendor is deleted.","type":"boolean"},"website":{"type":["string","null"]}},"required":["id","name","trashed"],"type":["object","null"]},"vendor_id":{"type":["string","null"]},"vendor_note":{"description":"The note printed for the vendor.","type":["string","null"]},"version":{"description":"2 for purchase orders made in the current editor; 1 for older ones.","type":"integer"},"warehouse":{"additionalProperties":true,"description":"The delivery address, usually one of the team's company locations.","properties":{"address1":{"type":["string","null"]},"address2":{"type":["string","null"]},"address_family_id":{"description":"Shared by an address and the copies made when it was edited after use.","type":["string","null"]},"city":{"type":["string","null"]},"copied_from_address_id":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"customer_id":{"description":"Customer addresses only: the customer's id.","type":"string"},"external_type":{"description":"`shopify` for an address synced from Shopify.","type":["string","null"]},"hold_stock":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"id":{"type":"string"},"is_current_source":{"description":"False for deleted, replaced, Shopify or redacted addresses. Only current addresses can be picked for new documents or edited.","type":"boolean"},"is_default_warehouse":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"is_external":{"description":"True for an address synced from Shopify; such addresses are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"nexus":{"description":"Company locations only; false for customer addresses.","type":"boolean"},"note":{"type":["string","null"]},"owner_id":{"description":"The owner's id: for a customer address, the customer's id (the same as `customer_id`).","type":["string","null"]},"owner_type":{"description":"`customer` for customer addresses.","enum":["customer","team","unknown"],"type":"string"},"postal_can_validate":{"type":"boolean"},"postal_is_valid":{"type":"boolean"},"postal_validated":{"description":"True once YoPrint has checked the address with its address validator. `postal_can_validate` says whether it could be checked and `postal_is_valid` gives the result. Any edit resets it to false.","type":"boolean"},"postcode":{"type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` when updating the address to protect against concurrent edits.","type":"integer"},"role":{"description":"`billing` or `shipping` for customer addresses.","type":"string"},"source":{"description":"`customer` for customer addresses.","enum":["customer","company_location","custom","unknown"],"type":"string"},"state":{"type":["string","null"]},"state_code":{"type":["string","null"]},"superseded_at":{"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"Set on an old copy: the address that replaced it.","type":["string","null"]},"trashed":{"type":"boolean"},"used_by_active_profile":{"description":"True when a brand profile uses it as Ship From. Sent on lists, reads, updates and customer answers; not on create or set-primary.","type":"boolean"}},"required":["id","label","address1","role","is_primary","trashed","revision_number","is_current_source"],"type":["object","null"]},"warehouse_can_hold_stock":{"description":"true when the delivery address is set and holds stock, so receiving adds stock there.","type":"boolean"},"warehouse_id":{"description":"Where the goods are delivered.","type":["string","null"]}},"required":["id","scoped_id","status_id","trashed","calc_subtotal","calc_tax","calc_total","items"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change a purchase order's status","tags":["Purchase orders"],"x-yoprint-docs":{"errors":[{"fix":"Send the `id` of a purchase order status.","status":422,"when":"`status_id` is missing or is not an id. `error.code` is `validation_failed`."},{"fix":"Pick a status from List purchase order statuses.","status":422,"when":"`status_id` is not one of this team's purchase order statuses (`error.code` `validation_error`, \"Invalid status_id for purchase order\")."},{"fix":"Receive the remaining items in YoPrint first, or pick a status that is not `end`.","status":422,"when":"Moving to the `end` status while lines are still to be received (\"Purchase Order cannot be completed without receiving all the items\"), or while the delivery location is no longer current (\"Purchase Order cannot be completed with an inactive warehouse location\"). `error.code` is `validation_error`; nothing changes."},{"fix":"Ask a team owner for a Manage Purchase Order level that can update.","status":403,"when":"Your role has no Manage Purchase Order permission to update. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the id, or ask to be assigned to the purchase order.","status":404,"when":"No live purchase order with this id in the team, or your role updates only purchase orders you created or are assigned to and this is not one of them. Nothing changes. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Who can update it: the team owner; a role whose Manage Purchase Order level includes `update_all_po`, for any of the team's purchase orders; or one with `update_self_po`, only for purchase orders the API key's user created or is assigned to (any other purchase order answers 404).","related":["v1_public_purchase_order_show","v1_public_status_list_purchase_order","v1_public_purchase_order_history"],"rules":["`status_id` must be a purchase order status of this team (role `purchase_order`): a sales order, job or shipment status is refused.","To move to the `end` status, a purchase order delivered to a company location that holds stock must have every live line except fees fully received (deleted and voided lines don't count), and that location must still be current (not deleted or replaced).","Sending the status it already has is accepted: it saves again and sends the webhook again."],"side_effects":["Sets the status and its change date; an `end` status also sets `status_completion_date`, any other clears it.","Sends the `purchase_order.status_changed` webhook on every call, even when the status didn't change.","When the status really changes, adds a status change to the purchase order's history.","Sends no email and does not sync to QuickBooks Online."]}}},"/v1/api/store/{team_slug}/quote/export":{"post":{"description":"Downloads a CSV file of the published quotes whose issue date is in a range. Drafts and deleted quotes are left out.\n\nSend `start_date` and `end_date` as ISO 8601 date-times, for example `2026-11-01T00:00:00Z` and `2026-11-30T23:59:59Z`. They are compared as given, so a date alone means midnight UTC and an end date of `2026-11-30` leaves out most of that day.\n\nThe rows have the sales order export's columns, read from each quote. With `list_only: true` they come back as JSON in `data` instead of a file (an empty range answers `data: []`), and the quote number is in `quote_id`. In the CSV file the number's column is headed `order_id` and comes out empty: read the number from the JSON rows, or match quotes by name.","operationId":"v1_public_v1_quote_export","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-11-30T23:59:59Z","list_only":true,"start_date":"2026-11-01T00:00:00Z"},"schema":{"properties":{"end_date":{"description":"End of the issue date range (ISO 8601).","format":"date-time","type":"string"},"list_only":{"description":"true to get the rows as JSON instead of a CSV file.","type":"boolean"},"start_date":{"description":"Start of the issue date range (ISO 8601).","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"balance_due":"0.00","customer_name":"Northwind Apparel","customer_tax_exempt":"FALSE","discount":"0.00","issue_date":"2026-11-03","name":"Fall jackets","paid":"TRUE","quote_id":"SO1002","status":"Sent","subtotal":"125.00","tax":"0.00","total":"0.00"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"One quote as JSON: the sales order export's columns, with `quote_id` instead of `order_id`.","properties":{"balance_due":{"description":"Invoiced total minus paid. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"client_note":{"type":["string","null"]},"creator":{"description":"Created By's name, or an empty string.","type":"string"},"customer_brand_profile":{"type":["string","null"]},"customer_contact_name":{"type":["string","null"]},"customer_email":{"type":["string","null"]},"customer_in_hand_date":{"description":"`YYYY-MM-DD`, or an empty string.","type":"string"},"customer_name":{"type":["string","null"]},"customer_po_number":{"type":["string","null"]},"customer_tax_exempt":{"enum":["TRUE","FALSE"],"type":"string"},"discount":{"description":"Invoiced discount; `\"0.00\"` until invoiced. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"issue_date":{"description":"`YYYY-MM-DD` in the team's time zone.","type":"string"},"jobs":{"description":"The jobs, one per line.","type":["string","null"]},"last_payment_date":{"type":["string","null"]},"name":{"description":"The order's name. JSON rows only: the CSV file has no `name` column.","type":["string","null"]},"paid":{"description":"`TRUE` when the invoiced total is paid.","enum":["TRUE","FALSE"],"type":"string"},"payment_term":{"type":["string","null"]},"pricing_group":{"type":["string","null"]},"pricing_strategy":{"type":["string","null"]},"prod_note":{"type":["string","null"]},"production_due_date":{"description":"`YYYY-MM-DD`, or an empty string.","type":"string"},"production_start_date":{"description":"`YYYY-MM-DD`, or an empty string.","type":"string"},"quote_id":{"description":"The quote number (not the id). In the CSV file this column is named `order_id` and comes out empty.","example":"SO1002","type":"string"},"shipment_due_date":{"description":"`YYYY-MM-DD`, or an empty string.","type":"string"},"status":{"description":"The status label.","type":["string","null"]},"subtotal":{"description":"The value of the order's lines. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"tags":{"description":"Tag names, comma-separated.","type":["string","null"]},"tax":{"description":"Invoiced tax; `\"0.00\"` until invoiced. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"total":{"description":"Invoiced total; `\"0.00\"` until invoiced. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"warehouse":{"type":["string","null"]}},"type":"object"},"type":"array"},"status":{"type":"integer"},"success":{"type":"boolean"}},"required":["success","status","data"],"type":"object"}},"text/csv":{"schema":{"description":"The quotes, one per row.","format":"binary","type":"string"}}},"description":"The CSV file, or with `list_only: true` the rows as JSON."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Export quotes as CSV","tags":["Quotes"],"x-yoprint-docs":{"errors":[{"fix":"Widen the range.","status":422,"when":"No quote is in the range, for the file: `quote_export_error` \"Quotes not found\". (With `list_only: true` the answer is `data: []`.)"},{"fix":"Ask the team owner for report permission.","status":403,"when":"The role lacks `view_report`. This error has no envelope: the body is `{\"message\": \"Insufficient Permission\"}`."}],"group":"Sales","permission":"Needs the `view_report` permission.","related":["v1_public_sales_order_export","v2_public_quote_filter"],"rules":["`start_date` and `end_date` are required."]}}},"/v1/api/store/{team_slug}/quote/filter":{"post":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_quote_filter` (POST /v2/api/store/{team_slug}/v2/quote/filter) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nRetired: this v1 operation no longer works. Every call fails with HTTP 500 and the body `{\"message\": \"Server Error\"}`. Use List quotes (`v2.public.quote.filter`) to list quotes.","operationId":"v1_public_v1_quote_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"description":"Never sent: this route always fails with HTTP 500."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Filter quotes (retired v1)","tags":["Quotes"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Use List quotes.","status":500,"when":"Always: `{\"message\": \"Server Error\"}`."}],"group":"Sales","prefer":"v2_public_quote_filter","related":["v2_public_quote_filter"],"status":"legacy"}}},"/v1/api/store/{team_slug}/real_time_data_fetcher/images":{"post":{"description":"Returns each catalog product's images: `local_images` (from YoPrint's copy of the catalog) and `real_time_images` (from the supplier), each with `images`, `color_image`, `preview_url` and `provider_meta`.","operationId":"v1_public_real_time_data_fetcher_images","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"product":[{"id":"ssa-B00000001","type":"db_catalog"},{"id":"ssa-B00000002","type":"db_catalog"}]},"schema":{"additionalProperties":false,"properties":{"product":{"items":{"additionalProperties":false,"properties":{"id":{"description":"A supplier catalog product id: one size and color of a style, such as `ssa-B00000001`.","type":"string"},"type":{"const":"db_catalog","type":"string"}},"required":["type","id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}},"required":["product"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"id":"ssa-B00000001","local_images":{"data":{"color_image":"https://example.com/swatches/black.jpg","images":[{"url":"https://example.com/catalog/ssa-B00000001-front.jpg"}],"preview_url":"https://example.com/catalog/ssa-B00000001-front.jpg","provider_meta":null},"errors":null,"success":true},"real_time_images":{"data":null,"errors":[{"code":"invalid_credentials","message":"ssa Credential Is Not Valid","retryable":false,"type":"provider_pre_check_error"}],"success":false}},{"id":"ssa-B00000002","local_images":{"data":{"color_image":"https://example.com/swatches/black.jpg","images":[{"url":"https://example.com/catalog/ssa-B00000002-front.jpg"}],"preview_url":"https://example.com/catalog/ssa-B00000002-front.jpg","provider_meta":null},"errors":null,"success":true},"real_time_images":{"data":null,"errors":[{"code":"invalid_credentials","message":"ssa Credential Is Not Valid","retryable":false,"type":"provider_pre_check_error"}],"success":false}}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"id":{"type":"string"},"local_images":{"description":"Images from YoPrint's copy of the catalog.","properties":{"data":{"additionalProperties":true,"properties":{"color_image":{"type":["string","null"]},"images":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"preview_url":{"type":["string","null"]},"provider_meta":{"additionalProperties":true,"type":["object","array","null"]}},"type":["object","null"]},"errors":{"description":"Null when the part succeeded. On a failure, the reasons (an empty list when none was recorded).","items":{"additionalProperties":true,"properties":{"code":{"enum":["account_missing","invalid_credentials","unsupported_format","image_not_found","image_load_failed","provider_unavailable","unknown"],"type":"string"},"message":{"description":"Readable reason, such as \"Real Time Pricing is not available for this team plan.\", or `internal error` when the reason is not shown.","type":"string"},"retryable":{"description":"True for `provider_unavailable`, `image_load_failed` and `unknown`.","type":"boolean"},"type":{"type":"string"}},"type":"object"},"type":["array","null"]},"success":{"type":"boolean"}},"required":["success","errors","data"],"type":"object"},"real_time_images":{"description":"Images from the supplier.","properties":{"data":{"additionalProperties":true,"properties":{"color_image":{"type":["string","null"]},"images":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"preview_url":{"type":["string","null"]},"provider_meta":{"additionalProperties":true,"type":["object","array","null"]}},"type":["object","null"]},"errors":{"description":"Null when the part succeeded. On a failure, the reasons (an empty list when none was recorded).","items":{"additionalProperties":true,"properties":{"code":{"enum":["account_missing","invalid_credentials","unsupported_format","image_not_found","image_load_failed","provider_unavailable","unknown"],"type":"string"},"message":{"description":"Readable reason, such as \"Real Time Pricing is not available for this team plan.\", or `internal error` when the reason is not shown.","type":"string"},"retryable":{"description":"True for `provider_unavailable`, `image_load_failed` and `unknown`.","type":"boolean"},"type":{"type":"string"}},"type":"object"},"type":["array","null"]},"success":{"type":"boolean"}},"required":["success","errors","data"],"type":"object"}},"required":["id","local_images","real_time_images"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get supplier images for catalog products","tags":["Supplier catalog"],"x-yoprint-docs":{"errors":[{"fix":"Send 1 to 100 items with `type: db_catalog`.","status":422,"when":"`product` is missing, empty or has more than 100 items, or a `type` is not `db_catalog`. `error.code` is `validation_failed`."},{"fix":"Check each part's `success`. Read `errors[].code` and `message`; fix the plan or the connection under Apps, or retry later for `provider_unavailable`.","status":200,"when":"A product, or one part of its answer, failed: not found, plan, supplier connection, or the supplier's API. The request still answers 200 with `success: true`; that part has `success: false`, `data: null` and its reasons in `errors`."}],"group":"Products and catalog","permission":"Any member of the team.","related":["v1_public_hydrate_imported_product"],"rules":["Send 1 to 100 products per request. Every `type` is `db_catalog`.","The answer is 200 once the body is valid; each part says `success` and `errors`.","Images do not depend on the plan. Most suppliers need a working connection under Apps (`account_missing` or `invalid_credentials` otherwise)."],"side_effects":["Calls each supplier's API with your team's credentials; requests to different suppliers run in parallel. Answers are cached for 30 seconds, so a repeat within that time does not call the supplier again."]}}},"/v1/api/store/{team_slug}/real_time_data_fetcher/inventory":{"post":{"description":"Returns how many units each supplier has of each catalog product, fetched live: `real_time_inventory.data.total_count` and `warehouses` (each with `id`, `name` and `count`). This is the supplier's stock, not yours; for your own stock use Get stock levels for products.","operationId":"v1_public_real_time_data_fetcher_inventory","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"product":[{"id":"ssa-B00000001","type":"db_catalog"},{"id":"ssa-B00000002","type":"db_catalog"}]},"schema":{"additionalProperties":false,"properties":{"product":{"items":{"additionalProperties":false,"properties":{"id":{"description":"A supplier catalog product id: one size and color of a style, such as `ssa-B00000001`.","type":"string"},"type":{"const":"db_catalog","type":"string"}},"required":["type","id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}},"required":["product"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"id":"ssa-B00000001","real_time_inventory":{"data":{"total_count":1250,"warehouses":[{"count":1000,"id":"IL","metadata":[],"name":"Illinois"},{"count":250,"id":"NV","metadata":[],"name":"Nevada"}]},"errors":null,"success":true}},{"id":"ssa-B00000002","real_time_inventory":{"data":{"total_count":600,"warehouses":[{"count":600,"id":"IL","metadata":[],"name":"Illinois"}]},"errors":null,"success":true}}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"id":{"type":"string"},"real_time_inventory":{"description":"Stock at the supplier, fetched live.","properties":{"data":{"additionalProperties":true,"properties":{"total_count":{"type":"integer"},"warehouses":{"items":{"additionalProperties":true,"properties":{"count":{"type":"integer"},"id":{"type":["string","integer","null"]},"metadata":{"additionalProperties":true,"description":"Supplier-specific details; an empty list `[]` when there are none.","type":["object","array"]},"name":{"type":["string","null"]}},"type":"object"},"type":"array"}},"type":["object","null"]},"errors":{"description":"Null when the part succeeded. On a failure, the reasons (an empty list when none was recorded).","items":{"additionalProperties":true,"properties":{"code":{"enum":["account_missing","invalid_credentials","unsupported_format","image_not_found","image_load_failed","provider_unavailable","unknown"],"type":"string"},"message":{"description":"Readable reason, such as \"Real Time Pricing is not available for this team plan.\", or `internal error` when the reason is not shown.","type":"string"},"retryable":{"description":"True for `provider_unavailable`, `image_load_failed` and `unknown`.","type":"boolean"},"type":{"type":"string"}},"type":"object"},"type":["array","null"]},"success":{"type":"boolean"}},"required":["success","errors","data"],"type":"object"}},"required":["id","real_time_inventory"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get live supplier inventory for catalog products","tags":["Supplier catalog"],"x-yoprint-docs":{"errors":[{"fix":"Send 1 to 100 items with `type: db_catalog`.","status":422,"when":"`product` is missing, empty or has more than 100 items, or a `type` is not `db_catalog`. `error.code` is `validation_failed`."},{"fix":"Check each part's `success`. Read `errors[].code` and `message`; fix the plan or the connection under Apps, or retry later for `provider_unavailable`.","status":200,"when":"A product, or one part of its answer, failed: not found, plan, supplier connection, or the supplier's API. The request still answers 200 with `success: true`; that part has `success: false`, `data: null` and its reasons in `errors`."}],"group":"Products and catalog","notes":["Inventory answers are cached for 30 seconds across all teams, so two teams asking at once may see the same numbers."],"permission":"Any member of the team.","related":["v1_public_real_time_data_fetcher_pricing_with_inventory","v1_public_misc_product_stock"],"rules":["Send 1 to 100 products per request. Every `type` is `db_catalog`.","The answer is always 200 once the body is valid: each product says `success` and `errors` for each part. A wrong id comes back as a failed part, not a 404.","Live data needs two things. The team's plan must include real-time vendor stock and pricing (otherwise \"Real Time Pricing is not available for this team plan.\" or \"Real Time Inventory is not available for this team plan.\"). And the supplier must be connected in Team settings, under Apps, with working credentials (otherwise `account_missing` or `invalid_credentials`).","Suppliers with live data: S&S Activewear (US and Canada), SanMar (US and Canada), Momentec / Augusta Sportswear (US and Canada) and AS Colour (US). AlphaBroder, Conde, TSF and Delta Apparel are no longer live (\"Catalog Product is deprecated.\"); their stored prices still come back in `local_pricing`."],"side_effects":["Calls each supplier's API with your team's credentials; requests to different suppliers run in parallel. Answers are cached for 30 seconds, so a repeat within that time does not call the supplier again."]}}},"/v1/api/store/{team_slug}/real_time_data_fetcher/pricing":{"post":{"description":"Returns each catalog product's cost from its supplier: `local_pricing` (YoPrint's stored copy of the supplier price list) and `real_time_pricing` (fetched live from the supplier with your team's connection, including your account's own price `your_price` and any `sales_price`).\n\nPrices are decimal pairs: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Read `dp` every time: it can differ between fields and records. Use the one you pick as the supplier cost of a catalog sales order line: `pricing.catalog.total` takes the pair as is, and `pricing.catalog.selected` names it (`piece`, `dozen`, `case`, `account` for `your_price`, `sales` for `sales_price`). YoPrint then applies your team's pricing to get the selling price; see Add a line item.\n\n**Ids and `provider`.** This answer has no `provider` field. Get each catalog product id, and its `provider`, from Load a product for a sales order line: `attr_data[].id` and `attr_data[].provider`. The provider is also the id's prefix before the first `-`: `ssa` in `ssa-B00000001`. Send it as the line's `pricing.catalog.provider`. The public API has no catalog search by keyword; see Load a product for a sales order line for where to start.","operationId":"v1_public_real_time_data_fetcher_pricing","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"product":[{"id":"ssa-B00000001","type":"db_catalog"},{"id":"ssa-B00000002","type":"db_catalog"}]},"schema":{"additionalProperties":false,"properties":{"product":{"items":{"additionalProperties":false,"properties":{"id":{"description":"A supplier catalog product id: one size and color of a style, such as `ssa-B00000001`.","type":"string"},"type":{"const":"db_catalog","type":"string"}},"required":["type","id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}},"required":["product"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"id":"ssa-B00000001","local_pricing":{"data":{"case_price":{"dp":2,"value":400},"dozen_price":{"dp":2,"value":425},"lowest_price_type":"case_price","piece_price":{"dp":2,"value":450}},"errors":null,"success":true},"real_time_pricing":{"data":{"case_price":{"dp":2,"value":400},"dozen_price":{"dp":2,"value":425},"lowest_price_type":"your_price","piece_price":{"dp":2,"value":450},"sales_price":null,"sales_price_end_date":null,"your_price":{"dp":2,"value":380}},"errors":null,"success":true}},{"id":"ssa-B00000002","local_pricing":{"data":{"case_price":{"dp":2,"value":425},"dozen_price":{"dp":2,"value":450},"lowest_price_type":"case_price","piece_price":{"dp":2,"value":475}},"errors":null,"success":true},"real_time_pricing":{"data":{"case_price":{"dp":2,"value":425},"dozen_price":{"dp":2,"value":450},"lowest_price_type":"your_price","piece_price":{"dp":2,"value":475},"sales_price":null,"sales_price_end_date":null,"your_price":{"dp":2,"value":400}},"errors":null,"success":true}}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"id":{"type":"string"},"local_pricing":{"description":"Prices from YoPrint's copy of the supplier catalog. Present whenever the catalog product exists, even when the live call fails.","properties":{"data":{"additionalProperties":true,"properties":{"case_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]},"dozen_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]},"lowest_price_type":{"enum":["piece_price","dozen_price","case_price",null],"type":["string","null"]},"piece_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]}},"type":["object","null"]},"errors":{"description":"Null when the part succeeded. On a failure, the reasons (an empty list when none was recorded).","items":{"additionalProperties":true,"properties":{"code":{"enum":["account_missing","invalid_credentials","unsupported_format","image_not_found","image_load_failed","provider_unavailable","unknown"],"type":"string"},"message":{"description":"Readable reason, such as \"Real Time Pricing is not available for this team plan.\", or `internal error` when the reason is not shown.","type":"string"},"retryable":{"description":"True for `provider_unavailable`, `image_load_failed` and `unknown`.","type":"boolean"},"type":{"type":"string"}},"type":"object"},"type":["array","null"]},"success":{"type":"boolean"}},"required":["success","errors","data"],"type":"object"},"real_time_pricing":{"description":"Prices fetched live from the supplier with your team's connection.","properties":{"data":{"additionalProperties":true,"properties":{"case_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]},"dozen_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]},"lowest_price_type":{"description":"Which of `your_price` and `sales_price` is lower.","enum":["your_price","sales_price",null],"type":["string","null"]},"piece_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]},"sales_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]},"sales_price_end_date":{"type":["string","null"]},"your_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]}},"type":["object","null"]},"errors":{"description":"Null when the part succeeded. On a failure, the reasons (an empty list when none was recorded).","items":{"additionalProperties":true,"properties":{"code":{"enum":["account_missing","invalid_credentials","unsupported_format","image_not_found","image_load_failed","provider_unavailable","unknown"],"type":"string"},"message":{"description":"Readable reason, such as \"Real Time Pricing is not available for this team plan.\", or `internal error` when the reason is not shown.","type":"string"},"retryable":{"description":"True for `provider_unavailable`, `image_load_failed` and `unknown`.","type":"boolean"},"type":{"type":"string"}},"type":"object"},"type":["array","null"]},"success":{"type":"boolean"}},"required":["success","errors","data"],"type":"object"}},"required":["id","local_pricing","real_time_pricing"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get live supplier pricing for catalog products","tags":["Supplier catalog"],"x-yoprint-docs":{"errors":[{"fix":"Send 1 to 100 items with `type: db_catalog`.","status":422,"when":"`product` is missing, empty or has more than 100 items, or a `type` is not `db_catalog`. `error.code` is `validation_failed`."},{"fix":"Check each part's `success`. Read `errors[].code` and `message`; fix the plan or the connection under Apps, or retry later for `provider_unavailable`.","status":200,"when":"A product, or one part of its answer, failed: not found, plan, supplier connection, or the supplier's API. The request still answers 200 with `success: true`; that part has `success: false`, `data: null` and its reasons in `errors`."}],"group":"Products and catalog","notes":["Check `real_time_pricing.success` before you use it. `errors[].code` says why it failed; `retryable` is only a hint (plan and deprecation messages come back as `unknown` and `retryable: true`).","Prices are the supplier's cost to you, not your selling price."],"permission":"Any member of the team.","related":["v2_public_order_item_store","v1_public_real_time_data_fetcher_pricing_with_inventory","v1_public_hydrate_imported_product"],"rules":["Send 1 to 100 products per request. Every `type` is `db_catalog`.","The answer is always 200 once the body is valid: each product says `success` and `errors` for each part. A wrong id comes back as a failed part, not a 404.","Live data needs two things. The team's plan must include real-time vendor stock and pricing (otherwise \"Real Time Pricing is not available for this team plan.\" or \"Real Time Inventory is not available for this team plan.\"). And the supplier must be connected in Team settings, under Apps, with working credentials (otherwise `account_missing` or `invalid_credentials`).","Suppliers with live data: S&S Activewear (US and Canada), SanMar (US and Canada), Momentec / Augusta Sportswear (US and Canada) and AS Colour (US). AlphaBroder, Conde, TSF and Delta Apparel are no longer live (\"Catalog Product is deprecated.\"); their stored prices still come back in `local_pricing`.","`local_pricing` still answers when the live call fails, so you can fall back to it."],"side_effects":["Calls each supplier's API with your team's credentials; requests to different suppliers run in parallel. Answers are cached for 30 seconds, so a repeat within that time does not call the supplier again."]}}},"/v1/api/store/{team_slug}/real_time_data_fetcher/pricing_with_inventory":{"post":{"description":"Pricing and inventory in one request: each product has `local_pricing`, `real_time_pricing` and `real_time_inventory`, as in the two operations on their own. Works when the plan includes live pricing or live inventory, and then both parts are fetched live. With neither, both live parts fail with their plan messages (\"Real Time Pricing is not available for this team plan.\" and \"Real Time Inventory is not available for this team plan.\"); `local_pricing` still answers.","operationId":"v1_public_real_time_data_fetcher_pricing_with_inventory","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"product":[{"id":"ssa-B00000001","type":"db_catalog"},{"id":"ssa-B00000002","type":"db_catalog"}]},"schema":{"additionalProperties":false,"properties":{"product":{"items":{"additionalProperties":false,"properties":{"id":{"description":"A supplier catalog product id: one size and color of a style, such as `ssa-B00000001`.","type":"string"},"type":{"const":"db_catalog","type":"string"}},"required":["type","id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}},"required":["product"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"id":"ssa-B00000001","local_pricing":{"data":{"case_price":{"dp":2,"value":400},"dozen_price":{"dp":2,"value":425},"lowest_price_type":"case_price","piece_price":{"dp":2,"value":450}},"errors":null,"success":true},"real_time_inventory":{"data":{"total_count":1250,"warehouses":[{"count":1000,"id":"IL","metadata":[],"name":"Illinois"},{"count":250,"id":"NV","metadata":[],"name":"Nevada"}]},"errors":null,"success":true},"real_time_pricing":{"data":{"case_price":{"dp":2,"value":400},"dozen_price":{"dp":2,"value":425},"lowest_price_type":"your_price","piece_price":{"dp":2,"value":450},"sales_price":null,"sales_price_end_date":null,"your_price":{"dp":2,"value":380}},"errors":null,"success":true}},{"id":"ssa-B00000002","local_pricing":{"data":{"case_price":{"dp":2,"value":425},"dozen_price":{"dp":2,"value":450},"lowest_price_type":"case_price","piece_price":{"dp":2,"value":475}},"errors":null,"success":true},"real_time_inventory":{"data":{"total_count":600,"warehouses":[{"count":600,"id":"IL","metadata":[],"name":"Illinois"}]},"errors":null,"success":true},"real_time_pricing":{"data":{"case_price":{"dp":2,"value":425},"dozen_price":{"dp":2,"value":450},"lowest_price_type":"your_price","piece_price":{"dp":2,"value":475},"sales_price":null,"sales_price_end_date":null,"your_price":{"dp":2,"value":400}},"errors":null,"success":true}}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"id":{"type":"string"},"local_pricing":{"description":"Prices from YoPrint's copy of the supplier catalog. Present whenever the catalog product exists, even when the live call fails.","properties":{"data":{"additionalProperties":true,"properties":{"case_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]},"dozen_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]},"lowest_price_type":{"enum":["piece_price","dozen_price","case_price",null],"type":["string","null"]},"piece_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]}},"type":["object","null"]},"errors":{"description":"Null when the part succeeded. On a failure, the reasons (an empty list when none was recorded).","items":{"additionalProperties":true,"properties":{"code":{"enum":["account_missing","invalid_credentials","unsupported_format","image_not_found","image_load_failed","provider_unavailable","unknown"],"type":"string"},"message":{"description":"Readable reason, such as \"Real Time Pricing is not available for this team plan.\", or `internal error` when the reason is not shown.","type":"string"},"retryable":{"description":"True for `provider_unavailable`, `image_load_failed` and `unknown`.","type":"boolean"},"type":{"type":"string"}},"type":"object"},"type":["array","null"]},"success":{"type":"boolean"}},"required":["success","errors","data"],"type":"object"},"real_time_inventory":{"description":"Stock at the supplier, fetched live.","properties":{"data":{"additionalProperties":true,"properties":{"total_count":{"type":"integer"},"warehouses":{"items":{"additionalProperties":true,"properties":{"count":{"type":"integer"},"id":{"type":["string","integer","null"]},"metadata":{"additionalProperties":true,"description":"Supplier-specific details; an empty list `[]` when there are none.","type":["object","array"]},"name":{"type":["string","null"]}},"type":"object"},"type":"array"}},"type":["object","null"]},"errors":{"description":"Null when the part succeeded. On a failure, the reasons (an empty list when none was recorded).","items":{"additionalProperties":true,"properties":{"code":{"enum":["account_missing","invalid_credentials","unsupported_format","image_not_found","image_load_failed","provider_unavailable","unknown"],"type":"string"},"message":{"description":"Readable reason, such as \"Real Time Pricing is not available for this team plan.\", or `internal error` when the reason is not shown.","type":"string"},"retryable":{"description":"True for `provider_unavailable`, `image_load_failed` and `unknown`.","type":"boolean"},"type":{"type":"string"}},"type":"object"},"type":["array","null"]},"success":{"type":"boolean"}},"required":["success","errors","data"],"type":"object"},"real_time_pricing":{"description":"Prices fetched live from the supplier with your team's connection.","properties":{"data":{"additionalProperties":true,"properties":{"case_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]},"dozen_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]},"lowest_price_type":{"description":"Which of `your_price` and `sales_price` is lower.","enum":["your_price","sales_price",null],"type":["string","null"]},"piece_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]},"sales_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]},"sales_price_end_date":{"type":["string","null"]},"your_price":{"additionalProperties":false,"description":"A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 425, \"dp\": 2 }` is 4.25). Read `dp` every time: it can differ between fields and records. Null when the supplier gave none.","properties":{"dp":{"type":"integer"},"value":{"description":"The integer amount without decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1` and a value too large for a JSON number.","type":["integer","string"]}},"required":["value","dp"],"type":["object","null"]}},"type":["object","null"]},"errors":{"description":"Null when the part succeeded. On a failure, the reasons (an empty list when none was recorded).","items":{"additionalProperties":true,"properties":{"code":{"enum":["account_missing","invalid_credentials","unsupported_format","image_not_found","image_load_failed","provider_unavailable","unknown"],"type":"string"},"message":{"description":"Readable reason, such as \"Real Time Pricing is not available for this team plan.\", or `internal error` when the reason is not shown.","type":"string"},"retryable":{"description":"True for `provider_unavailable`, `image_load_failed` and `unknown`.","type":"boolean"},"type":{"type":"string"}},"type":"object"},"type":["array","null"]},"success":{"type":"boolean"}},"required":["success","errors","data"],"type":"object"}},"required":["id","local_pricing","real_time_pricing","real_time_inventory"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get live supplier pricing and inventory together","tags":["Supplier catalog"],"x-yoprint-docs":{"errors":[{"fix":"Send 1 to 100 items with `type: db_catalog`.","status":422,"when":"`product` is missing, empty or has more than 100 items, or a `type` is not `db_catalog`. `error.code` is `validation_failed`."},{"fix":"Check each part's `success`. Read `errors[].code` and `message`; fix the plan or the connection under Apps, or retry later for `provider_unavailable`.","status":200,"when":"A product, or one part of its answer, failed: not found, plan, supplier connection, or the supplier's API. The request still answers 200 with `success: true`; that part has `success: false`, `data: null` and its reasons in `errors`."}],"group":"Products and catalog","permission":"Any member of the team.","related":["v1_public_real_time_data_fetcher_pricing","v1_public_real_time_data_fetcher_inventory"],"rules":["Send 1 to 100 products per request. Every `type` is `db_catalog`.","The answer is always 200 once the body is valid: each product says `success` and `errors` for each part. A wrong id comes back as a failed part, not a 404.","Live data needs two things. The team's plan must include real-time vendor stock and pricing (otherwise \"Real Time Pricing is not available for this team plan.\" or \"Real Time Inventory is not available for this team plan.\"). And the supplier must be connected in Team settings, under Apps, with working credentials (otherwise `account_missing` or `invalid_credentials`).","Suppliers with live data: S&S Activewear (US and Canada), SanMar (US and Canada), Momentec / Augusta Sportswear (US and Canada) and AS Colour (US). AlphaBroder, Conde, TSF and Delta Apparel are no longer live (\"Catalog Product is deprecated.\"); their stored prices still come back in `local_pricing`."],"side_effects":["Calls each supplier's API with your team's credentials; requests to different suppliers run in parallel. Answers are cached for 30 seconds, so a repeat within that time does not call the supplier again."]}}},"/v1/api/store/{team_slug}/report/payment":{"post":{"description":"Returns every payment and refund recorded in the period on a sales order or quote that still exists, with its order, and every payment customers made in the Customer Portal. Use it to reconcile what you received.\n\nEach row is a payment record (the shape of an order's payment list) plus six order fields: `amount` is in thousandths, an older encoding (`339750` is 339.75; refunds are negative), `date` is ISO 8601, `order_id` is the order's hash id while `order_scoped_id` is its number, and `invoices` is a list of the order's invoice numbers. (The CSV export from the web app formats these differently.)\n\nA Customer Portal payment produces one row however many orders it paid. On all Customer Portal rows, `warehouse`, `order_scoped_id`, `order_name`, and `created_by` are null; `invoices` lists the invoices it was applied to, and `orders` lists the orders. Later provider changes (such as refunds) add an adjustment row signed like the change.\n\n| Kind of payment row | `subtype` / `action` | Has `order_id` | Fields that are `null` |\n| --- | --- | --- | --- |\n| Standard order payment | `subtype: PAYMENT` | Yes | None (order fields populated) |\n| Customer Portal (single order) | `subtype: PAYMENT`<br>`action: CUSTOMER_CHECKOUT` | Yes | `warehouse`, `order_scoped_id`, `order_name`, `created_by` |\n| Customer Portal (multi-order funding) | `subtype: CUSTOMER_CHECKOUT_FUNDING` | No (`null`) | `warehouse`, `order_scoped_id`, `order_name`, `created_by` |\n| Customer Portal funding adjustment | `subtype: CUSTOMER_CHECKOUT_FUNDING_ADJUSTMENT` | No (`null`) | `warehouse`, `order_scoped_id`, `order_name`, `created_by` |","operationId":"v1_public_report_payment","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-11-30T23:59:59Z","start_date":"2026-11-01T00:00:00Z"},"schema":{"properties":{"end_date":{"description":"End of the period (ISO 8601), inclusive: send `23:59:59` to include the whole last day. In UTC, like `start_date` (an offset is dropped, not applied).","format":"date-time","type":"string"},"start_date":{"description":"Start of the period (ISO 8601), inclusive, to the second: send the start of the day. Send it in UTC (`Z`): the date and time are compared with UTC as written and any offset is dropped, so `2026-10-01T00:00:00-05:00` means midnight UTC.","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"action":"ORDER_PAYMENT","amount":100000,"created_by":"Alex Rivera","customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","date":"2026-11-03T14:30:00+00:00","direction":"INCREASE","id":"hAwWd7vPrqjuHD","invoices":["1001"],"is_deletable":true,"is_editable":true,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","payment_gateway":null,"payment_method_id":"Kst6z3ULXLBrmN","reference_description":null,"reference_id":"CHK-1001","refundable_amount":100000,"related_transaction":null,"subtype":"PAYMENT","token":null,"type":"MANUAL","user_id":"4mdDkMg3dgQOa3","voided":false,"warehouse":null}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A payment or refund, with its order. Customer Portal payment rows also carry the source fields of an order's payment list (`customer_payment_checkout_id`, `funding_transaction_id`, `customer_payment_source_kind`, `currency_iso`, `customer_payment_sources`, `funding_payment_gateway`).","properties":{"action":{"description":"How it was made, for example a gateway name.","type":["string","null"]},"amount":{"description":"The amount. Refunds are negative. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":100000,"type":["integer","number","string","null"]},"created_by":{"description":"Name of who created the order.","example":"Alex Rivera","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"customer_payment_funding_id":{"description":"Customer Portal payment rows only: the customer payment.","type":["string","null"]},"date":{"description":"When it was recorded. ISO 8601 with offset.","example":"2026-11-03T14:30:00+00:00","format":"date-time","type":"string"},"direction":{"description":"`INCREASE` for a payment, `DECREASE` for a refund; a Customer Portal adjustment carries its own direction.","enum":["INCREASE","DECREASE"],"example":"INCREASE","type":"string"},"has_open_hold":{"description":"Card and Customer Portal payments: true while a dispute (or review) is open.","type":"boolean"},"id":{"description":"The payment record.","example":"hAwWd7vPrqjuHD","type":"string"},"invoices":{"description":"The order's invoice numbers (all of them, not only those this payment paid). On Customer Portal payment rows: the invoices the payment was applied to.","items":{"example":"1001","type":"string"},"type":"array"},"is_deletable":{"type":"boolean"},"is_editable":{"type":"boolean"},"is_external_cash_movement":{"description":"Customer Portal payment rows only: true for the customer's payment and its later changes.","type":"boolean"},"order_id":{"description":"The order's hash id (not its number: that is `order_scoped_id`).","example":"sFbALVSYD55eXe","type":["string","null"]},"order_name":{"description":"The order name.","example":"Team shirts","type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"orders":{"description":"Customer Portal payment rows only: the orders the payment was applied to (empty when they can't be found).","items":{"additionalProperties":true,"properties":{"invoice_applications":{"items":{"additionalProperties":true,"properties":{"invoice_id":{"description":"The invoice's unique key.","example":"ordinv_EXAMPLEuniqueKey","type":["string","null"]},"invoice_reference":{"description":"The invoice number.","example":"1001","type":["string","null"]},"original_applied_amount":{"description":"What was first applied to this invoice, in currency units. A decimal string, such as `\"100.0000\"`; parse it as a decimal.","example":"100.0000","type":["string","null"]}},"type":"object"},"type":"array"},"order_id":{"description":"The order's unique key (`ord_…`), not its hash id.","example":"ord_EXAMPLEuniqueKey","type":"string"},"order_reference":{"description":"The order number when it was paid.","example":"SO1001","type":["string","null"]},"original_applied_amount":{"description":"What the payment first applied to this order, in currency units (not thousandths). A decimal string, such as `\"100.0000\"`; parse it as a decimal.","example":"100.0000","type":["string","null"]}},"type":"object"},"type":"array"},"payment_freeze_reason":{"description":"`STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and direct Customer Portal payments: `chargeback_open` or `payment_under_review` while a dispute or review freezes it, otherwise null.","type":["string","null"]},"payment_gateway":{"description":"The gateway, for a gateway payment or refund; null otherwise.","type":["string","null"]},"payment_gateway_source":{"description":"Only on gateway payments and refunds: the card source the gateway reported (Square), or null.","type":["string","null"]},"payment_method_id":{"description":"The payment method.","example":"Kst6z3ULXLBrmN","type":["string","null"]},"payment_notices":{"description":"Card and Customer Portal payments: one notice per open dispute, as on an order's payment list.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"reference_description":{"type":["string","null"]},"reference_id":{"example":"CHK-1001","type":["string","null"]},"refundable_amount":{"description":"For a payment, what can still be refunded (0 when the method doesn't support refunds); 0 for a refund. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":100000,"type":["integer","number","string","null"]},"related_transaction":{"description":"For a refund, the `id` of the payment it refunds; null otherwise.","example":null,"type":["string","null"]},"subtype":{"description":"`CUSTOMER_CHECKOUT_FUNDING` is a Customer Portal payment that paid several orders; `CUSTOMER_CHECKOUT_FUNDING_ADJUSTMENT` a later change to one (its `action` names the kind, for example `CUSTOMER_CHECKOUT_REFUND`).","enum":["PAYMENT","REFUND","CUSTOMER_CHECKOUT_FUNDING","CUSTOMER_CHECKOUT_FUNDING_ADJUSTMENT"],"example":"PAYMENT","type":"string"},"token":{"description":"A gateway reference, on some gateway payments; null otherwise.","type":["string","null"]},"type":{"description":"`MANUAL` (recorded by hand) or `SYSTEM` (recorded by a payment gateway).","example":"MANUAL","type":"string"},"user_id":{"description":"Who recorded it.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"voided":{"type":"boolean"},"warehouse":{"description":"The order's warehouse label.","type":["string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Report payments and refunds","tags":["Reports"],"x-yoprint-docs":{"errors":[{"fix":"Ask the team owner to turn on View Reports for your permission group.","status":403,"when":"Your role lacks View Reports."},{"fix":"Send both as ISO 8601 date-times.","status":422,"when":"`start_date` or `end_date` is missing or not ISO 8601."}],"group":"Reports","notes":["There is no paging: the whole period comes back in one response. Ask for a month or less at a time."],"permission":"Needs the View Reports permission. Otherwise 403 with a bare `{ \"message\": \"Insufficient Permission\" }` (no `success` or `error` envelope).","related":["v1_public_report_tax","v2_public_sales_order_payment_index"],"rules":["A payment or refund is in the period when it was recorded (created) between `start_date` and `end_date`, inclusive.","Payments on a quote that became a sales order stay in the report. Payments on deleted orders are left out, except `CUSTOMER_CHECKOUT_FUNDING` rows and their adjustments, which are listed whatever happened to the orders.","Only gateway, manual and Customer Portal payments and refunds are listed (lost disputes count as refunds): payments from customer credit, refunds to customer credit, and the moves that apply a Customer Portal payment to its orders are left out. Rows come newest first."]}}},"/v1/api/store/{team_slug}/report/purchase_order":{"post":{"description":"Returns every purchase order issued in the period, in full. Amounts (`calc_subtotal`, `calc_tax`, `calc_total`) are decimal strings with 4 decimal places (`\"125.0000\"`).","operationId":"v1_public_report_purchase_order","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-11-30T23:59:59Z","start_date":"2026-11-01T00:00:00Z"},"schema":{"properties":{"end_date":{"description":"End of the period (ISO 8601), inclusive: send `23:59:59` to include the whole last day. In UTC, like `start_date` (an offset is dropped, not applied).","format":"date-time","type":"string"},"start_date":{"description":"Start of the period (ISO 8601), inclusive, to the second: send the start of the day. Send it in UTC (`Z`): the date and time are compared with UTC as written and any offset is dropped, so `2026-10-01T00:00:00-05:00` means midnight UTC.","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"calc_subtotal":"125.0000","calc_tax":"0.0000","calc_total":"125.0000","due_date":"2026-11-03T00:00:00+00:00","id":"7vsJXKGghZrXt6","issue_date":"2026-11-02T00:00:00+00:00","name":"Blanks for SO1001","scoped_id":"PO0042","status_id":"25xgwxzs4paoV2","tax_mode":null,"tax_rate":null,"vendor_id":"bWecZtQvmMt3Cw","warehouse_id":null}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A purchase order. Amounts are decimal strings.","properties":{"calc_subtotal":{"description":"Subtotal, 4 decimal places. A decimal string, such as `\"125.0000\"`; parse it as a decimal.","example":"125.0000","type":["string","null"]},"calc_tax":{"description":"Tax. A decimal string, such as `\"0.0000\"`; parse it as a decimal.","example":"0.0000","type":["string","null"]},"calc_total":{"description":"Total. A decimal string, such as `\"125.0000\"`; parse it as a decimal.","example":"125.0000","type":["string","null"]},"due_date":{"description":"Due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The purchase order.","example":"7vsJXKGghZrXt6","type":"string"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"name":{"type":["string","null"]},"pdf_url":{"description":"PDF link with its own access token."},"scoped_id":{"description":"The PO number.","example":"PO0042","type":["string","null"]},"status_id":{"description":"The PO status.","example":null,"type":["string","null"]},"tax_mode":{"type":["string","null"]},"tax_rate":{"description":"Tax rate. A decimal string, such as `\"24.00000000\"`; parse it as a decimal.","example":null,"type":["string","null"]},"vendor_id":{"description":"The vendor.","example":"bWecZtQvmMt3Cw","type":["string","null"]},"warehouse_id":{"description":"The warehouse.","example":null,"type":["string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Report purchase orders by issue date","tags":["Reports"],"x-yoprint-docs":{"errors":[{"fix":"Ask the team owner to turn on View Reports for your permission group.","status":403,"when":"Your role lacks View Reports."},{"fix":"Send both as ISO 8601 date-times.","status":422,"when":"`start_date` or `end_date` is missing or not ISO 8601."}],"group":"Reports","notes":["There is no paging: the whole period comes back in one response. Ask for a month or less at a time."],"permission":"Needs the View Reports permission. Otherwise 403 with a bare `{ \"message\": \"Insufficient Permission\" }` (no `success` or `error` envelope).","related":["v1_public_report_sales_order"],"rules":["A purchase order is in the period when its issue date is between `start_date` and `end_date`, inclusive."]}}},"/v1/api/store/{team_slug}/report/quote":{"post":{"description":"Returns every quote issued in the period, in full (v1 order shape). Drafts and unsaved quotes are left out. Amounts are in thousandths, an older encoding: `339750` is 339.75. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","operationId":"v1_public_report_quote","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-11-30T23:59:59Z","start_date":"2026-11-01T00:00:00Z"},"schema":{"properties":{"end_date":{"description":"End of the period (ISO 8601), inclusive: send `23:59:59` to include the whole last day. In UTC, like `start_date` (an offset is dropped, not applied).","format":"date-time","type":"string"},"start_date":{"description":"Start of the period (ISO 8601), inclusive, to the second: send the start of the day. Send it in UTC (`Z`): the date and time are compared with UTC as written and any offset is dropped, so `2026-10-01T00:00:00-05:00` means midnight UTC.","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"approval_status":null,"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"calc_deposit_total":0,"calc_discount":0,"calc_subtotal":0,"calc_tax":0,"calc_total":0,"created_at":"2026-11-02T15:00:00+00:00","created_by":"4mdDkMg3dgQOa3","cust_due_date":"2026-11-10T00:00:00+00:00","customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"customer_id":"ifAHmADekGZ6id","customer_po_number":null,"customer_portal_order_link":"https://example.com/portal/order","customer_portal_payment_link":"https://example.com/portal/pay","deposit_due":null,"deposit_required":false,"deposit_total":0,"due_date":"2026-11-06T17:00:00+00:00","full_amount_due":"2026-11-20T00:00:00+00:00","id":"mJ8Wrr98wnbAnj","is_quote":true,"is_rush":false,"issue_date":"2026-11-02T00:00:00+00:00","name":"Staff polos","object_type":"quote","paid_amount":0,"payment_term_id":null,"scoped_id":"QT1001","ship_due_date":"2026-11-08T00:00:00+00:00","start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#9e9e9e","customer_label":"Pending","id":"35gWu7rwnoRn60","label":"Sent","position":1,"role":"quote","trashed":false,"type":"start"},"status_id":"35gWu7rwnoRn60","tags":[],"unique_key":"ord_EXAMPLEuniqueKe4","warehouse_id":null}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A sales order or quote in the v1 order shape, with its `status`, `assigned_users`, `tags` and `customer`. Amounts are in thousandths.","properties":{"approval_status":{"description":"`requested`, `need-changes`, `approved`, or null.","type":["string","null"]},"assigned_users":{"description":"People on the order.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"calc_deposit_total":{"description":"Deposit amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_discount":{"description":"Invoiced discount; 0 until invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_subtotal":{"description":"Invoiced line and shipping subtotal; 0 until the order is invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_tax":{"description":"Invoiced tax; 0 until invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_total":{"description":"Invoiced total; 0 until the order is invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"created_by":{"description":"Who created it.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Customer due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer":{"oneOf":[{"additionalProperties":true,"description":"The customer, as in Get a customer.","properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":"string"},"name":{"example":"Northwind Apparel","type":["string","null"]}},"type":"object"},{"type":"null"}]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_po_number":{"type":["string","null"]},"customer_portal_order_link":{"description":"Customer portal link. It carries the customer's portal access: don't publish it.","type":["string","null"]},"customer_portal_payment_link":{"description":"Customer portal payment page link, with the same access.","type":["string","null"]},"deposit_due":{"description":"Deposit due. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"deposit_required":{"type":"boolean"},"deposit_total":{"description":"The deposit **percentage** ×1000: `50000` is 50%. Not an amount.","example":50000,"type":["integer","number","string","null"]},"due_date":{"description":"Production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"full_amount_due":{"description":"Full amount due. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"is_quote":{"type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"name":{"type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"paid_amount":{"description":"Paid so far. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"payment_term_id":{"description":"Payment term.","example":null,"type":["string","null"]},"scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"ship_due_date":{"description":"Ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]},"tags":{"description":"The order's tags.","items":{"additionalProperties":true,"properties":{"color_hex":{"example":"#e91e63","type":["string","null"]},"id":{"description":"The tag.","example":"DjLvcpJY6LweSp","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"unique_key":{"example":"ord_EXAMPLEuniqueKey","type":["string","null"]},"warehouse_id":{"description":"Warehouse.","example":null,"type":["string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Report quotes by issue date","tags":["Reports"],"x-yoprint-docs":{"errors":[{"fix":"Ask the team owner to turn on View Reports for your permission group.","status":403,"when":"Your role lacks View Reports."},{"fix":"Send both as ISO 8601 date-times.","status":422,"when":"`start_date` or `end_date` is missing or not ISO 8601."}],"group":"Reports","notes":["There is no paging: the whole period comes back in one response. Ask for a month or less at a time."],"permission":"Needs the View Reports permission. Otherwise 403 with a bare `{ \"message\": \"Insufficient Permission\" }` (no `success` or `error` envelope).","related":["v1_public_report_sales_order"],"rules":["A quote is in the period when its issue date is between `start_date` and `end_date`, inclusive."]}}},"/v1/api/store/{team_slug}/report/sales_order":{"post":{"description":"Returns every sales order issued in the period, in full (v1 order shape), for your own reporting. Drafts and unsaved orders are left out.\n\nAmounts are in thousandths, an older encoding (`339750` is 339.75). An order's `calc_*` fields (`calc_subtotal`, `calc_tax`, `calc_discount`, `calc_total`) measure only what has been invoiced so far, and remain 0 until an invoice is created for the order. `deposit_total` is the deposit percentage ×1000, not an amount. See [Money and quantities](/concepts/money-and-quantities/).","operationId":"v1_public_report_sales_order","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-11-30T23:59:59Z","start_date":"2026-11-01T00:00:00Z"},"schema":{"properties":{"end_date":{"description":"End of the period (ISO 8601), inclusive: send `23:59:59` to include the whole last day. In UTC, like `start_date` (an offset is dropped, not applied).","format":"date-time","type":"string"},"start_date":{"description":"Start of the period (ISO 8601), inclusive, to the second: send the start of the day. Send it in UTC (`Z`): the date and time are compared with UTC as written and any offset is dropped, so `2026-10-01T00:00:00-05:00` means midnight UTC.","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"approval_status":null,"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"calc_deposit_total":169880,"calc_discount":0,"calc_subtotal":315000,"calc_tax":24750,"calc_total":339750,"created_at":"2026-11-02T15:00:00+00:00","created_by":"4mdDkMg3dgQOa3","cust_due_date":"2026-11-10T00:00:00+00:00","customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"customer_id":"ifAHmADekGZ6id","customer_po_number":null,"customer_portal_order_link":"https://example.com/portal/order","customer_portal_payment_link":"https://example.com/portal/pay","deposit_due":"2026-11-05T00:00:00+00:00","deposit_required":true,"deposit_total":50000,"due_date":"2026-11-06T17:00:00+00:00","full_amount_due":"2026-11-20T00:00:00+00:00","id":"sFbALVSYD55eXe","is_quote":false,"is_rush":false,"issue_date":"2026-11-02T00:00:00+00:00","name":"Team shirts","object_type":"sales_order","paid_amount":100000,"payment_term_id":null,"scoped_id":"SO1001","ship_due_date":"2026-11-08T00:00:00+00:00","start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"wgbOT87gGZvhgy","label":"In production","position":2,"role":"order","trashed":false,"type":"in_progress"},"status_id":"wgbOT87gGZvhgy","tags":[],"unique_key":"ord_EXAMPLEuniqueKey","warehouse_id":null}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A sales order or quote in the v1 order shape, with its `status`, `assigned_users`, `tags` and `customer`. Amounts are in thousandths.","properties":{"approval_status":{"description":"`requested`, `need-changes`, `approved`, or null.","type":["string","null"]},"assigned_users":{"description":"People on the order.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"calc_deposit_total":{"description":"Deposit amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_discount":{"description":"Invoiced discount; 0 until invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_subtotal":{"description":"Invoiced line and shipping subtotal; 0 until the order is invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_tax":{"description":"Invoiced tax; 0 until invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_total":{"description":"Invoiced total; 0 until the order is invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"created_by":{"description":"Who created it.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Customer due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer":{"oneOf":[{"additionalProperties":true,"description":"The customer, as in Get a customer.","properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":"string"},"name":{"example":"Northwind Apparel","type":["string","null"]}},"type":"object"},{"type":"null"}]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_po_number":{"type":["string","null"]},"customer_portal_order_link":{"description":"Customer portal link. It carries the customer's portal access: don't publish it.","type":["string","null"]},"customer_portal_payment_link":{"description":"Customer portal payment page link, with the same access.","type":["string","null"]},"deposit_due":{"description":"Deposit due. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"deposit_required":{"type":"boolean"},"deposit_total":{"description":"The deposit **percentage** ×1000: `50000` is 50%. Not an amount.","example":50000,"type":["integer","number","string","null"]},"due_date":{"description":"Production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"full_amount_due":{"description":"Full amount due. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"is_quote":{"type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"name":{"type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"paid_amount":{"description":"Paid so far. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"payment_term_id":{"description":"Payment term.","example":null,"type":["string","null"]},"scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"ship_due_date":{"description":"Ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]},"tags":{"description":"The order's tags.","items":{"additionalProperties":true,"properties":{"color_hex":{"example":"#e91e63","type":["string","null"]},"id":{"description":"The tag.","example":"DjLvcpJY6LweSp","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"unique_key":{"example":"ord_EXAMPLEuniqueKey","type":["string","null"]},"warehouse_id":{"description":"Warehouse.","example":null,"type":["string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Report sales orders by issue date","tags":["Reports"],"x-yoprint-docs":{"errors":[{"fix":"Ask the team owner to turn on View Reports for your permission group.","status":403,"when":"Your role lacks View Reports."},{"fix":"Send both as ISO 8601 date-times.","status":422,"when":"`start_date` or `end_date` is missing or not ISO 8601."}],"group":"Reports","notes":["There is no paging: the whole period comes back in one response. Ask for a month or less at a time."],"permission":"Needs the View Reports permission. Otherwise 403 with a bare `{ \"message\": \"Insufficient Permission\" }` (no `success` or `error` envelope).","related":["v1_public_report_quote","v1_public_report_payment","v1_public_report_tax"],"rules":["An order is in the period when its issue date is between `start_date` and `end_date`, inclusive."]}}},"/v1/api/store/{team_slug}/report/tax":{"post":{"description":"Returns the invoices of the sales orders that were paid in full in the period, with their tax, for cash-basis tax reporting.\n\nAn order counts in the period of its last payment or refund: it is included when it is fully paid now and its latest payment or refund was recorded in the period. A later transaction of any kind on a later UTC day moves it out of this period (to that later period when it is a payment or refund, to none otherwise).\n\nEach row is formatted like the tax CSV export: amounts are decimal strings with 2 decimal places (`\"24.75\"`), dates are `YYYY-MM-DD` in your team's time zone, yes/no fields are `\"TRUE\"` or `\"FALSE\"`, and `order_id` and `invoice_id` are document **numbers**, not ids.","operationId":"v1_public_report_tax","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-11-30T23:59:59Z","start_date":"2026-11-01T00:00:00Z"},"schema":{"properties":{"end_date":{"description":"End of the period (ISO 8601), inclusive: send `23:59:59` to include the whole last day. In UTC, like `start_date` (an offset is dropped, not applied).","format":"date-time","type":"string"},"start_date":{"description":"Start of the period (ISO 8601), inclusive, to the second: send the start of the day. Send it in UTC (`Z`): the date and time are compared with UTC as written and any offset is dropped, so `2026-10-01T00:00:00-05:00` means midnight UTC.","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"balance_due":"0.00","customer_contact_name":"Alex Rivera","customer_email":"alex@example.com","customer_name":"Northwind Apparel","customer_tax_exempt":"FALSE","delivery":"15.00","discount":"0.00","invoice_id":"998","issue_date":"2026-10-28","jobs":"JOB-2410 Staff hoodies","last_payment_date":"2026-11-12","order_creator":"Alex Rivera","order_customer_in_hand_date":"2026-11-06","order_id":"SO0998","order_issue_date":"2026-10-28","order_name":"Staff hoodies","order_status":"Completed","order_warehouse":null,"paid":"TRUE","paid_amount":"339.75","shipping_address1":"100 Example Street","subtotal":"315.00","tax":"24.75","tax_percentage":"8.25","total":"339.75"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"An invoice row, as in the tax CSV export. Amounts are decimal strings.","properties":{"balance_due":{"description":"Balance. A decimal string, such as `\"0.00\"`; parse it as a decimal.","example":"0.00","type":["string","null"]},"customer_contact_name":{"example":"Alex Rivera","type":["string","null"]},"customer_email":{"example":"alex@example.com","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"customer_tax_exempt":{"enum":["TRUE","FALSE",null],"example":"FALSE","type":["string","null"]},"delivery":{"description":"Shipping. A decimal string, such as `\"15.00\"`; parse it as a decimal.","example":"15.00","type":["string","null"]},"discount":{"description":"Discount. A decimal string, such as `\"0.00\"`; parse it as a decimal.","example":"0.00","type":["string","null"]},"invoice_id":{"description":"The invoice **number**.","example":"1001","type":["string","null"]},"issue_date":{"description":"The invoice issue date, `YYYY-MM-DD`.","example":"2026-10-01","type":["string","null"]},"jobs":{"description":"One line per job, `JOB-<number> <name>`, joined with `\\r\\n`; null when no line has a job.","example":"JOB-2419 Front print","type":["string","null"]},"last_payment_date":{"description":"The date of the order's latest payment (money in), `YYYY-MM-DD` in the team's time zone; null when there is none.","type":["string","null"]},"order_creator":{"type":["string","null"]},"order_customer_in_hand_date":{"description":"`YYYY-MM-DD`, or empty.","type":["string","null"]},"order_id":{"description":"The order **number**.","example":"SO1001","type":["string","null"]},"order_issue_date":{"description":"`YYYY-MM-DD` in the team's time zone.","example":"2026-10-01","type":["string","null"]},"order_name":{"type":["string","null"]},"order_status":{"description":"The order status name.","type":["string","null"]},"order_warehouse":{"type":["string","null"]},"paid":{"enum":["TRUE","FALSE"],"example":"TRUE","type":"string"},"paid_amount":{"description":"Paid. A decimal string, such as `\"339.75\"`; parse it as a decimal.","example":"339.75","type":["string","null"]},"shipping_address1":{"description":"Ship To fields: `shipping_label`, `shipping_address1`, `shipping_address2`, `shipping_city`, `shipping_state`, `shipping_state_code`, `shipping_country`, `shipping_country_code`, `shipping_postcode`.","type":["string","null"]},"subtotal":{"description":"Subtotal, 2 decimal places. A decimal string, such as `\"300.00\"`; parse it as a decimal.","example":"300.00","type":["string","null"]},"tax":{"description":"Tax. A decimal string, such as `\"24.75\"`; parse it as a decimal.","example":"24.75","type":["string","null"]},"tax_percentage":{"description":"The tax rate in percent, as text (for example `8.25`), or null when it can't be stated.","example":"8.25","type":["string","null"]},"total":{"description":"Total. A decimal string, such as `\"339.75\"`; parse it as a decimal.","example":"339.75","type":["string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Report invoices of orders paid in full","tags":["Reports"],"x-yoprint-docs":{"errors":[{"fix":"Ask the team owner to turn on View Reports for your permission group.","status":403,"when":"Your role lacks View Reports."},{"fix":"Send both as ISO 8601 date-times.","status":422,"when":"`start_date` or `end_date` is missing or not ISO 8601."}],"group":"Reports","notes":["There is no paging: the whole period comes back in one response. Ask for a month or less at a time.","An order that becomes unpaid again (for example after a refund) drops out of earlier periods, so a re-run report can differ."],"permission":"Needs the View Reports permission. Otherwise 403 with a bare `{ \"message\": \"Insufficient Permission\" }` (no `success` or `error` envelope).","related":["v1_public_report_payment","v1_public_invoice_index"],"rules":["Only sales orders whose `paid_amount` is at least their invoiced total are included, and only their current (v2) invoices are listed.","An order counts in the period of a payment or refund made on the UTC calendar day of its last transaction of any kind: a later transaction on a later day removes it from this period. If that later transaction isn't a payment or refund (for example a payment from customer credit, or a failed card refund given back), the order appears in no period.","Payments from customer credit never put an order into a period: only gateway, manual and Customer Portal payments and refunds do, including the share of a Customer Portal payment that paid several orders."]}}},"/v1/api/store/{team_slug}/sales_order/export":{"post":{"description":"Downloads a CSV file of the published sales orders whose issue date is in a range. Quotes and drafts are left out; use Export quotes for quotes.\n\nSend `start_date` and `end_date` as ISO 8601 date-times, for example `2026-11-01T00:00:00Z` and `2026-11-30T23:59:59Z`. They are compared as given, so a date alone means midnight UTC and an end date of `2026-11-30` leaves out most of that day.\n\nThe file has one row per order with these columns: order_id (the number), issue_date, creator, customer_po_number, customer_email, customer_contact_name, customer_name, customer_tax_exempt, customer_brand_profile, pricing_group, payment_term, pricing_strategy, warehouse, production_start_date, production_due_date, shipment_due_date, customer_in_hand_date, client_note, prod_note, jobs, status, subtotal, discount, tax, total, balance_due, paid, last_payment_date and tags. Dates are `YYYY-MM-DD` in the team's time zone. Amounts are decimal strings with 2 decimal places: `subtotal` is the value of the order's lines, while `discount`, `tax`, `total` and `balance_due` count only what has been invoiced (`0.00` until then). `paid` and `customer_tax_exempt` are `TRUE` or `FALSE`.\n\nWith `list_only: true` the same rows come back as JSON in `data`, each with the order's `name` as well; an empty range then answers `data: []` instead of 422. The answer is built at once; for large ranges, use the data export instead.","operationId":"v1_public_sales_order_export","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-11-30T23:59:59Z","list_only":false,"start_date":"2026-11-01T00:00:00Z"},"schema":{"properties":{"end_date":{"description":"End of the issue date range (ISO 8601).","format":"date-time","type":"string"},"list_only":{"description":"true to get the rows as JSON instead of a CSV file.","type":"boolean"},"start_date":{"description":"Start of the issue date range (ISO 8601).","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"balance_due":"85.00","customer_name":"Northwind Apparel","customer_tax_exempt":"FALSE","discount":"0.00","issue_date":"2026-11-03","name":"Spring team shirts","order_id":"SO1001","paid":"FALSE","status":"In production","subtotal":"125.00","tax":"10.00","total":"135.00"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"One order as JSON: the CSV file's columns, plus `name`.","properties":{"balance_due":{"description":"Invoiced total minus paid. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"client_note":{"type":["string","null"]},"creator":{"description":"Created By's name, or an empty string.","type":"string"},"customer_brand_profile":{"type":["string","null"]},"customer_contact_name":{"type":["string","null"]},"customer_email":{"type":["string","null"]},"customer_in_hand_date":{"description":"`YYYY-MM-DD`, or an empty string.","type":"string"},"customer_name":{"type":["string","null"]},"customer_po_number":{"type":["string","null"]},"customer_tax_exempt":{"enum":["TRUE","FALSE"],"type":"string"},"discount":{"description":"Invoiced discount; `\"0.00\"` until invoiced. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"issue_date":{"description":"`YYYY-MM-DD` in the team's time zone.","type":"string"},"jobs":{"description":"The jobs, one per line.","type":["string","null"]},"last_payment_date":{"type":["string","null"]},"name":{"description":"The order's name. JSON rows only: the CSV file has no `name` column.","type":["string","null"]},"order_id":{"description":"The order number (not the id).","example":"SO1001","type":"string"},"paid":{"description":"`TRUE` when the invoiced total is paid.","enum":["TRUE","FALSE"],"type":"string"},"payment_term":{"type":["string","null"]},"pricing_group":{"type":["string","null"]},"pricing_strategy":{"type":["string","null"]},"prod_note":{"type":["string","null"]},"production_due_date":{"description":"`YYYY-MM-DD`, or an empty string.","type":"string"},"production_start_date":{"description":"`YYYY-MM-DD`, or an empty string.","type":"string"},"shipment_due_date":{"description":"`YYYY-MM-DD`, or an empty string.","type":"string"},"status":{"description":"The status label.","type":["string","null"]},"subtotal":{"description":"The value of the order's lines. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"tags":{"description":"Tag names, comma-separated.","type":["string","null"]},"tax":{"description":"Invoiced tax; `\"0.00\"` until invoiced. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"total":{"description":"Invoiced total; `\"0.00\"` until invoiced. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"warehouse":{"type":["string","null"]}},"type":"object"},"type":"array"},"status":{"type":"integer"},"success":{"type":"boolean"}},"required":["success","status","data"],"type":"object"}},"text/csv":{"schema":{"description":"The sales orders, one per row.","format":"binary","type":"string"}}},"description":"The CSV file, or with `list_only: true` the rows as JSON."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Export sales orders as CSV","tags":["Sales orders"],"x-yoprint-docs":{"errors":[{"fix":"Widen the range.","status":422,"when":"No sales order is in the range, for the file: `sales_order_export_error` \"Sales Order not found\". (With `list_only: true` the answer is `data: []`.)"},{"fix":"Send both dates as ISO 8601.","status":422,"when":"A date is missing or not ISO 8601."},{"fix":"Ask the team owner for report permission.","status":403,"when":"The role lacks `view_report`. This error has no envelope: the body is `{\"message\": \"Insufficient Permission\"}`."}],"group":"Sales","notes":["The CSV answer is a file (`text/csv`), not JSON."],"permission":"Needs the `view_report` permission.","related":["v1_public_v1_quote_export","v1_public_data_export_export_sales_order","v2_public_sales_order_filter"],"rules":["`start_date` and `end_date` are required.","Finds published sales orders only (not quotes, drafts or deleted orders)."]}}},"/v1/api/store/{team_slug}/sales_order/filter":{"post":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_sales_order_filter` (POST /v2/api/store/{team_slug}/v2/sales_order/filter) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nRetired: this v1 operation no longer works. Every call fails with HTTP 500 and the body `{\"message\": \"Server Error\"}`. Use List sales orders (`v2.public.sales_order.filter`) to list sales orders.","operationId":"v1_public_v1_sales_order_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"description":"Never sent: this route always fails with HTTP 500."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Filter sales orders (retired v1)","tags":["Sales orders"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Use List sales orders.","status":500,"when":"Always: `{\"message\": \"Server Error\"}`."}],"group":"Sales","prefer":"v2_public_sales_order_filter","related":["v2_public_sales_order_filter"],"status":"legacy"}}},"/v1/api/store/{team_slug}/sales_order/invoices/export":{"post":{"description":"Downloads a CSV file of invoices.\n\nInvoices are picked by their **sales order's** issue date, not the invoice date, and only for published, non-deleted sales orders.\n\nSend `start_date` and `end_date` as ISO 8601 date-times, for example `2026-11-01T00:00:00Z` and `2026-11-30T23:59:59Z`. They are compared as given, so a date alone means midnight UTC and an end date of `2026-11-30` leaves out most of that day.","operationId":"v1_public_sales_order_invoices_export","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-11-30T23:59:59Z","start_date":"2026-11-01T00:00:00Z"},"schema":{"properties":{"end_date":{"description":"End of the issue date range (ISO 8601).","format":"date-time","type":"string"},"start_date":{"description":"Start of the issue date range (ISO 8601).","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"text/csv":{"schema":{"description":"The invoices, one per row.","format":"binary","type":"string"}}},"description":"The CSV file."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Export invoices as CSV","tags":["Invoices"],"x-yoprint-docs":{"errors":[{"fix":"Widen the range.","status":422,"when":"No invoice is in the range: `invoice_export_error` \"Invoices not found\"."},{"fix":"Ask the team owner for report permission.","status":403,"when":"The role lacks `view_report`. This error has no envelope: the body is `{\"message\": \"Insufficient Permission\"}`."}],"group":"Invoices and payments","notes":["The answer is a file (`text/csv`), not JSON."],"permission":"Needs the `view_report` permission.","related":["v1_public_sales_order_invoices_export_list","v1_public_data_export_export_invoice"]}}},"/v1/api/store/{team_slug}/sales_order/invoices/export_all_sales_order_invoice_item":{"post":{"description":"Returns the invoice lines that come from order lines, one row per line, as JSON in `data`, for a date range. Tax, shipping, discount and fee lines of an invoice are not listed, and the rows' `tax`, `discount` and `tax_percent` are always null. `order_id` and `invoice_id` here are hash ids; the numbers are `order_scoped_id` and `invoice_scoped_id`. Amounts are thousandths as strings, an older encoding: `\"12500\"` is 12.50. See [Money and quantities](/concepts/money-and-quantities/).\n\nInvoices are picked by their **sales order's** issue date, not the invoice date, and only for published, non-deleted sales orders.\n\nHere the range covers whole days: `start_date` from midnight, `end_date` to the end of its day (UTC). Send ISO 8601 dates, such as `2026-11-01` and `2026-11-30`.","operationId":"v1_public_sales_order_invoices_export_all_invoice_items","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-11-30","start_date":"2026-11-01"},"schema":{"properties":{"end_date":{"description":"End of the issue date range (ISO 8601).","format":"date-time","type":"string"},"start_date":{"description":"Start of the issue date range (ISO 8601).","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"discount":null,"has_empty_product_cost":false,"invoice_id":"QRbvVd2ZKcvSTB","invoice_scoped_id":"1001","job_name":"Front logo","order_creator":"Alex Rivera","order_creator_id":"PydH0WtBhSeiNU","order_date":"2026-11-03","order_id":"V4keXwwxMQyXw7","order_name":"Spring team shirts","order_scoped_id":"SO1001","order_status":"In production","order_warehouse":"Main","product_cost":"6000","product_name":"Team shirt","product_total":"12500","product_type":"user_simple","quantity":10,"service_total":"0","services":"Screen print","subtotal":"125000","tax":null,"tax_percent":null,"total":"125000"}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"One row per invoice line that comes from an order line; `[]` when none is in the range.","items":{"additionalProperties":true,"description":"One invoice line that comes from an order line.","properties":{"discount":{"description":"Always null.","type":"null"},"has_empty_product_cost":{"type":"boolean"},"invoice_id":{"description":"The invoice's `id` (a hash id).","example":"QRbvVd2ZKcvSTB","type":"string"},"invoice_scoped_id":{"description":"The invoice number.","example":"1001","type":"string"},"job_name":{"description":"The line's job name, or an empty string.","type":"string"},"order_creator":{"description":"Created By's name, or an empty string.","type":"string"},"order_creator_id":{"description":"Created By's user id, or an empty string.","type":"string"},"order_date":{"description":"The order's issue date, `YYYY-MM-DD` in the team's time zone.","type":"string"},"order_id":{"description":"The order's `id` (a hash id).","example":"V4keXwwxMQyXw7","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"order_status":{"description":"The order's status label.","type":["string","null"]},"order_warehouse":{"description":"The order's warehouse label.","type":"string"},"product_cost":{"description":"Cost of one unit. Thousandths as a string, an older encoding: `\"12500\"` is 12.50. See [Money and quantities](/concepts/money-and-quantities/).","type":"string"},"product_name":{"type":["string","null"]},"product_total":{"description":"Product price of one unit. Thousandths as a string, an older encoding: `\"12500\"` is 12.50. See [Money and quantities](/concepts/money-and-quantities/).","type":"string"},"product_type":{"description":"The line's kind.","type":"string"},"quantity":{"description":"The quantity: a whole number, or a decimal string.","type":["integer","string"]},"service_total":{"description":"Decoration price of one unit. Thousandths as a string, an older encoding: `\"12500\"` is 12.50. See [Money and quantities](/concepts/money-and-quantities/).","type":"string"},"services":{"description":"The job's decoration services, comma-separated.","type":"string"},"status":{"additionalProperties":true,"description":"The order's status record, as stored (not the status answer shape).","type":["object","null"]},"subtotal":{"description":"The invoice line's subtotal. Thousandths as a string, an older encoding: `\"12500\"` is 12.50. See [Money and quantities](/concepts/money-and-quantities/).","type":"string"},"tax":{"description":"Always null: this export has no tax per line.","type":"null"},"tax_percent":{"description":"Always null.","type":"null"},"total":{"description":"The same as `subtotal`. Thousandths as a string, an older encoding: `\"12500\"` is 12.50. See [Money and quantities](/concepts/money-and-quantities/).","type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List invoice lines for export","tags":["Invoices"],"x-yoprint-docs":{"errors":[{"fix":"Send both dates.","status":422,"when":"A date is missing or not ISO 8601."},{"fix":"Ask the team owner for report permission.","status":403,"when":"The role lacks `view_report`. This error has no envelope: the body is `{\"message\": \"Insufficient Permission\"}`."}],"group":"Invoices and payments","permission":"Needs the `view_report` permission.","related":["v1_public_sales_order_invoices_export_list","v1_public_data_export_export_invoice_item"]}}},"/v1/api/store/{team_slug}/sales_order/invoices/export_list":{"post":{"description":"Returns invoice rows as JSON in `data`, one per invoice, for a date range: the invoice CSV export's columns plus a few more. `order_id` and `invoice_id` are the numbers people see, not ids. Amounts are decimal strings with 2 decimal places.\n\nInvoices are picked by their **sales order's** issue date, not the invoice date, and only for published, non-deleted sales orders.\n\nSend `start_date` and `end_date` as ISO 8601 date-times, for example `2026-11-01T00:00:00Z` and `2026-11-30T23:59:59Z`. They are compared as given, so a date alone means midnight UTC and an end date of `2026-11-30` leaves out most of that day.","operationId":"v1_public_sales_order_invoices_export_list","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-11-30T23:59:59Z","start_date":"2026-11-01T00:00:00Z"},"schema":{"properties":{"end_date":{"description":"End of the issue date range (ISO 8601).","format":"date-time","type":"string"},"start_date":{"description":"Start of the issue date range (ISO 8601).","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"balance_due":"85.00","customer_contact_name":"Alex Rivera","customer_email":"alex@example.com","customer_name":"Northwind Apparel","customer_tax_exempt":"FALSE","delivery":"0.00","discount":"0.00","invoice_id":"1001","issue_date":"2026-11-03","jobs":"JOB-1001 Front logo","last_payment_date":"2026-11-03","order_creator":"Alex Rivera","order_customer_in_hand_date":"","order_id":"SO1001","order_issue_date":"2026-11-03","order_name":"Spring team shirts","order_status":"In production","order_warehouse":"Main","paid":"FALSE","paid_amount":"50.00","shipping_address1":"100 Example Street","subtotal":"125.00","tax":"10.00","tax_percentage":"8","total":"135.00"}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"One row per invoice; `[]` when none is in the range.","items":{"additionalProperties":true,"description":"One invoice: the invoice CSV export's columns, plus `order_name`, `order_status`, `order_issue_date`, `issue_date`, `subtotal`, `discount` and `delivery`.","properties":{"balance_due":{"description":"Total minus paid. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"customer_contact_name":{"type":["string","null"]},"customer_email":{"type":["string","null"]},"customer_name":{"type":["string","null"]},"customer_tax_exempt":{"enum":["TRUE","FALSE",null],"type":["string","null"]},"delivery":{"description":"Shipping. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"discount":{"description":"Discount. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"invoice_id":{"description":"The invoice number (not the id).","example":"1001","type":"string"},"issue_date":{"description":"The invoice date, `YYYY-MM-DD`, or null.","type":["string","null"]},"jobs":{"description":"The jobs, one per line.","type":["string","null"]},"last_payment_date":{"description":"The order's last payment, `YYYY-MM-DD`, or null.","type":["string","null"]},"order_creator":{"description":"Created By's name, or an empty string.","type":"string"},"order_customer_in_hand_date":{"description":"`YYYY-MM-DD`, or an empty string.","type":"string"},"order_id":{"description":"The order number (not the id).","example":"SO1001","type":"string"},"order_issue_date":{"description":"`YYYY-MM-DD` in the team's time zone.","type":"string"},"order_name":{"type":["string","null"]},"order_status":{"description":"The order's status label.","type":["string","null"]},"order_warehouse":{"type":["string","null"]},"paid":{"enum":["TRUE","FALSE"],"type":"string"},"paid_amount":{"description":"Paid on this invoice. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"shipping_address1":{"description":"The shipping address, in `shipping_label`, `shipping_address1`, `shipping_address2`, `shipping_city`, `shipping_state`, `shipping_state_code`, `shipping_country`, `shipping_country_code` and `shipping_postcode`.","type":["string","null"]},"subtotal":{"description":"Invoice subtotal. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"tax":{"description":"Tax. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"},"tax_percentage":{"description":"The tax rate in percent, such as `\"8.25\"`, when the invoice has one rate; otherwise null.","type":["string","null"]},"total":{"description":"Invoice total. A decimal string with 2 decimal places, such as `\"1250.00\"`; parse it as a decimal.","type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List invoices for export","tags":["Invoices"],"x-yoprint-docs":{"errors":[{"fix":"Send both dates.","status":422,"when":"A date is missing or not ISO 8601."},{"fix":"Ask the team owner for report permission.","status":403,"when":"The role lacks `view_report`. This error has no envelope: the body is `{\"message\": \"Insufficient Permission\"}`."}],"group":"Invoices and payments","permission":"Needs the `view_report` permission.","related":["v1_public_sales_order_invoices_export","v1_public_sales_order_invoices_export_all_invoice_items"]}}},"/v1/api/store/{team_slug}/sales_order/poll_pending_payment":{"post":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_sales_order_payment_index` (GET /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nMeant to check a pending card payment. Card-payment polling isn't usable through the public API: every call fails with HTTP 500 (`{\"message\": \"Server Error\"}`), here and on the v2 path, because the route has no place for the pending payment's id. YoPrint checks pending payments in the background; read the order's payments with List the payments of a sales order instead.","operationId":"v1_public_sales_order_payment_gateway_polling","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"poll_token":"token-from-execute"},"schema":{"properties":{"poll_token":{"description":"The `poll_token` from Charge a card.","type":"string"}},"required":["poll_token"],"type":"object"}}},"required":true},"responses":{"200":{"description":"Never sent: this route always fails with HTTP 500."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Check a pending card payment (v1, not usable)","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"List the order's payments instead.","status":500,"when":"Always, as described above."}],"group":"Invoices and payments","permission":"Any member of the team.","prefer":"v2_public_sales_order_payment_index","related":["v2_public_sales_order_payment_index"],"status":"legacy"}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/history":{"get":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_order_history` (GET /v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}/history) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nRetired: this v1 operation no longer works. Every call fails with HTTP 500 and the body `{\"message\": \"Server Error\"}`. Use List the history of a sales order or quote (`v2.public.order.history`) to read an order's history. An id that is not one of this team's order ids answers 404 instead.","operationId":"v1_public_sales_order_history","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"description":"Never sent: this route always fails with HTTP 500."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get an order's history (retired v1)","tags":["Sales orders"],"x-yoprint-docs":{"errors":[{"fix":"Use List the history of a sales order or quote.","status":500,"when":"Every call with a valid id: `{\"message\": \"Server Error\"}`."}],"group":"Sales","prefer":"v2_public_order_history","related":["v2_public_order_history"],"status":"legacy"}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/job/{id}/attach":{"put":{"description":"Attaches files you uploaded first to a job, as mockups or production files. `{id}` is the job's `id`.\n\nThere is no separate v2 operation for this; in v2 you can also send files when you create or update a job. The answer is the job. Each job file carries its latest approval in `current_approval`; add `?omit_media_approval_items=1` to leave out that approval's `items` when you don't need them. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v1_public_sales_order_job_attach","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The job's `id` (a hash id).","example":"K6iF8n29iwOZnj","in":"path","name":"id","required":true,"schema":{"example":"K6iF8n29iwOZnj","type":"string"}},{"description":"Send `1` (or `true`, `on`, `yes`) to leave `items` out of each job file's `current_approval`, which makes the answer much smaller for jobs with many files on one approval. Every other key stays, in the same order, and the job's `pending_approval` keeps its items. Leave it out and the answer is unchanged. Only the query string counts: a body field of this name is ignored.","example":"1","in":"query","name":"omit_media_approval_items","required":false,"schema":{"enum":["1","true","on","yes"],"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"attachment":[{"collection":"mockup","id":"n5C1IPCmxDAqfy","position":1,"show_in_pdf":true}]},"schema":{"properties":{"attachment":{"items":{"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"id":{"description":"The upload's `id`.","type":"string"},"job_service":{"description":"The job service id (or ids) the file belongs to."},"name":{"type":"string"},"position":{"description":"Its place among the job's files.","type":"number"},"show_in_pdf":{"description":"Required for mockups: show it on the order PDF.","type":"boolean"}},"required":["id","collection","position"],"type":"object"},"minItems":1,"type":"array"}},"required":["attachment"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"id":"K6iF8n29iwOZnj","is_rush":false,"mockup":[{"collection":"mockup","created_at":"2026-11-03T09:00:00+00:00","current_approval":null,"current_approval_status":null,"file_name":"front-logo.png","id":"n5C1IPCmxDAqfy","is_image":true,"job_id":"K6iF8n29iwOZnj","job_service":[],"mime_type":"image/png","name":"Front logo","position":1,"show_in_pdf":true,"size":20480,"url":"https://example.com/files/front-logo.png"}],"name":"Front logo","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","pipelines":[],"pricing_total":{"dp":6,"value":0},"production_file":[],"scoped_id":"JOB-1001","services":[],"status":{"color":"#9e9e9e","customer_label":"Pending","id":"YOqAGjroQEo2ZK","label":"Artwork","position":1,"role":"job","trashed":false,"type":"start"},"status_id":"YOqAGjroQEo2ZK"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A job.","properties":{"assigned_users":{"items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"K6iF8n29iwOZnj","type":"string"},"impression_count":{"description":"Item count times decoration locations.","type":["string","number","integer","null"]},"inventory_status":{"type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Total quantity of the job's lines (a decimal string or number).","type":["string","number","integer","null"]},"mockup":{"description":"Mockups.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"name":{"example":"Front logo","type":["string","null"]},"note":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pending_approval":{"additionalProperties":true,"description":"The job's open approval (the first one not yet answered), or null. It always keeps its `items`, with or without `omit_media_approval_items`.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"pipelines":{"description":"Work pipelines (production steps).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"position":{"type":["integer","null"]},"pricing_original_total":{"description":"The same before pricing rules. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null when no rule did. List the jobs of a sales order or quote, Get one job and Rearrange the jobs answer with the full summary below. Other answers carry only `type`, the two ids and the two totals.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"2.00","type":"string"},"after_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2000000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","example":"2.50","type":"string"},"base_type":{"description":"Full summary only: always `service_price` on a job.","enum":["service_price"],"type":"string"},"normal_price":{"description":"Full summary only: the price with no rule; on a job the same as `base`.","example":"2.50","type":["string","null"]},"original_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`service` on a job.","example":"service","type":"string"}},"type":["object","null"]},"pricing_total":{"description":"Decoration price per unit that the job adds to each of its lines. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"is_rush":{"type":"boolean"},"name":{"type":["string","null"]},"object_type":{"type":"string"},"status_id":{"type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number people see, such as `JOB-1001`.","example":"JOB-1001","type":"string"},"services":{"description":"Decoration services: `service_id`, `location_*`, `option`, `position`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"services_still_valid":{"description":"false when the job's decoration services need repair.","type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status, as the status operations return it.","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_id":{"description":"The job's production status.","example":"YOqAGjroQEo2ZK","type":"string"},"unique_key":{"example":"job_EXAMPLEuniqueKey","type":["string","null"]}},"required":["id","order_id","scoped_id","status_id"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/MediaUploadValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Attach uploaded files to a job","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Send `collection`, `position` and, for mockups, `show_in_pdf`.","status":422,"when":"A required field is missing."},{"fix":"Check the ids.","status":404,"when":"The job or an upload does not exist."},{"fix":"Upload the file again and send the new id.","status":500,"when":"An id is a file already attached to something else, not a fresh upload (`{\"message\": \"Server Error\"}`)."}],"group":"Production","notes":["The job is found by its id alone; make sure it belongs to the order in the path.","Files are attached one at a time: when one fails, the ones before it stay attached.","A file already on this job is not attached twice; its `show_in_pdf`, `name` and position are updated from the entry."],"permission":"Any member of the team.","related":["v1_public_async_upload_store","v1_public_sales_order_job_rearrange","v2_public_job_update"],"rules":["`collection` is `mockup` or `production_file`; mockups also need `show_in_pdf`.","Each id must be a finished upload that is not attached anywhere yet."]}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/job/{id}/rearrange":{"put":{"description":"Sets new positions for a job's mockups and production files. `{id}` is the job's `id`. Not to be confused with reordering the jobs of an order (v2). The answer is the job. Each job file carries its latest approval in `current_approval`; add `?omit_media_approval_items=1` to leave out that approval's `items` when you don't need them. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v1_public_sales_order_job_rearrange","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The job's `id` (a hash id).","example":"K6iF8n29iwOZnj","in":"path","name":"id","required":true,"schema":{"example":"K6iF8n29iwOZnj","type":"string"}},{"description":"Send `1` (or `true`, `on`, `yes`) to leave `items` out of each job file's `current_approval`, which makes the answer much smaller for jobs with many files on one approval. Every other key stays, in the same order, and the job's `pending_approval` keeps its items. Leave it out and the answer is unchanged. Only the query string counts: a body field of this name is ignored.","example":"1","in":"query","name":"omit_media_approval_items","required":false,"schema":{"enum":["1","true","on","yes"],"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"attachment":[{"id":"n5C1IPCmxDAqfy","position":1},{"id":"CUv0F9nmg2laqp","position":2}]},"schema":{"properties":{"attachment":{"items":{"properties":{"id":{"description":"A file of the job.","type":"string"},"position":{"description":"Its new position.","type":"integer"}},"required":["id","position"],"type":"object"},"minItems":1,"type":"array"}},"required":["attachment"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"id":"K6iF8n29iwOZnj","is_rush":false,"mockup":[{"collection":"mockup","created_at":"2026-11-03T09:00:00+00:00","current_approval":null,"current_approval_status":null,"file_name":"front-logo.png","id":"n5C1IPCmxDAqfy","is_image":true,"job_id":"K6iF8n29iwOZnj","job_service":[],"mime_type":"image/png","name":"Front logo","position":1,"show_in_pdf":true,"size":20480,"url":"https://example.com/files/front-logo.png"},{"collection":"mockup","created_at":"2026-11-03T09:00:00+00:00","current_approval":null,"current_approval_status":null,"file_name":"back-print.png","id":"CUv0F9nmg2laqp","is_image":true,"job_id":"K6iF8n29iwOZnj","job_service":[],"mime_type":"image/png","name":"Back print","position":2,"show_in_pdf":true,"size":20480,"url":"https://example.com/files/front-logo.png"}],"name":"Front logo","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","pipelines":[],"pricing_total":{"dp":6,"value":0},"production_file":[],"scoped_id":"JOB-1001","services":[],"status":{"color":"#9e9e9e","customer_label":"Pending","id":"YOqAGjroQEo2ZK","label":"Artwork","position":1,"role":"job","trashed":false,"type":"start"},"status_id":"YOqAGjroQEo2ZK"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A job.","properties":{"assigned_users":{"items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"K6iF8n29iwOZnj","type":"string"},"impression_count":{"description":"Item count times decoration locations.","type":["string","number","integer","null"]},"inventory_status":{"type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Total quantity of the job's lines (a decimal string or number).","type":["string","number","integer","null"]},"mockup":{"description":"Mockups.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"name":{"example":"Front logo","type":["string","null"]},"note":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pending_approval":{"additionalProperties":true,"description":"The job's open approval (the first one not yet answered), or null. It always keeps its `items`, with or without `omit_media_approval_items`.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"pipelines":{"description":"Work pipelines (production steps).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"position":{"type":["integer","null"]},"pricing_original_total":{"description":"The same before pricing rules. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null when no rule did. List the jobs of a sales order or quote, Get one job and Rearrange the jobs answer with the full summary below. Other answers carry only `type`, the two ids and the two totals.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"2.00","type":"string"},"after_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2000000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","example":"2.50","type":"string"},"base_type":{"description":"Full summary only: always `service_price` on a job.","enum":["service_price"],"type":"string"},"normal_price":{"description":"Full summary only: the price with no rule; on a job the same as `base`.","example":"2.50","type":["string","null"]},"original_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`service` on a job.","example":"service","type":"string"}},"type":["object","null"]},"pricing_total":{"description":"Decoration price per unit that the job adds to each of its lines. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"is_rush":{"type":"boolean"},"name":{"type":["string","null"]},"object_type":{"type":"string"},"status_id":{"type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number people see, such as `JOB-1001`.","example":"JOB-1001","type":"string"},"services":{"description":"Decoration services: `service_id`, `location_*`, `option`, `position`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"services_still_valid":{"description":"false when the job's decoration services need repair.","type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status, as the status operations return it.","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_id":{"description":"The job's production status.","example":"YOqAGjroQEo2ZK","type":"string"},"unique_key":{"example":"job_EXAMPLEuniqueKey","type":["string","null"]}},"required":["id","order_id","scoped_id","status_id"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Reorder the files of a job","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Send every file with its new position.","status":422,"when":"`attachment` is missing or empty, or an entry lacks `id` or a valid `position` (`validation_failed`)."},{"fix":"Use ids from the job's files.","status":404,"when":"A file is not on this job."}],"group":"Production","permission":"Any member of the team.","related":["v1_public_sales_order_job_attach","v2_public_job_rearrange"],"rules":["Every id must be a file of the job."],"side_effects":["Refreshes the job for people who have it open in the web app."]}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/message":{"get":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_order_message_index` (GET /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/message) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nReturns the same conversation as the v2 list. Prefer List the messages of an order (v2). `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v1_public_sales_order_v1_message_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"actor_name":"Alex Rivera","actor_type":"user","contact_id":null,"created_at":"2026-11-03T09:00:00+00:00","email":null,"id":"mD1A7NR38PtyNs","name":null,"order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","preview_message":"<p>Hi Alex, your order is ready for pickup.</p>","status":"pending","type":"outbound","user_id":"PydH0WtBhSeiNU"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A message.","properties":{"actor_name":{"description":"The writer's name, by `actor_type`: the team member, contact, customer, guest, participant or vendor; the team's name for `system`. Null when it can't be found.","example":"Alex Rivera","type":["string","null"]},"actor_type":{"description":"Who wrote it: `user` (a team member), `contact`, `customer`, `guest`, `participant`, `vendor` or `system`.","example":"user","type":["string","null"]},"contact_id":{"description":"The contact who sent it, for replies.","type":["string","null"]},"created_at":{"description":"Sent. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"delivery_summary":{"additionalProperties":true,"description":"Delivery state per recipient.","type":["object","null"]},"email":{"type":["string","null"]},"id":{"example":"mD1A7NR38PtyNs","type":"string"},"name":{"description":"Sender name, for replies from the customer; null on messages your team sends (read `actor_name`).","type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"preview_message":{"description":"The first 200 characters. An email's preview keeps its HTML.","type":["string","null"]},"status":{"type":["string","null"]},"type":{"type":["string","null"]},"user_id":{"description":"The team member who sent it.","type":["string","null"]}},"required":["id"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the messages of an order (v1)","tags":["Sales order messages"],"x-yoprint-docs":{"group":"Sales","permission":"Needs permission to message this order's customer: the team owner, `message_all_order`, or `message_self_order` for orders the user created or is assigned to.","prefer":"v2_public_order_message_index","related":["v2_public_order_message_index"],"status":"legacy"}},"post":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_order_message_store` (POST /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/message) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nSends a message like the v2 operation, with the same body, but it also accepts drafts. Prefer Send a message to the customer (v2). Email limit: if your team goes over the daily email limit for its plan (60 a day on a free plan or trial, more on paid plans), YoPrint blocks email sending for your whole team until YoPrint support lifts the block. Space out bulk sends. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v1_public_sales_order_v1_message_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"internal_attachments":[{"type":"order"}],"message":"<p>Hi Alex, your order is ready for pickup.</p>","participants":[{"id":"LBbXMRNWVof2bd"}]},"schema":{"properties":{"internal_attachments":{"description":"Documents and files to attach.","items":{"properties":{"detail":{"type":"string"},"media_id":{"description":"The file's id. Required for `media` and `reference_media`.","type":"string"},"name":{"description":"The attachment's file name.","type":"string"},"options":{"properties":{"id":{"description":"For `single_compact_invoice`: the `id` of one of this order's invoices. Another order's invoice, or an invoice that can't be printed yet, is left out without an error, and the message is still sent.","type":"string"},"show_mockup":{"description":"For `so_jobs_with_mockup` and `so_jobs_without_mockup`: `true` puts each job's mockup pages in the job sheets, `false` leaves them out. It overrides the type's own choice. Text such as `\"true\"` or `\"off\"` is accepted too; any other value is refused with 422 `validation_failed`. Other types ignore it.","type":"boolean"}},"type":"object"},"type":{"description":"A PDF YoPrint makes: the order or quote (`order`, `order_compact`), all jobs with or without mockups, all invoices (`so_invoices`, `so_compact_invoices`) or one invoice (`single_compact_invoice`, with `options.id`). Or a file: `media` or `reference_media`, with `media_id`. On a quote, the invoice files are named \"Pro Forma Invoice\" by default.","enum":["order","order_compact","so_jobs_with_mockup","so_jobs_without_mockup","so_invoices","so_compact_invoices","single_compact_invoice","media","reference_media"],"type":"string"}},"required":["type"],"type":"object"},"type":"array"},"message":{"description":"The message. HTML for email; plain text for a text message.","type":"string"},"participants":{"description":"Who receives it: participant ids from this order's participants (not contact ids). Required, at least one. Every id must be a current participant of this order: one that isn't refuses the whole message with 422 `participant_not_on_record`, and nothing is sent. An id listed twice counts once.","items":{"properties":{"id":{"description":"A participant `id`.","type":"string"}},"required":["id"],"type":"object"},"maxItems":20,"type":"array"},"send_as_text_message":{"description":"true to send it as a text message (SMS) instead of email.","type":"boolean"}},"required":["message","participants"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"actor_name":"Alex Rivera","actor_type":"user","contact_id":null,"created_at":"2026-11-03T09:00:00+00:00","email":null,"id":"mD1A7NR38PtyNs","message":"<p>Hi Alex, your order is ready for pickup.</p>","name":null,"order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","preview_message":"<p>Hi Alex, your order is ready for pickup.</p>","retryable":false,"status":"pending","type":"outbound","user_id":"PydH0WtBhSeiNU"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A message.","properties":{"actor_name":{"description":"The writer's name, by `actor_type`: the team member, contact, customer, guest, participant or vendor; the team's name for `system`. Null when it can't be found.","example":"Alex Rivera","type":["string","null"]},"actor_type":{"description":"Who wrote it: `user` (a team member), `contact`, `customer`, `guest`, `participant`, `vendor` or `system`.","example":"user","type":["string","null"]},"contact_id":{"description":"The contact who sent it, for replies.","type":["string","null"]},"created_at":{"description":"Sent. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"delivery_summary":{"additionalProperties":true,"description":"Delivery state per recipient.","type":["object","null"]},"email":{"type":["string","null"]},"id":{"example":"mD1A7NR38PtyNs","type":"string"},"message":{"description":"The full message.","type":["string","null"]},"name":{"description":"Sender name, for replies from the customer; null on messages your team sends (read `actor_name`).","type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"preview_message":{"description":"The first 200 characters. An email's preview keeps its HTML.","type":["string","null"]},"retryable":{"description":"true when a failed delivery can be retried.","type":"boolean"},"status":{"type":["string","null"]},"type":{"type":["string","null"]},"user_id":{"description":"The team member who sent it.","type":["string","null"]}},"required":["id"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Send a message to the customer (v1)","tags":["Sales order messages"],"x-yoprint-docs":{"errors":[{"fix":"Add participants with an email address or SMS consent.","status":422,"when":"An empty `participants` list, a participant who can't receive the channel, a deleted order, or the team's email limit is reached."},{"fix":"List this order's participants and send only their ids; add anyone missing as a participant first.","status":422,"when":"A participant id is not a current participant of this order: another order's participant, a removed one, or an unknown id (`error.code` `participant_not_on_record`). Nothing is saved or sent."},{"fix":"Ask YoPrint support to turn email on, or lift the block.","status":422,"when":"The team can't send email: `email_feature_not_enabled_in_trial`, or over the daily limit."},{"fix":"Ask the team owner for message permission.","status":403,"when":"The role can't message this order's customer."}],"group":"Messages and activity","permission":"Needs permission to message this order's customer: the team owner, `message_all_order`, or `message_self_order` for orders the user created or is assigned to.","prefer":"v2_public_order_message_store","related":["v2_public_order_message_store"],"rules":["`participants` must be a non-empty list: an empty or missing list is refused with 422 \"Participants are required\".","Every participant id must belong to this order and not be removed: an id of another order's participant, a removed participant or an unknown id refuses the whole message with 422 `participant_not_on_record` (\"A recipient is not on this record. Refresh the page and choose the recipients again.\"), and nothing is saved or sent. Use ids from this order's participant list.","Each participant must be able to receive the channel: email needs an email address (`participant_cannot_receive_email`), a text message needs `can_receive_sms`.","By email, every listed participant with an email address is sent the message, whatever their `status` or `can_receive_mail`. By text message, only those with `can_receive_sms` and status `all` or `message`. Leave out anyone who should not receive it.","At most 20 participants per message.","Deleted orders and Shopify orders refuse messages.","Messages count toward the team's daily email limit (60 a day on the free plan, and on a trial only once YoPrint support has turned email on for it; 280, 380 or 800 on paid plans depending on the subscription's age). Going over it blocks the team's email until YoPrint support lifts the block. A trial without email turned on, or a team without an active plan, gets 422 `email_feature_not_enabled_in_trial`."],"side_effects":["Sends the message to the participants by email (or text message) after it is saved, with the attachments. An email's link to the conversation opens it for the contact it was sent to.","The message is sent as the API key's user.","When the message shows in the customer portal (a published order that isn't from Shopify, with customer messages on), Customer Portal pages the order's customer has open refresh."],"status":"legacy"}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/participant":{"get":{"description":"Participants are the people who can receive an order's messages: contacts of the customer, or guests with just an email address. Each has its own email and text message switches and a `status` (`all` by default). A message goes to the participants you list in it: by email to everyone listed who has an email address, whatever the switches or status; by text only to those with `can_receive_sms` and status `all` or `message`. Every id in a message must be a current participant of that order, or the message is refused (see Send a message to the customer).\n\nReturns the order's participants with their `id`, which messages use. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here. There is no v2 version.","operationId":"v1_public_sales_order_participant_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"can_receive_mail":true,"can_receive_sms":false,"contact_id":"7fobq9tQvOi5EG","email":"alex@example.com","id":"LBbXMRNWVof2bd","name":"Alex Rivera","order_id":"V4keXwwxMQyXw7","phone":null,"status":"all","trashed":false,"type":"contact"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A participant.","properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact_id":{"description":"Set for contacts; null for guests.","type":["string","null"]},"email":{"example":"alex@example.com","type":["string","null"]},"id":{"description":"The participant id that messages use.","example":"LBbXMRNWVof2bd","type":"string"},"name":{"example":"Alex Rivera","type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"phone":{"type":["string","null"]},"status":{"description":"`all`, `message`, `notification` or `disabled`.","example":"all","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"`contact` or `guest`.","type":["string","null"]}},"required":["id","status"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the participants of an order","tags":["Sales order messages"],"x-yoprint-docs":{"group":"Sales","permission":"Any member of the team.","related":["v1_public_sales_order_participant_store","v2_public_order_message_store"]}},"post":{"description":"Participants are the people who can receive an order's messages: contacts of the customer, or guests with just an email address. Each has its own email and text message switches and a `status` (`all` by default). A message goes to the participants you list in it: by email to everyone listed who has an email address, whatever the switches or status; by text only to those with `can_receive_sms` and status `all` or `message`. Every id in a message must be a current participant of that order, or the message is refused (see Send a message to the customer).\n\nAdds one participant. Send `type: \"contact\"` with a `contact_id`, or `type: \"guest\"` with an `email`. The answer is the participant; use its `id` in messages. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v1_public_sales_order_participant_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"contact":{"summary":"A contact of the customer","value":{"can_receive_mail":true,"can_receive_sms":false,"contact_id":"7fobq9tQvOi5EG","status":"all","type":"contact"}},"guest":{"summary":"A guest","value":{"can_receive_mail":true,"can_receive_sms":false,"email":"alex@example.com","name":"Alex Rivera","type":"guest"}}},"schema":{"properties":{"can_receive_mail":{"description":"Whether they get messages by email.","type":"boolean"},"can_receive_sms":{"description":"Whether they get text messages.","type":"boolean"},"contact_id":{"description":"Required for `contact`: the contact's `id`.","type":"string"},"email":{"description":"Required for `guest`.","format":"email","type":"string"},"name":{"description":"The guest's name.","type":"string"},"status":{"description":"Default `all`.","enum":["all","message","notification","disabled"],"type":"string"},"type":{"description":"`contact` for one of the customer's contacts, `guest` for anyone else.","enum":["contact","guest"],"type":"string"}},"required":["type","can_receive_mail","can_receive_sms"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"can_receive_mail":true,"can_receive_sms":false,"contact_id":"7fobq9tQvOi5EG","email":"alex@example.com","id":"LBbXMRNWVof2bd","name":"Alex Rivera","order_id":"V4keXwwxMQyXw7","phone":null,"status":"all","trashed":false,"type":"contact"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A participant.","properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact_id":{"description":"Set for contacts; null for guests.","type":["string","null"]},"email":{"example":"alex@example.com","type":["string","null"]},"id":{"description":"The participant id that messages use.","example":"LBbXMRNWVof2bd","type":"string"},"name":{"example":"Alex Rivera","type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"phone":{"type":["string","null"]},"status":{"description":"`all`, `message`, `notification` or `disabled`.","example":"all","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"`contact` or `guest`.","type":["string","null"]}},"required":["id","status"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add a participant to an order","tags":["Sales order messages"],"x-yoprint-docs":{"errors":[{"fix":"Send the fields for the chosen `type`.","status":422,"when":"A required field is missing or the email is not valid."}],"group":"Sales","permission":"Any member of the team.","related":["v1_public_sales_order_participant_index","v2_public_order_message_store","v1_public_customer_contact_index"],"rules":["`contact_id` is required for `contact`, `email` for `guest`.","`can_receive_mail` and `can_receive_sms` are required."],"side_effects":["Sends nothing."]}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/participant/clear":{"patch":{"description":"Removes all participants of a sales order. A quote answers 404: this operation looks the order up among sales orders only. Messages already sent keep their recipients. The answer has no data. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v1_public_sales_order_participant_clear","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's `id` (a hash id). A quote's id answers 404 here. The `ord_` unique key and the order number do not work.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"description":"No data.","type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove every participant from an order","tags":["Sales order messages"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Check the id. A quote's participants can't be cleared here.","status":404,"when":"No such sales order in this team, or the id is a quote's."}],"group":"Sales","permission":"Any member of the team.","related":["v1_public_sales_order_participant_store"],"rules":["Sales orders only: a quote's id answers 404."],"side_effects":["A later message that names a removed participant is refused with 422 `participant_not_on_record`. Add participants again, and use their new ids, before sending."]}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/payment/{payment_gateway}":{"post":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_sales_order_payment_gateway_execute` (POST /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment/{payment_reference}) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nThe older path for charging a card (`{payment_gateway}` is the gateway name). It runs exactly the same code as Charge a card through the payment gateway (`v2.public.sales_order.payment.gateway.execute`): use that one.","operationId":"v1_public_sales_order_payment_gateway_execute","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The payment gateway.","example":"stripe","in":"path","name":"payment_gateway","required":true,"schema":{"enum":["stripe","square","square_v2","paypal","authorize_net","charge_it_pro"],"example":"stripe","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"locking_token":"pay-1001-a","order_id":"V4keXwwxMQyXw7","payment_intent_id":"pi_example_1001"},"schema":{"properties":{"amount":{"description":"The amount to charge. Send a whole number of thousandths: `12500` is 12.50. Required for `square`, `square_v2` (not with `square_token` `cash`), `paypal`, and `authorize_net`; checked before the provider is called. `stripe` and `charge_it_pro` take the amount from Prepare a card payment.","type":"integer"},"authorizenet_token":{"description":"`authorize_net`: the card token.","type":"string"},"internal_id":{"description":"`charge_it_pro`: the pending payment from Prepare.","type":"string"},"locking_token":{"description":"Your one-time token for this payment attempt. Required.","type":"string"},"order_id":{"description":"The order's `id` again. Required.","type":"string"},"payment_intent_id":{"description":"`stripe`: the confirmed payment intent from Prepare.","type":"string"},"paypal_order_id":{"description":"`paypal`: the approved PayPal order.","type":"string"},"square_token":{"description":"`square`: the card token.","type":"string"},"surcharge":{"description":"Optional card surcharge included in `amount`, when the team charges one; the order must have an invoice. It must not be negative.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["locking_token","order_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"poll_id":"","poll_token":"","status":"success"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"poll_id":{"description":"For `pending`: the pending payment's id.","type":"string"},"poll_token":{"description":"For `pending`: a token for polling.","type":"string"},"status":{"description":"`success`, or `pending` while the provider finishes.","example":"success","type":"string"}},"required":["status"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Charge a card through the gateway (v1)","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Connect the gateway in Settings and send its fields.","status":422,"when":"`square_v2` without a Square v2 connection (`gateway_not_setup`), `square` when the team's old Square connection is switched off (`using_deprecated_old_square_gateway`), a missing gateway field, the provider refused (for example `payment_capture_failed`), or a Shopify order deleted in Shopify (`shopify_order_deleted_externally`)."},{"fix":"Use one of the gateway names.","status":404,"when":"An unknown `{payment_gateway}` or order (`page_not_found` or \"No query results for …\")."},{"fix":"Send at least 1.00 (`1000`) in thousandths.","status":422,"when":"`amount` is missing or not a whole number (`validation_failed`), less than 1.00 after the surcharge (`payment_below_minimum`), or the surcharge is negative (`payment_surcharge_invalid`). Nothing is charged."}],"group":"Invoices and payments","permission":"Any member of the team.","prefer":"v2_public_sales_order_payment_gateway_execute","related":["v2_public_sales_order_payment_gateway_execute"],"status":"legacy"}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/payment/{payment_gateway}/pre_execute":{"post":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_sales_order_payment_gateway_pre_execute` (POST /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment/{payment_gateway}/pre_execute) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nThe older path for preparing a card payment. It runs exactly the same code as Prepare a card payment (`v2.public.sales_order.payment.gateway.pre_execute`): use that one.","operationId":"v1_public_sales_order_payment_gateway_pre_execute","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The payment gateway.","example":"stripe","in":"path","name":"payment_gateway","required":true,"schema":{"enum":["stripe","square","square_v2","paypal","authorize_net","charge_it_pro"],"example":"stripe","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"amount":85000},"schema":{"properties":{"amount":{"description":"The amount to charge. Send a whole number of thousandths: `12500` is 12.50. Required for every gateway.","type":"integer"},"internal_id":{"description":"`charge_it_pro` only, optional: a UUID to use as the pending payment's `internal_id`. Anything that isn't a UUID is refused with 422 \"The internal id must be a valid UUID.\"","format":"uuid","type":["string","null"]},"locking_token":{"description":"`charge_it_pro` only: your one-time token for this payment.","type":["string","null"]},"skip_terminal":{"description":"`charge_it_pro` only.","type":"boolean"},"surcharge":{"description":"Optional card surcharge included in `amount`, read only when the team charges one. It must not be negative; it is taken off `amount` for the minimum check.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["amount"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"client_secret":"client-secret-from-stripe","payment_intent_id":"pi_example_1001"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"What the gateway needs next; `stripe` shown. Other gateways return their own fields.","properties":{"client_secret":{"description":"`stripe`: the secret for Stripe.js.","type":"string"},"payment_intent_id":{"description":"`stripe`: the payment intent to confirm.","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Prepare a card payment (v1)","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Connect the gateway in Settings and send its fields.","status":422,"when":"`square_v2` without a Square v2 connection (`gateway_not_setup`), `square` when the team's old Square connection is switched off (`using_deprecated_old_square_gateway`), a missing gateway field, the provider refused (for example `payment_capture_failed`), or a Shopify order deleted in Shopify (`shopify_order_deleted_externally`)."},{"fix":"Use one of the gateway names.","status":404,"when":"An unknown `{payment_gateway}` or order (`page_not_found` or \"No query results for …\")."},{"fix":"Call Charge a card directly.","status":422,"when":"The gateway has no first step (`square`, `square_v2`, `paypal`, `authorize_net`): `payment_pre_execute_failed` \"Pre Execution Not Supported\"."},{"fix":"Send at least 1.00 (`1000`) in thousandths.","status":422,"when":"`amount` is missing or not a whole number (`validation_failed`), less than 1.00 after the surcharge (`payment_below_minimum`), or the surcharge is negative (`payment_surcharge_invalid`)."},{"fix":"Check the order id.","status":422,"when":"A valid order id that no longer exists: \"Cannot Start Transaction: Sales Order Not Found\"."}],"group":"Invoices and payments","permission":"Any member of the team.","prefer":"v2_public_sales_order_payment_gateway_pre_execute","related":["v2_public_sales_order_payment_gateway_pre_execute"],"status":"legacy"}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/payment_gateway_refund/{id}":{"put":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_sales_order_payment_gateway_refund` (PUT /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment_gateway_refund/{id}) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nThe older path for refunding a card payment. It runs exactly the same code as Refund a card payment through the gateway (`v2.public.sales_order.payment.gateway.refund`): use that one.","operationId":"v1_public_sales_order_payment_gateway_refund","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The card payment's `id` (a hash id).","example":"JMQ642WFe4sANJ","in":"path","name":"id","required":true,"schema":{"example":"JMQ642WFe4sANJ","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"amount":25000,"locking_token":"refund-1001-a"},"schema":{"properties":{"amount":{"description":"How much to refund, in thousandths. Required in practice: see above.","minimum":1,"type":"integer"},"intent":{"description":"Accepted and not used: the refund is the same whatever you send. Any other value is refused with 422.","enum":["provider_refund_only","cancel_and_return_credit","return_to_source_credit"],"type":"string"},"locking_token":{"description":"Your one-time token for this refund. Required.","type":"string"}},"required":["locking_token","amount"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"description":"No data.","type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Refund a card payment (v1)","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Check the payment, or refund it in the provider's dashboard and record it with Record a refund.","status":422,"when":"Another order's payment, a record that isn't a card payment, a Charge It Pro payment or a Customer Portal payment its provider can't refund (`refund_failed`); a payment from Customer Portal credit (`customer_payment_parent_refund_required`)."},{"fix":"Read the message; check the payment in the provider's dashboard.","status":422,"when":"The provider refused (`refund_processing_failed`). For Stripe the message says why (for example a disputed charge, or more than is left to refund) and `error.data` has `provider` `stripe` and `provider_error_code`."},{"fix":"Wait for the provider's decision, then try again.","status":422,"when":"A payment is frozen by an open dispute or review (`customer_payment_disputed_funds_unavailable` or `invoice_payment_funding_withheld`, with `error.reason`)."},{"fix":"Wait for settlement, or refund it in the provider's dashboard.","status":422,"when":"An Authorize.Net payment that hasn't settled (`invoice_payment_refund_requires_settlement`, `invoice_payment_refund_provider_state_invalid`), or the Customer Portal payment's provider account changed (`invoice_payment_provider_identity_mismatch`)."},{"fix":"Refund at most the payment's `refundable_amount` plus unspent credit issued from it.","status":422,"when":"More than the payment can refund (`validation_error`, \"Refund Amount greater than what payment can be refunded\"). This is found after the provider refunded: check the provider before you do anything else."},{"fix":"Send `amount` and a card payment `id` (`payment_gateway` not null).","status":500,"when":"No `amount`, an id that is no record of the team, or a payment through the old Square connection (`{\"message\": \"Server Error\"}`)."}],"group":"Invoices and payments","permission":"Any member of the team.","prefer":"v2_public_sales_order_payment_gateway_refund","related":["v2_public_sales_order_payment_gateway_refund"],"status":"legacy"}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/square_terminal/create":{"post":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_sales_order_payment_square_terminal_create` (POST /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/square_terminal/create) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nThe older path for starting a Square Terminal checkout. It runs exactly the same code as Start a Square Terminal checkout (`v2.public.sales_order.payment.square_terminal.create`): use that one.","operationId":"v1_public_sales_order_payment_square_terminal_create","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"amount":85000,"device_id":"device-1001"},"schema":{"properties":{"amount":{"description":"Send a whole number of thousandths: `12500` is 12.50. Must be at least 1.00 (`1000`) after any `surcharge`.","type":"integer"},"device_id":{"description":"The Square Terminal device id.","type":"string"},"surcharge":{"description":"Optional card surcharge included in `amount`, read only when the team charges one. It must not be negative; it is taken off `amount` for the minimum check.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["device_id","amount"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"amount_money":{"amount":8500,"currency":"USD"},"id":"checkout-1001","reference_id":"SO1001","status":"PENDING"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"Square's Terminal checkout, with empty fields left out (also `note`, `device_options`, `deadline_duration`, `created_at`, `updated_at`, `app_id`, `location_id`, `payment_type`).","properties":{"amount_money":{"additionalProperties":true,"properties":{"amount":{"description":"In Square's smallest unit (cents for USD): 125000 thousandths is 12500.","type":"integer"},"currency":{"example":"USD","type":"string"}},"type":"object"},"id":{"description":"Square's checkout id: use it to cancel.","example":"checkout-1001","type":"string"},"reference_id":{"description":"The order number, for example SO1001.","type":"string"},"status":{"description":"Square's checkout status, such as `PENDING`.","type":["string","null"]}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Start a Square Terminal checkout (v1)","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Publish the order first.","status":500,"when":"A draft order: `error.code` \"Action Not Allow\"."},{"fix":"Connect Square in Settings.","status":422,"when":"Square v2 is not connected: `{\"message\": \"Square v2 Not Setup\"}`, with no envelope."},{"fix":"Check the device id.","status":422,"when":"Square refused: `payment_capture_failed`, with Square's errors in `error.data`."},{"fix":"Send at least 1.00 (`1000`) in thousandths.","status":422,"when":"`amount` is missing or not a whole number (`validation_failed`), less than 1.00 after the surcharge (`payment_below_minimum`), or the surcharge is negative (`payment_surcharge_invalid`)."}],"group":"Invoices and payments","permission":"Any member of the team.","prefer":"v2_public_sales_order_payment_square_terminal_create","related":["v2_public_sales_order_payment_square_terminal_create"],"status":"legacy"}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/square_terminal/{checkout_id}/cancel":{"patch":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_sales_order_payment_square_terminal_cancel` (PATCH /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/square_terminal/{checkout_id}/cancel) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nThe older path for cancelling a Square Terminal checkout. It runs exactly the same code as Cancel a Square Terminal checkout (`v2.public.sales_order.payment.square_terminal.cancel`): use that one.","operationId":"v1_public_sales_order_payment_square_terminal_cancel","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"Square's checkout id, from Start a Square Terminal checkout. Not a YoPrint hash id.","example":"checkout-1001","in":"path","name":"checkout_id","required":true,"schema":{"example":"checkout-1001","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"description":"No data.","type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Cancel a Square Terminal checkout (v1)","tags":["Payments"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Cancel it on the device.","status":500,"when":"Square could not cancel it (`unable_cancel_terminal_flow`)."},{"fix":"Connect Square in Settings.","status":422,"when":"Square v2 is not connected: `{\"message\": \"Square v2 Not Setup\"}`."}],"group":"Invoices and payments","permission":"Any member of the team.","prefer":"v2_public_sales_order_payment_square_terminal_cancel","related":["v2_public_sales_order_payment_square_terminal_cancel"],"status":"legacy"}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/tag":{"get":{"description":"Returns the tags on a sales order or quote. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here. This is the current way to manage order tags; there is no v2 version.","operationId":"v1_public_sales_order_tag_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color_hex":"#E53935","id":"7qYPMmbLZR9oFg","name":"Rush"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"color_hex":{"description":"Tag color, for example `#E53935`.","type":["string","null"]},"id":{"example":"7qYPMmbLZR9oFg","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the tags of an order","tags":["Sales order tags"],"x-yoprint-docs":{"group":"Sales","permission":"Any member of the team.","related":["v1_public_sales_order_tag_attach","v1_public_tag_index"]}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/tag/attach":{"put":{"description":"Adds an existing tag to a sales order or quote. Adding a tag it already has changes nothing.\n\nCreate new tags with the team's tag operations. The answer is the order's tags. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v1_public_sales_order_tag_attach","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"id":"7qYPMmbLZR9oFg"},"schema":{"properties":{"id":{"description":"The tag's `id`, from the team's tags.","type":"string"}},"required":["id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color_hex":"#E53935","id":"7qYPMmbLZR9oFg","name":"Rush"}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"The order's tags after the change.","items":{"additionalProperties":true,"properties":{"color_hex":{"description":"Tag color, for example `#E53935`.","type":["string","null"]},"id":{"example":"7qYPMmbLZR9oFg","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Tag an order","tags":["Sales order tags"],"x-yoprint-docs":{"errors":[{"fix":"Use a tag id from the team's tags.","status":404,"when":"The tag or the order does not exist in this team."}],"group":"Sales","permission":"Any member of the team.","related":["v1_public_sales_order_tag_detach","v1_public_tag_index","v1_public_tag_store"],"side_effects":["Refreshes the order for people who have it open in the web app."]}}},"/v1/api/store/{team_slug}/sales_order/{hash_id}/tag/detach":{"put":{"description":"Removes a tag from a sales order or quote. The tag itself stays. The answer is the order's remaining tags. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v1_public_sales_order_tag_detach","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"id":"7qYPMmbLZR9oFg"},"schema":{"properties":{"id":{"description":"The tag's `id`, from the team's tags.","type":"string"}},"required":["id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[],"status":200,"success":true},"schema":{"properties":{"data":{"description":"The order's tags after the change.","items":{"additionalProperties":true,"properties":{"color_hex":{"description":"Tag color, for example `#E53935`.","type":["string","null"]},"id":{"example":"7qYPMmbLZR9oFg","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove a tag from an order","tags":["Sales order tags"],"x-yoprint-docs":{"errors":[{"fix":"Use a tag id from the order's tags.","status":404,"when":"The tag or the order does not exist in this team."}],"group":"Sales","permission":"Any member of the team.","related":["v1_public_sales_order_tag_attach"],"side_effects":["Refreshes the order for people who have it open in the web app."]}}},"/v1/api/store/{team_slug}/service_location":{"get":{"description":"Lists every service location of the team, deleted ones included (`trashed: true`), each with `id`, `name`, `enable` and the `services` (`id`, `name`) offered there. Not paged.","operationId":"v1_public_service_location_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"enable":true,"id":"454DGJ3i6EQpq0","name":"Shirt - Left Chest","services":[{"id":"IIVE3hadAUOmIA","name":"Screen printing"}],"trashed":false}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"enable":{"type":"boolean"},"id":{"type":"string"},"name":{"type":["string","null"]},"services":{"description":"The services offered at this location.","items":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","name"],"type":"object"},"type":"array"},"trashed":{"type":"boolean"}},"required":["id","name","services","enable","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List service locations","tags":["Service locations"],"x-yoprint-docs":{"group":"Team settings","permission":"Any member of the team.","related":["v1_public_service_location_store"]}},"post":{"description":"Creates a service location and returns it. Link it to services in YoPrint (Settings).","operationId":"v1_public_service_location_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"enable":true,"name":"Shirt - Left Chest"},"schema":{"additionalProperties":false,"properties":{"enable":{"description":"Whether it can be picked. Defaults to true. Not checked: send a JSON boolean.","type":"boolean"},"name":{"description":"Where on the item the decoration goes, such as \"Shirt - Front\". Need not be unique.","type":"string"}},"required":["name"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"enable":true,"id":"454DGJ3i6EQpq0","name":"Shirt - Left Chest","services":[],"trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"enable":{"type":"boolean"},"id":{"type":"string"},"name":{"type":["string","null"]},"services":{"description":"The services offered at this location.","items":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","name"],"type":"object"},"type":"array"},"trashed":{"type":"boolean"}},"required":["id","name","services","enable","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a service location","tags":["Service locations"],"x-yoprint-docs":{"errors":[{"fix":"Send a name.","status":422,"when":"`name` is missing. `error.code` is `validation_failed`."},{"fix":"Ask a team owner to set Manage Services to the level that can create.","status":403,"when":"Your role cannot create services. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Team settings","notes":["Leave `enable` out and the location is saved enabled, but this answer shows `enable: false` (it is not read back). Send `enable: true`, or read the location again."],"permission":"Needs the Manage Services permission at the level that can create services.","related":["v1_public_service_location_index"]}}},"/v1/api/store/{team_slug}/service_location/{hash_id}":{"delete":{"description":"Deletes a service location. It can be restored. Deleting one that is already deleted also succeeds (its delete time is set again).","operationId":"v1_public_service_location_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The service location's id (`id` from List service locations). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a service location","tags":["Service locations"],"x-yoprint-docs":{"errors":[{"fix":"Check the id.","status":404,"when":"No service location with this id in the team. `error.code` is null and `error.message` names the record type."},{"fix":"Ask a team owner to raise Manage Services for your role.","status":403,"when":"Your role cannot update services. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Team settings","permission":"Needs the Manage Services permission at the level that can update services.","related":["v1_public_service_location_restore"]}},"get":{"description":"Returns one service location with its `services`, deleted ones included (`trashed`).","operationId":"v1_public_service_location_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The service location's id (`id` from List service locations). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"enable":true,"id":"454DGJ3i6EQpq0","name":"Shirt - Left Chest","services":[{"id":"IIVE3hadAUOmIA","name":"Screen printing"}],"trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"enable":{"type":"boolean"},"id":{"type":"string"},"name":{"type":["string","null"]},"services":{"description":"The services offered at this location.","items":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","name"],"type":"object"},"type":"array"},"trashed":{"type":"boolean"}},"required":["id","name","services","enable","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a service location","tags":["Service locations"],"x-yoprint-docs":{"group":"Team settings","permission":"Any member of the team.","related":["v1_public_service_location_update_patch"]}},"patch":{"description":"Renames or enables or disables a service location, and returns it. Deleted ones can be changed too.\n\nUse `PUT`: it checks `name`. `PATCH` takes the same body but checks nothing. `enable` is never checked: send a JSON boolean.","operationId":"v1_public_service_location_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The service location's id (`id` from List service locations). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"name":"Shirt - Left Chest (small)"},"schema":{"additionalProperties":false,"properties":{"enable":{"type":"boolean"},"name":{"type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"enable":true,"id":"454DGJ3i6EQpq0","name":"Shirt - Left Chest (small)","services":[{"id":"IIVE3hadAUOmIA","name":"Screen printing"}],"trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"enable":{"type":"boolean"},"id":{"type":"string"},"name":{"type":["string","null"]},"services":{"description":"The services offered at this location.","items":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","name"],"type":"object"},"type":"array"},"trashed":{"type":"boolean"}},"required":["id","name","services","enable","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a service location (PATCH)","tags":["Service locations"],"x-yoprint-docs":{"errors":[{"fix":"Check the id.","status":404,"when":"No service location with this id in the team. `error.code` is null and `error.message` names the record type."},{"fix":"Ask a team owner to raise Manage Services for your role.","status":403,"when":"Your role cannot update services. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Team settings","permission":"Needs the Manage Services permission at the level that can update services.","related":["v1_public_service_location_show"]}},"put":{"description":"Renames or enables or disables a service location, and returns it. Deleted ones can be changed too.\n\nUse `PUT`: it checks `name`. `PATCH` takes the same body but checks nothing. `enable` is never checked: send a JSON boolean.","operationId":"v1_public_service_location_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The service location's id (`id` from List service locations). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"name":"Shirt - Left Chest (small)"},"schema":{"additionalProperties":false,"properties":{"enable":{"type":"boolean"},"name":{"type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"enable":true,"id":"454DGJ3i6EQpq0","name":"Shirt - Left Chest (small)","services":[{"id":"IIVE3hadAUOmIA","name":"Screen printing"}],"trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"enable":{"type":"boolean"},"id":{"type":"string"},"name":{"type":["string","null"]},"services":{"description":"The services offered at this location.","items":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":["string","null"]}},"required":["id","name"],"type":"object"},"type":"array"},"trashed":{"type":"boolean"}},"required":["id","name","services","enable","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a service location","tags":["Service locations"],"x-yoprint-docs":{"errors":[{"fix":"Send `name` as a string.","status":422,"when":"`PUT` only: `name` is not a string. `error.code` is `validation_failed`."},{"fix":"Check the id.","status":404,"when":"No service location with this id in the team. `error.code` is null and `error.message` names the record type."},{"fix":"Ask a team owner to raise Manage Services for your role.","status":403,"when":"Your role cannot update services. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Team settings","permission":"Needs the Manage Services permission at the level that can update services.","related":["v1_public_service_location_show"]}}},"/v1/api/store/{team_slug}/service_location/{hash_id}/restore":{"patch":{"description":"Brings back a deleted service location. Answers `success: true` with `data: null`.","operationId":"v1_public_service_location_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The service location's id (`id` from List service locations). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a service location","tags":["Service locations"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Check the id.","status":404,"when":"No service location with this id. `error.code` is null and `error.message` names the record type."},{"fix":"Ask a team owner to raise Manage Services for your role.","status":403,"when":"Your role cannot update services. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Team settings","permission":"Needs the Manage Services permission at the level that can update services.","related":["v1_public_service_location_destroy"]}}},"/v1/api/store/{team_slug}/setting":{"get":{"description":"Returns the team's settings as one object keyed by setting name: PDF and display options, date formats, tax labels, customer portal options and more, with defaults filled in for options the team never changed.\n\nIt also includes which gateways are on (`enable_*`), the webhook URLs each gateway calls (`stripe_webhook_url`, `paypal_webhook_url`, `square_webhook_url`), and the payment gateway values saved with Update payment gateway settings. Which saved values you get depends on who you are:\n\n- The team owner and members with Manage Settings get all of them, including secret keys, access tokens and signing keys.\n- Every other member gets only the values that identify an account: `publishable_key`, `paypal_client_id`, `paypal_webhook_id`, `square_client_id`, `square_location_id`, `square_webhook_locations`, `stripe_webhook_id`, `charge_it_pro_oid`, `charge_it_pro_device_id`, `authorize_login_id` and `authorize_client_key`.","operationId":"v1_public_setting_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"cust_msg_status":true,"customer_portal_account_login_available":true,"customer_portal_rollout":{"account_only":false,"all_teams_at":null,"configuration_warning":null,"legacy_access_allowed":true,"new_teams_at":null,"reason":"transition"},"default_pricing_strategy":"job_separately","enable_stripe":true,"payment_amount_policies":{"USD":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null}},"payment_amount_policy":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null},"paypal_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/paypal","pdf_date_format":"other_1","shipping_label_create_cost_line_item":true,"square_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/square","stripe_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/stripe","tax_label_name":"Tax","web_date_format":"default"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"Every stored team setting, keyed by name, with defaults filled in for the display options, and the team's stored payment gateway values: all of them for the team owner and members with Manage Settings, only the account identifiers for other members (see Show team settings).","properties":{"cust_msg_status":{"example":true,"type":"boolean"},"customer_portal_account_login_available":{"description":"Worked out by YoPrint: whether customers can sign in to your customer portal with an email account. True when your plan includes the customer portal.","example":true,"type":"boolean"},"customer_portal_rollout":{"additionalProperties":false,"description":"Worked out by YoPrint: where the customer portal's move to email-account sign-in stands for your team. YoPrint sets the dates; you can't change them here.","properties":{"account_only":{"description":"True when customers must sign in with an email account: a direct portal link alone no longer opens the portal.","example":false,"type":"boolean"},"all_teams_at":{"description":"When account login becomes mandatory for all teams (UTC), or null if not set.","example":null,"format":"date-time","type":["string","null"]},"configuration_warning":{"description":"A system warning if rollout dates are inconsistent (`new_teams_cutoff_not_before_all_teams_cutoff` or `invalid_rollout_date`), or null.","enum":["new_teams_cutoff_not_before_all_teams_cutoff","invalid_rollout_date",null],"example":null,"type":["string","null"]},"legacy_access_allowed":{"description":"True when direct portal links still open the portal without an account sign-in.","example":true,"type":"boolean"},"new_teams_at":{"description":"When account login became mandatory for new teams (UTC), or null if not set.","example":null,"format":"date-time","type":["string","null"]},"reason":{"description":"Why this rollout policy applies to your team: `transition` (standard rollout period), `new_team_cutoff` (new team policy), or `all_teams_cutoff` (mandatory for all teams).","enum":["transition","new_team_cutoff","all_teams_cutoff"],"example":"transition","type":"string"}},"required":["account_only","legacy_access_allowed","reason","new_teams_at","all_teams_at","configuration_warning"],"type":"object"},"default_pricing_strategy":{"description":"How new jobs are priced by default. `job_separately` when never set.","enum":["job_separately","job_together","service_loc_together"],"example":"job_separately","type":"string"},"enable_stripe":{"description":"Present once it was sent to Update payment gateway settings, with the value sent. The same for `enable_paypal`, `enable_square`, `enable_square_payment`, `enable_charge_it_pro`, `enable_authorize_net` and `charge_it_pro_mode`.","example":true,"type":"boolean"},"payment_amount_policies":{"additionalProperties":{"additionalProperties":true,"type":"object"},"description":"Read only: the minimum payment policy for each of your currencies (deleted ones included), keyed by ISO currency code. An empty list `[]` when the team has no currencies.","example":{"USD":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null}},"type":["object","array"]},"payment_amount_policy":{"description":"Read only: the smallest payment YoPrint accepts in your default currency, or null when the team has no default currency.","properties":{"currency":{"description":"The currency code.","example":"USD","type":"string"},"minimum_payment":{"description":"A decimal pair whose `value` is a string: the amount is `value` ÷ 10^`dp` (`{\"value\": \"1000\", \"dp\": 3}` is 1.00). YoPrint refuses smaller payments.","properties":{"dp":{"const":3,"description":"Always 3.","example":3,"type":"integer"},"value":{"description":"The unscaled amount as a string.","example":"1000","type":"string"}},"required":["value","dp"],"type":"object"},"minimum_remaining_balance":{"description":"Always null here.","example":null,"type":"null"}},"type":["object","null"]},"paypal_webhook_url":{"example":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/paypal","type":"string"},"pdf_date_format":{"description":"The date format on PDFs. `std` is the default for a team that never changed it; PDFs show it like `other_1` (05 Nov 2026). A team whose saved settings have no date format reads `other_1`. Update general settings accepts only the other five values.","enum":["std","default","british_standard","us_standard","international","other_1"],"example":"other_1","type":"string"},"shipping_label_create_cost_line_item":{"description":"Whether \"Create Shipping Cost Line Item\" starts checked when someone buys a shipping label in the web app. `true` when never set.","example":true,"type":"boolean"},"square_webhook_url":{"description":"Add this URL in the Square Developer Dashboard before you turn Square on.","example":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/square","type":"string"},"stripe_webhook_url":{"description":"The URL Stripe calls for this team. YoPrint registers it in your Stripe account when you save Stripe settings.","example":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/stripe","type":"string"},"tax_label_name":{"description":"The name used for tax on documents. `Tax` when never set.","example":"Tax","type":"string"},"web_date_format":{"description":"The date format in the web app. `us` is the default for a team that never changed it; the web app shows it like `default` (Nov 05, 2026). A team whose saved settings have no date format reads `default`. Update general settings accepts only the other five values.","enum":["us","default","british_standard","us_standard","international","other_1"],"example":"default","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show team settings","tags":["Company settings"],"x-yoprint-docs":{"group":"Team settings","notes":["For the team owner and members with Manage Settings the response includes stored payment gateway credentials. Keep it out of logs and don't pass it to people who shouldn't see them.","Which keys appear depends on what the team has saved. Read the keys you need and ignore the rest."],"permission":"Any team member can call it. Reading needs no extra permission. Stored gateway credentials are returned only to the team owner and members with Manage Settings.","related":["v1_public_setting_update","v1_public_setting_general_update","v1_public_setting_detail_show","v1_public_setting_payment_gateway_update"]}},"put":{"description":"Changes the team's company details: name, email, phone, website, tax number and timezone. Returns the team, as Get your company details does.\n\nSend only the fields to change. On this operation `null` clears `email`, `phone`, `website` and `tax_number`; `name` and `timezone` can't be cleared. An empty or blank string clears a field too.","operationId":"v1_public_setting_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"email":"alex@example.com","name":"Northwind Apparel","phone":"+1 201 555 0123","website":null},"schema":{"properties":{"email":{"description":"The company email. `null` clears it.","format":"email","type":["string","null"]},"name":{"description":"The company name. Can't be empty or null.","minLength":1,"type":"string"},"onboard_status":{"description":"Used by the web app's onboarding. Leave it out.","type":"string"},"phone":{"description":"`null` clears it.","type":["string","null"]},"phone_country":{"description":"The phone number's country code, such as `US`. An empty value is ignored.","type":"string"},"tax_number":{"description":"The team's tax or VAT number. `null` clears it.","type":["string","null"]},"timezone":{"description":"A timezone name such as `America/New_York`. Can't be empty or null. An unknown name is refused with 422: \"The timezone must be a timezone name, such as America/New_York.\"","type":"string"},"website":{"description":"`null` clears it.","type":["string","null"]}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"channel_id":1001,"custom_domain":null,"customer_portal_bg":null,"dimension":"in","email":"alex@example.com","favicon_url":null,"ga_id":null,"id":"s8D8dfOtRdUiRt","logo_url":null,"name":"Northwind Apparel","onboard_status":"completed","payment_gateway":[],"phone":"+1 201 555 0123","phone_country":"US","plan":{"active":true,"detail":{"active":true,"name":"Pro","need_to_select_plan":false,"status":"active"},"features":{"user_limit":10},"type":"paid"},"plan_region":"US","printavo_importer_available":false,"printavo_importer_enabled":false,"seeded":true,"slug":"your-team","tax_number":null,"timezone":"America/New_York","trial_expires_at":"2026-11-03T15:00:00+00:00","website":null,"weight":"lbs"},"status":200,"success":true},"schema":{"properties":{"data":{"description":"The team, with its plan.","properties":{"channel_id":{"description":"The team's number, used by YoPrint's live-update channel.","example":1001,"type":"integer"},"custom_domain":{"example":null,"type":["string","null"]},"customer_portal_bg":{"example":null,"type":["string","null"]},"dimension":{"description":"The length unit.","example":"in","type":["string","null"]},"email":{"example":"alex@example.com","type":["string","null"]},"favicon_url":{"description":"The customer portal favicon, or null when none is uploaded.","example":null,"type":["string","null"]},"ga_id":{"example":null,"type":["string","null"]},"id":{"example":"s8D8dfOtRdUiRt","type":"string"},"logo_url":{"example":null,"type":["string","null"]},"name":{"example":"Northwind Apparel","type":"string"},"onboard_status":{"example":"completed","type":["string","null"]},"payment_gateway":{"description":"The gateways customers can pay through, with only their public identifiers. Empty when the plan has no payment integration.","example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"phone":{"example":"+1 201 555 0123","type":["string","null"]},"phone_country":{"example":"US","type":["string","null"]},"plan":{"additionalProperties":true,"description":"The team's YoPrint plan: `type` (`paid`, `trial` or `free`), `active`, `detail` and `features`. The same as on Get your company details.","properties":{"active":{"example":true,"type":"boolean"},"detail":{"additionalProperties":true,"example":{"active":true,"name":"Pro","need_to_select_plan":false,"status":"active"},"type":"object"},"features":{"additionalProperties":true,"example":{"user_limit":10},"type":"object"},"type":{"enum":["paid","trial","free"],"example":"paid","type":"string"}},"type":"object"},"plan_region":{"example":"US","type":["string","null"]},"printavo_importer_available":{"example":false,"type":"boolean"},"printavo_importer_enabled":{"example":false,"type":"boolean"},"seeded":{"example":true,"type":"boolean"},"slug":{"description":"The `{team_slug}` in every path.","example":"your-team","type":"string"},"tax_number":{"example":null,"type":["string","null"]},"timezone":{"example":"America/New_York","type":"string"},"trial_expires_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"website":{"example":null,"type":["string","null"]},"weight":{"description":"The weight unit.","example":"lbs","type":["string","null"]}},"required":["id","name","slug","timezone","payment_gateway","plan"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update company details","tags":["Company settings"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`name` or `timezone` is empty or null, `timezone` is not a timezone name, or `email` is not an email address. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_setting_detail_show","v1_public_setting_show"],"rules":["`name` and `timezone`, when sent, must not be empty or null. `timezone` must be a name PHP knows, such as `America/New_York`: any other text is 422 (`error.fields.timezone`: \"The timezone must be a timezone name, such as America/New_York.\").","`email`, when not null, must be an email address.","Surrounding spaces are trimmed from `email`, `phone`, `website` and `tax_number`."],"side_effects":["New PDFs and emails use the new details."]}}},"/v1/api/store/{team_slug}/setting/adjustment_reason":{"get":{"description":"Returns all the team's stock adjustment reasons in one list, on and off. This only manages the reasons: stock adjustments, stock takes and transfers are not part of the public API.\n\nReasons offered when someone adjusts stock by hand, such as Damaged or Stocktake. A stock adjustment stores the reason as text, so renaming or deleting a reason doesn't change past adjustments. Every team starts with YoPrint's built-in reasons (`system: true`): New Products, Returned, Production of Goods, Damaged, Shrinkage, Promotion and Stocktake.","operationId":"v1_public_adjustment_reason_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"enable":true,"id":"ygAWpMiOJ7htSQ","reason":"Damaged","system":true}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"enable":{"description":"Whether stock adjustments offer it. False hides it.","example":true,"type":"boolean"},"id":{"example":"ygAWpMiOJ7htSQ","type":"string"},"reason":{"example":"Damaged","type":"string"},"system":{"description":"True for YoPrint's built-in reasons.","example":true,"type":"boolean"}},"required":["id","reason","enable","system"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List stock adjustment reasons","tags":["Stock adjustment reasons"],"x-yoprint-docs":{"group":"Team settings","notes":["Offer only reasons with `enable: true`."],"permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_adjustment_reason_store"]}},"post":{"description":"Adds a reason of your own and returns it. It is on unless you send `enable: false`.\n\nReasons offered when someone adjusts stock by hand, such as Damaged or Stocktake. A stock adjustment stores the reason as text, so renaming or deleting a reason doesn't change past adjustments. Every team starts with YoPrint's built-in reasons (`system: true`): New Products, Returned, Production of Goods, Damaged, Shrinkage, Promotion and Stocktake.","operationId":"v1_public_adjustment_reason_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"reason":"Sample sent to customer"},"schema":{"properties":{"enable":{"default":true,"type":"boolean"},"reason":{"description":"The text people pick.","type":"string"}},"required":["reason"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"enable":true,"id":"8MICavW4VoLtS2","reason":"Sample sent to customer","system":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"enable":{"description":"Whether stock adjustments offer it. False hides it.","example":true,"type":"boolean"},"id":{"example":"ygAWpMiOJ7htSQ","type":"string"},"reason":{"example":"Damaged","type":"string"},"system":{"description":"True for YoPrint's built-in reasons.","example":true,"type":"boolean"}},"required":["id","reason","enable","system"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a stock adjustment reason","tags":["Stock adjustment reasons"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`reason` is missing. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_adjustment_reason_index"],"rules":["`reason` is required. Reasons don't have to be unique."]}}},"/v1/api/store/{team_slug}/setting/adjustment_reason/{hash_id}":{"delete":{"description":"Deletes a reason for good. Past stock adjustments keep their reason text. To hide a reason you may want later, set `enable: false` instead.","operationId":"v1_public_adjustment_reason_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The stock adjustment reason's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"ygAWpMiOJ7htSQ","in":"path","name":"hash_id","required":true,"schema":{"example":"ygAWpMiOJ7htSQ","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a stock adjustment reason","tags":["Stock adjustment reasons"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No stock adjustment reason with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","notes":["YoPrint lets you delete a built-in reason too, and there is no restore."],"permission":"Needs the Manage Settings permission."}},"get":{"description":"Returns one stock adjustment reason.","operationId":"v1_public_adjustment_reason_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The stock adjustment reason's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"ygAWpMiOJ7htSQ","in":"path","name":"hash_id","required":true,"schema":{"example":"ygAWpMiOJ7htSQ","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"enable":true,"id":"ygAWpMiOJ7htSQ","reason":"Damaged","system":true},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"enable":{"description":"Whether stock adjustments offer it. False hides it.","example":true,"type":"boolean"},"id":{"example":"ygAWpMiOJ7htSQ","type":"string"},"reason":{"example":"Damaged","type":"string"},"system":{"description":"True for YoPrint's built-in reasons.","example":true,"type":"boolean"}},"required":["id","reason","enable","system"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show a stock adjustment reason","tags":["Stock adjustment reasons"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_adjustment_reason_update_patch"]}},"patch":{"description":"Use PUT to change this record. PATCH saves the same fields but skips validation, so a bad value can be stored or fail with a server error.","operationId":"v1_public_adjustment_reason_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The stock adjustment reason's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"ygAWpMiOJ7htSQ","in":"path","name":"hash_id","required":true,"schema":{"example":"ygAWpMiOJ7htSQ","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"enable":false},"schema":{"properties":{"enable":{"description":"Ignored for built-in reasons.","type":"boolean"},"reason":{"type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"enable":false,"id":"8MICavW4VoLtS2","reason":"Sample sent to customer","system":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"enable":{"description":"Whether stock adjustments offer it. False hides it.","example":true,"type":"boolean"},"id":{"example":"ygAWpMiOJ7htSQ","type":"string"},"reason":{"example":"Damaged","type":"string"},"system":{"description":"True for YoPrint's built-in reasons.","example":true,"type":"boolean"}},"required":["id","reason","enable","system"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a stock adjustment reason without checks","tags":["Stock adjustment reasons"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No stock adjustment reason with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_adjustment_reason_show"]}},"put":{"description":"Renames a reason or turns it on or off, and returns it. Built-in reasons (`system: true`) can be renamed, but `enable` is ignored for them.","operationId":"v1_public_adjustment_reason_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The stock adjustment reason's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"ygAWpMiOJ7htSQ","in":"path","name":"hash_id","required":true,"schema":{"example":"ygAWpMiOJ7htSQ","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"enable":false},"schema":{"properties":{"enable":{"description":"Ignored for built-in reasons.","type":"boolean"},"reason":{"type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"enable":false,"id":"8MICavW4VoLtS2","reason":"Sample sent to customer","system":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"enable":{"description":"Whether stock adjustments offer it. False hides it.","example":true,"type":"boolean"},"id":{"example":"ygAWpMiOJ7htSQ","type":"string"},"reason":{"example":"Damaged","type":"string"},"system":{"description":"True for YoPrint's built-in reasons.","example":true,"type":"boolean"}},"required":["id","reason","enable","system"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a stock adjustment reason","tags":["Stock adjustment reasons"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No stock adjustment reason with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`reason` is not a string, or `enable` is not a boolean. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_adjustment_reason_show"]}}},"/v1/api/store/{team_slug}/setting/billing_portal":{"get":{"description":"**Internal.** Built for YoPrint's own apps, not for integrations. Don't build on it.\n\nMeant to return `{\"url\": ...}`, a link to manage YoPrint billing: the billing page for the team owner, an error page for anyone else.\n\nToday it always fails with 500, because the pages it links to no longer exist. Manage billing on the Billing page of the YoPrint web app.","operationId":"v1_public_setting_billing_portal_redirect","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"url":"https://example.com/billing"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"url":{"description":"Not returned today; see above.","format":"uri","type":"string"}},"required":["url"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a link to the billing page","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Use the Billing page in the YoPrint web app.","status":500,"when":"Always, today. The body is `{\"message\": \"Server Error\"}`, without the error envelope."}],"group":"Team settings","notes":["AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"Any member of the team.","status":"internal"},"x-internal":true}},"/v1/api/store/{team_slug}/setting/column":{"put":{"description":"Saves which columns one of the team's lists shows in the web app, for everyone on the team: sales orders, quotes, purchase orders, customers, jobs or shipments.\n\n`value` replaces the saved setting for that list. Its shape is the web app's own: read the current `column` setting first and send it back changed. Returns the full settings object.","operationId":"v1_public_setting_column_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"key":"sales_order","value":[{"field":"customer","visible":true}]},"schema":{"additionalProperties":false,"properties":{"key":{"enum":["sales_order","quote","purchase_order","customer","job","shipment"],"type":"string"},"value":{"description":"The column setting for that list, as the web app saves it (a JSON array or object). It replaces what was saved.","type":["array","object"]}},"required":["key","value"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"column":{"sales_order":[{"field":"customer","visible":true}]},"cust_msg_status":false,"customer_portal_account_login_available":true,"customer_portal_rollout":{"account_only":false,"all_teams_at":null,"configuration_warning":null,"legacy_access_allowed":true,"new_teams_at":null,"reason":"transition"},"default_pricing_strategy":"job_separately","dimension":"in","enable_stock_management":true,"pagination_per_page":50,"payment_amount_policies":{"USD":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null}},"payment_amount_policy":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null},"paypal_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/paypal","pdf_date_format":"us_standard","pdf_sales_order_display_option":["job_summary"],"shipping_label_create_cost_line_item":true,"square_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/square","stripe_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/stripe","web_date_format":"default","weight":"lbs"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"The team's settings: the saved general settings (the keys \"Update general settings\" takes, with their defaults), `column` (list columns), `cust_msg_status` (the add-on), the three payment webhook addresses, the read-only customer portal sign-in and payment minimum fields below, and the payment gateway values stored for the team, which can include secret keys (sensitive; treat as private). A team that never changed its date formats reads `pdf_date_format: \"std\"` and `web_date_format: \"us\"`, values outside the list the update takes.","properties":{"column":{"additionalProperties":true,"description":"List columns, by list name (`sales_order`, `quote`, ...). An empty array `[]` when none is saved.","type":["object","array"]},"cust_msg_status":{"description":"Whether the customer message statuses add-on is on.","type":"boolean"},"customer_portal_account_login_available":{"description":"Read only: whether customers can sign in to your customer portal with an email account. True when your plan includes the customer portal.","type":"boolean"},"customer_portal_rollout":{"additionalProperties":false,"description":"Read only: where the customer portal's move to email-account sign-in stands for your team. YoPrint sets the dates; you can't change them here.","properties":{"account_only":{"description":"True when customers must sign in with an email account: a portal link alone no longer opens the portal.","type":"boolean"},"all_teams_at":{"description":"From when every team is account-only (UTC), or null when not set.","format":"date-time","type":["string","null"]},"configuration_warning":{"description":"Set when YoPrint's own rollout dates are inconsistent; null normally.","enum":["new_teams_cutoff_not_before_all_teams_cutoff","invalid_rollout_date",null],"type":["string","null"]},"legacy_access_allowed":{"description":"The opposite of `account_only`: portal links still open the portal.","type":"boolean"},"new_teams_at":{"description":"From when new teams are account-only (UTC), or null when not set.","format":"date-time","type":["string","null"]},"reason":{"description":"`transition`: links still work. `new_team_cutoff`: the team was created after the date for new teams. `all_teams_cutoff`: the date for every team has passed.","enum":["transition","new_team_cutoff","all_teams_cutoff"],"type":"string"}},"required":["account_only","legacy_access_allowed","reason","new_teams_at","all_teams_at","configuration_warning"],"type":"object"},"pagination_per_page":{"type":"integer"},"payment_amount_policies":{"additionalProperties":{"additionalProperties":false,"properties":{"currency":{"example":"USD","type":"string"},"minimum_payment":{"additionalProperties":false,"description":"A decimal pair whose `value` is a string: the amount is `value` ÷ 10^`dp` (`{\"value\": \"1000\", \"dp\": 3}` is 1.00). YoPrint refuses smaller payments.","properties":{"dp":{"const":3,"type":"integer"},"value":{"type":"string"}},"required":["value","dp"],"type":"object"},"minimum_remaining_balance":{"description":"Always null here.","type":"null"}},"required":["currency","minimum_payment","minimum_remaining_balance"],"type":"object"},"description":"Read only: the same for each of your currencies, deleted ones included, keyed by ISO code (orders keep the currency they were made in). `[]` when the team has none.","type":["object","array"]},"payment_amount_policy":{"anyOf":[{"additionalProperties":false,"properties":{"currency":{"example":"USD","type":"string"},"minimum_payment":{"additionalProperties":false,"description":"A decimal pair whose `value` is a string: the amount is `value` ÷ 10^`dp` (`{\"value\": \"1000\", \"dp\": 3}` is 1.00). YoPrint refuses smaller payments.","properties":{"dp":{"const":3,"type":"integer"},"value":{"type":"string"}},"required":["value","dp"],"type":"object"},"minimum_remaining_balance":{"description":"Always null here.","type":"null"}},"required":["currency","minimum_payment","minimum_remaining_balance"],"type":"object"},{"type":"null"}],"description":"Read only: the smallest payment YoPrint takes in your default currency, or null when the team has no default currency."},"paypal_webhook_url":{"description":"The same for PayPal.","format":"uri","type":"string"},"pdf_date_format":{"description":"Date format on PDFs. `std` is the default for a team that never changed it; PDFs show it like `other_1` (05 Nov 2026). A team whose saved settings have no date format reads `other_1`. \"Update general settings\" accepts only the other five values.","enum":["std","default","british_standard","us_standard","international","other_1"],"type":"string"},"shipping_label_create_cost_line_item":{"description":"Whether \"Create Shipping Cost Line Item\" starts checked when someone buys a shipping label in the web app. `true` until changed.","type":"boolean"},"square_webhook_url":{"description":"The same for Square.","format":"uri","type":"string"},"stripe_webhook_url":{"description":"The address to give Stripe for this team's payment webhooks.","format":"uri","type":"string"},"web_date_format":{"description":"Date format in the web app. `us` is the default for a team that never changed it; the web app shows it like `default` (Nov 05, 2026). A team whose saved settings have no date format reads `default`. \"Update general settings\" accepts only the other five values.","enum":["us","default","british_standard","us_standard","international","other_1"],"type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set the columns of a list","tags":["Company settings"],"x-yoprint-docs":{"errors":[{"fix":"Send one of the listed keys and an array.","status":422,"when":"`key` is not one of the six lists, or `value` is not an array (`validation_failed`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Treat the response as sensitive: besides your preferences it can carry the payment gateway values stored for the team. Don't log or share it."],"permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_setting_general_update"],"rules":["Always send `key` and `value`. The server doesn't require them, but without `key` the value is saved under an empty name."]}}},"/v1/api/store/{team_slug}/setting/compliance/shopify-data-request/{id}/download":{"get":{"description":"**Internal.** Built for YoPrint's own apps, not for integrations. Don't build on it.\n\nBuilt for YoPrint's web app: it downloads the file YoPrint prepared for a Shopify customer data request, a ZIP of what YoPrint holds about that customer. The `{id}` identifies the data request.\n\n**Through this API it always answers 403.** The download is for the team owner, and it looks for the owner's web sign-in, which an API key doesn't carry. So even the owner's key gets 403 \"Only the team owner can access this compliance export.\" Download the file as the owner in the YoPrint web app.","operationId":"v1_public_compliance_shopify_data_request_download","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The Shopify data request. Its hash id from an earlier answer; there is no unique key for it.","example":"PwbV3hrunm1NZ8","in":"path","name":"id","required":true,"schema":{"example":"PwbV3hrunm1NZ8","type":"string"}}],"responses":{"200":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}},"description":"Binary download response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download a Shopify customer data export","tags":["Compliance requests"],"x-yoprint-docs":{"errors":[{"fix":"Download it as the owner in the YoPrint web app.","status":403,"when":"Every call with an API key whose data request belongs to your team. The body is `{\"message\": \"Only the team owner can access this compliance export.\"}`, without the error envelope."},{"fix":"Use your own team's data request.","status":403,"when":"The data request belongs to another team. The body is `{\"message\": \"You do not have permission to access this compliance export.\"}`, without the error envelope."},{"fix":"Use the data request's id.","status":404,"when":"No data request has this id. `error.code` is null."}],"group":"Team settings","notes":["AI apps (MCP connections) can't call it either: they get 403 `agent_operation_not_available`."],"permission":"Meant for the team owner only, but no API key passes the owner check (see the description). It is a GET, so the Manage Settings check on its route doesn't apply.","status":"internal"},"x-internal":true}},"/v1/api/store/{team_slug}/setting/connected_device":{"get":{"description":"Returns the devices paired with your team, such as Square terminals for in-person card payments.\n\n`device_status` is `ready` (paired), `unpaired`, `not-found` (gone from Square, or its pairing code expired), `unknown`, or `disabled` for a device that is not a Square terminal. A Square terminal is added with the Square integration's data call (`type: create_device_code`), and its status refreshed with `type: device`.","operationId":"v1_public_connected_device_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"device_config":{"code":"ABCDEF","device_id":"device_example_1","id":"device_code_example_1","location_id":"YOUR_SQUARE_LOCATION_ID","name":"Front counter","product_type":"TERMINAL_API","status":"PAIRED","version":"1"},"device_id":"device_code_example_1","device_name":"Front counter","device_status":"ready","device_type":"square_terminal","id":"fPbIOxwKlAzDsA","is_enabled":true}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"device_config":{"description":"The provider's device details as stored, including a Square terminal's pairing `code` and `status` (sensitive; treat as private). Null for AI apps.","type":["object","array","null"]},"device_id":{"description":"The provider's id for it: for a Square terminal, the id of its pairing code.","type":["string","null"]},"device_name":{"type":["string","null"]},"device_status":{"enum":["ready","unpaired","not-found","unknown","disabled"],"type":"string"},"device_type":{"example":"square_terminal","type":"string"},"id":{"type":"string"},"is_enabled":{"type":"boolean"}},"required":["id","device_id","device_name","is_enabled","device_config","device_type","device_status"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List connected devices","tags":["Connected devices"],"x-yoprint-docs":{"group":"Team settings","notes":["`device_config` can hold a terminal's pairing code. Treat it as sensitive."],"permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_connected_device_destroy"]}}},"/v1/api/store/{team_slug}/setting/connected_device/{hash_id}":{"delete":{"description":"Removes the device from YoPrint for good. It is not unpaired at Square: do that in your Square account if you need to.","operationId":"v1_public_connected_device_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The device, from the device list. Its hash id from an earlier answer; there is no unique key for it.","example":"fPbIOxwKlAzDsA","in":"path","name":"hash_id","required":true,"schema":{"example":"fPbIOxwKlAzDsA","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove a connected device","tags":["Connected devices"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the device list.","status":404,"when":"No device of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_connected_device_index"],"side_effects":["Team members who have YoPrint open see it disappear at once."]}}},"/v1/api/store/{team_slug}/setting/currency":{"get":{"description":"Returns the team's currencies in one list. Deleted currencies are left out.\n\nYoPrint works in one currency per team: the default currency. Its `symbol` appears on PDFs, emails and formatted amounts (such as `formatted_calc_total`), and its `iso` code is sent to integrations such as QuickBooks and Shopify. A new sales order records the default currency when it is created, and YoPrint doesn't convert between currencies.\n\nThe team's first currency is its default. No operation changes the default: `default` in a request is ignored.","operationId":"v1_public_currency_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"default":true,"id":"Y3WvW4mbyTw1sO","iso":"USD","name":"US Dollar","symbol":"$","trashed":false}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"default":{"description":"Whether it is the team's currency.","example":true,"type":"boolean"},"id":{"example":"Y3WvW4mbyTw1sO","type":"string"},"iso":{"description":"The three-letter ISO 4217 code, in capitals.","example":"USD","type":"string"},"name":{"example":"US Dollar","type":"string"},"symbol":{"example":"$","type":"string"},"trashed":{"example":false,"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List currencies","tags":["Currencies"],"x-yoprint-docs":{"group":"Team settings","notes":["The currency with `default: true` is the one YoPrint uses."],"permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_currency_update_patch"]}},"post":{"description":"Adds a currency and returns it. It becomes the default only when the team has no currency yet.\n\nYoPrint works in one currency per team: the default currency. Its `symbol` appears on PDFs, emails and formatted amounts (such as `formatted_calc_total`), and its `iso` code is sent to integrations such as QuickBooks and Shopify. A new sales order records the default currency when it is created, and YoPrint doesn't convert between currencies.\n\nThe team's first currency is its default. No operation changes the default: `default` in a request is ignored.","operationId":"v1_public_currency_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"iso":"CAD","name":"Canadian Dollar","symbol":"CA$"},"schema":{"properties":{"auto_rate":{"description":"Stored but not used or returned.","type":"boolean"},"default":{"description":"Ignored.","type":"boolean"},"iso":{"description":"The three-letter ISO 4217 code, such as `CAD`. YoPrint checks only that it is 3 characters long, and saves it in capitals.","maxLength":3,"minLength":3,"type":"string"},"name":{"type":"string"},"rate":{"description":"Stored but not used or returned.","exclusiveMinimum":0,"type":"number"},"symbol":{"type":"string"}},"required":["name","iso","symbol"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"default":false,"id":"f468IevwjuSudz","iso":"CAD","name":"Canadian Dollar","symbol":"CA$","trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"default":{"description":"Whether it is the team's currency.","example":true,"type":"boolean"},"id":{"example":"Y3WvW4mbyTw1sO","type":"string"},"iso":{"description":"The three-letter ISO 4217 code, in capitals.","example":"USD","type":"string"},"name":{"example":"US Dollar","type":"string"},"symbol":{"example":"$","type":"string"},"trashed":{"example":false,"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a currency","tags":["Currencies"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A required field is missing, `iso` is not 3 characters, or `rate` is 0 or less. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","notes":["Adding a currency changes nothing else: amounts keep using the default currency."],"permission":"Needs the Manage Settings permission.","related":["v1_public_currency_index"],"rules":["`name`, `iso` (exactly 3 characters) and `symbol` are required.","`rate`, when sent, is greater than 0."]}}},"/v1/api/store/{team_slug}/setting/currency/{hash_id}":{"delete":{"description":"Deletes a currency that is not the default. It disappears from the list; restore it with Restore a currency.","operationId":"v1_public_currency_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The currency's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"Y3WvW4mbyTw1sO","in":"path","name":"hash_id","required":true,"schema":{"example":"Y3WvW4mbyTw1sO","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a currency","tags":["Currencies"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No currency with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"The default currency cannot be deleted or changed to another one through the API.","status":500,"when":"The currency is the team default (`error.code` is `delete_fail`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_currency_restore"],"rules":["The default currency cannot be deleted."]}},"get":{"description":"Returns one currency. A deleted currency answers 404.","operationId":"v1_public_currency_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The currency's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"Y3WvW4mbyTw1sO","in":"path","name":"hash_id","required":true,"schema":{"example":"Y3WvW4mbyTw1sO","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"default":true,"id":"Y3WvW4mbyTw1sO","iso":"USD","name":"US Dollar","symbol":"$","trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"default":{"description":"Whether it is the team's currency.","example":true,"type":"boolean"},"id":{"example":"Y3WvW4mbyTw1sO","type":"string"},"iso":{"description":"The three-letter ISO 4217 code, in capitals.","example":"USD","type":"string"},"name":{"example":"US Dollar","type":"string"},"symbol":{"example":"$","type":"string"},"trashed":{"example":false,"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show a currency","tags":["Currencies"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_currency_update_patch"]}},"patch":{"description":"Use PUT to change a currency. PATCH saves the same fields but skips validation, so an `iso` of the wrong length is stored.","operationId":"v1_public_currency_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The currency's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"Y3WvW4mbyTw1sO","in":"path","name":"hash_id","required":true,"schema":{"example":"Y3WvW4mbyTw1sO","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"symbol":"US$"},"schema":{"properties":{"auto_rate":{"description":"Stored but not used or returned.","type":"boolean"},"default":{"description":"Ignored.","type":"boolean"},"iso":{"description":"The three-letter ISO 4217 code, such as `CAD`. YoPrint checks only that it is 3 characters long, and saves it in capitals.","maxLength":3,"minLength":3,"type":"string"},"name":{"type":"string"},"rate":{"description":"Stored but not used or returned.","exclusiveMinimum":0,"type":"number"},"symbol":{"type":"string"}},"required":[],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"default":true,"id":"Y3WvW4mbyTw1sO","iso":"USD","name":"US Dollar","symbol":"US$","trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"default":{"description":"Whether it is the team's currency.","example":true,"type":"boolean"},"id":{"example":"Y3WvW4mbyTw1sO","type":"string"},"iso":{"description":"The three-letter ISO 4217 code, in capitals.","example":"USD","type":"string"},"name":{"example":"US Dollar","type":"string"},"symbol":{"example":"$","type":"string"},"trashed":{"example":false,"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a currency without checks","tags":["Currencies"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No currency with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_currency_show"],"rules":["`iso`, when sent, is exactly 3 characters.","`default` is ignored."]}},"put":{"description":"Changes a currency's name, code or symbol, and returns it. Send only the fields to change.\n\nChanging the default currency's `symbol` changes how amounts show on PDFs and emails made afterwards, and in formatted amounts. Changing its `iso` changes the code sent to integrations.","operationId":"v1_public_currency_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The currency's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"Y3WvW4mbyTw1sO","in":"path","name":"hash_id","required":true,"schema":{"example":"Y3WvW4mbyTw1sO","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"symbol":"US$"},"schema":{"properties":{"auto_rate":{"description":"Stored but not used or returned.","type":"boolean"},"default":{"description":"Ignored.","type":"boolean"},"iso":{"description":"The three-letter ISO 4217 code, such as `CAD`. YoPrint checks only that it is 3 characters long, and saves it in capitals.","maxLength":3,"minLength":3,"type":"string"},"name":{"type":"string"},"rate":{"description":"Stored but not used or returned.","exclusiveMinimum":0,"type":"number"},"symbol":{"type":"string"}},"required":[],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"default":true,"id":"Y3WvW4mbyTw1sO","iso":"USD","name":"US Dollar","symbol":"US$","trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"default":{"description":"Whether it is the team's currency.","example":true,"type":"boolean"},"id":{"example":"Y3WvW4mbyTw1sO","type":"string"},"iso":{"description":"The three-letter ISO 4217 code, in capitals.","example":"USD","type":"string"},"name":{"example":"US Dollar","type":"string"},"symbol":{"example":"$","type":"string"},"trashed":{"example":false,"type":"boolean"}},"required":["id","name","iso","symbol","default","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a currency","tags":["Currencies"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No currency with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`iso` is not 3 characters, or `rate` is 0 or less. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_currency_show"],"rules":["`iso`, when sent, is exactly 3 characters.","`default` is ignored."]}}},"/v1/api/store/{team_slug}/setting/currency/{id}/restore":{"patch":{"description":"Brings back a deleted currency. You need its id from before it was deleted, because the list leaves deleted currencies out.","operationId":"v1_public_currency_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The currency's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"Y3WvW4mbyTw1sO","in":"path","name":"id","required":true,"schema":{"example":"Y3WvW4mbyTw1sO","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a currency","tags":["Currencies"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No currency with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_currency_destroy"]}}},"/v1/api/store/{team_slug}/setting/custom_domain/check":{"put":{"description":"Runs the same checks as \"Set the custom domain\" without saving anything. It does not look at DNS; use \"Check a custom domain's DNS\" for that. When the domain is allowed, the answer is 200 with `data: null`.","operationId":"v1_public_setting_custom_domain_check","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"custom_domain":"shop.example.com"},"schema":{"additionalProperties":false,"properties":{"custom_domain":{"description":"The host, without `https://`: `shop.example.com`.","type":"string"}},"required":["custom_domain"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Check a custom domain is allowed","tags":["Company settings"],"x-yoprint-docs":{"errors":[{"fix":"Send the host as a string. The domain can't be cleared through this call.","status":422,"when":"`custom_domain` is missing or not a string (`validation_failed`)."},{"fix":"Read `error.message`, then choose another domain or upgrade the plan.","status":422,"when":"The domain is not valid (`domain_invalid`), not allowed (`domain_validation`), in use by another team (`domain_validation`), or beyond your plan (`plan_limitation`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_setting_custom_domain_update","v1_public_setting_custom_domain_check_setup"],"rules":["It must be a valid domain name.","Subdomains of `yoprint.com` are no longer allowed; use a subdomain of `yoprintmerch.com` instead.","YoPrint's own domains and hosts are refused.","Without the custom domain feature in your plan, only subdomains of `yoprintmerch.com` are allowed (`plan_limitation`).","A domain another team uses is refused."]}}},"/v1/api/store/{team_slug}/setting/custom_domain/check_setup":{"put":{"description":"Checks that the domain has a CNAME record pointing to `domain.yoprint.com`, using public DNS. Subdomains of `yoprintmerch.com` (and of `yoprint.com`) always pass.\n\nA success is remembered, so later checks of the same domain pass without a lookup. Send `refresh: true` to look again.\n\nThe response has no data when the record is right.","operationId":"v1_public_setting_custom_domain_check_setup","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"custom_domain":"shop.example.com","refresh":true},"schema":{"additionalProperties":false,"properties":{"custom_domain":{"description":"The host, without `https://`: `shop.example.com`.","type":"string"},"refresh":{"default":false,"description":"Ignore a remembered success and look the DNS up again.","type":"boolean"}},"required":["custom_domain"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Check a custom domain's DNS","tags":["Company settings"],"x-yoprint-docs":{"errors":[{"fix":"Add the record at your DNS provider and try again later; DNS changes can take a while to spread.","status":422,"when":"No CNAME record points to `domain.yoprint.com` yet, or the lookup failed: `error.code` `domain_not_setup`."},{"fix":"Send the host as a string.","status":422,"when":"`custom_domain` is missing, or `refresh` is not a boolean (`validation_failed`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Setting the domain doesn't check DNS. Check it before or after, so customers can reach the portal on it."],"permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_setting_custom_domain_update","v1_public_setting_custom_domain_check"],"side_effects":["Makes a DNS lookup through public resolvers."]}}},"/v1/api/store/{team_slug}/setting/custom_domain/update":{"put":{"description":"Sets the domain your customer portal is served on, for example `shop.example.com` or a subdomain of `yoprintmerch.com`.\n\nPoint the domain to YoPrint with a CNAME record to `domain.yoprint.com`, then confirm with \"Check a custom domain's DNS\". This call does not check DNS.\n\nReturns your company details with the new `custom_domain`.","operationId":"v1_public_setting_custom_domain_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"custom_domain":"shop.example.com"},"schema":{"additionalProperties":false,"properties":{"custom_domain":{"description":"The host, without `https://`: `shop.example.com`.","type":"string"}},"required":["custom_domain"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"channel_id":1001,"custom_domain":"shop.example.com","customer_portal_bg":null,"dimension":"in","email":"alex@example.com","favicon_url":null,"ga_id":"YxPx1001","id":"OutVLW14xRJYLp","logo_url":"https://example.com/logo.png","name":"Northwind Apparel","onboard_status":null,"payment_gateway":[],"phone":"+1 201 555 0123","phone_country":"US","plan":{"active":true,"detail":{"active":true,"name":"default","need_to_select_plan":false,"status":"active"},"features":{"customer_portal":true,"user_limit":5},"type":"paid"},"plan_region":"US","printavo_importer_available":false,"printavo_importer_enabled":false,"seeded":true,"slug":"your-team","tax_number":null,"timezone":"America/New_York","trial_expires_at":"2026-01-15T00:00:00+00:00","website":"https://example.com","weight":"lbs"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"channel_id":{"description":"The team's number, used by YoPrint's live-update channel.","type":"integer"},"custom_domain":{"description":"The host your customer portal is served on, or null.","type":["string","null"]},"customer_portal_bg":{"description":"The customer portal background image, or null.","type":["string","null"]},"dimension":{"description":"Length unit: `m`, `cm`, `mm` or `in`.","type":["string","null"]},"email":{"type":["string","null"]},"favicon_url":{"description":"The customer portal favicon (the icon in the browser tab), or null when none is uploaded.","type":["string","null"]},"ga_id":{"description":"An analytics id: `YxPx` and the team's number (`channel_id`).","example":"YxPx1001","type":"string"},"id":{"example":"OutVLW14xRJYLp","type":"string"},"logo_url":{"type":["string","null"]},"name":{"example":"Northwind Apparel","type":"string"},"onboard_status":{"type":["string","null"]},"payment_gateway":{"description":"The payment gateways your customers can pay through, with only their public identifiers (for example a Stripe publishable key). Empty when the plan has no payment integration.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"plan":{"additionalProperties":false,"description":"The team's YoPrint plan.","properties":{"active":{"description":"Whether the plan is active now.","type":"boolean"},"detail":{"additionalProperties":true,"description":"With a subscription: `name`, `status`, `active` and `need_to_select_plan`. On a trial or free plan: `id`, `name`, `archive`, `need_to_select_plan`, and on a trial `expire_at` and `status` (`active` or `expired`).","properties":{"active":{"type":"boolean"},"archive":{"type":"boolean"},"expire_at":{"format":"date-time","type":["string","null"]},"id":{"type":"string"},"name":{"description":"With a subscription, always `default`; otherwise the trial or free plan's name.","type":["string","null"]},"need_to_select_plan":{"description":"True when the team must choose a plan before it can go on.","type":"boolean"},"status":{"type":["string","null"]}},"type":"object"},"features":{"additionalProperties":true,"description":"What the plan allows: features, limits and integrations, keyed by name.","type":"object"},"type":{"description":"`paid` with a subscription; otherwise `trial` or `free`.","enum":["paid","trial","free"],"type":"string"}},"required":["type","active","detail","features"],"type":"object"},"plan_region":{"type":["string","null"]},"printavo_importer_available":{"type":"boolean"},"printavo_importer_enabled":{"type":"boolean"},"seeded":{"type":"boolean"},"slug":{"description":"The `{team_slug}` in every path.","example":"your-team","type":"string"},"tax_number":{"type":["string","null"]},"timezone":{"example":"America/New_York","type":"string"},"trial_expires_at":{"format":"date-time","type":"string"},"website":{"type":["string","null"]},"weight":{"description":"Weight unit: `kg`, `g`, `lbs` or `oz`.","type":["string","null"]}},"required":["id","name","slug","timezone","custom_domain","payment_gateway","plan"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set the custom domain","tags":["Company settings"],"x-yoprint-docs":{"errors":[{"fix":"Send the host as a string. The domain can't be cleared through this call.","status":422,"when":"`custom_domain` is missing or not a string (`validation_failed`)."},{"fix":"Read `error.message`, then choose another domain or upgrade the plan.","status":422,"when":"The domain is not valid (`domain_invalid`), not allowed (`domain_validation`), in use by another team (`domain_validation`), or beyond your plan (`plan_limitation`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_setting_custom_domain_check","v1_public_setting_custom_domain_check_setup","v1_public_setting_detail_show"],"rules":["It must be a valid domain name.","Subdomains of `yoprint.com` are no longer allowed; use a subdomain of `yoprintmerch.com` instead.","YoPrint's own domains and hosts are refused.","Without the custom domain feature in your plan, only subdomains of `yoprintmerch.com` are allowed (`plan_limitation`).","A domain another team uses is refused."],"side_effects":["Customer portal links use the new domain from now on."]}}},"/v1/api/store/{team_slug}/setting/customer_portal_bg":{"delete":{"description":"Removes the customer portal background image. The company details then read `customer_portal_bg: null`. Calling it when there is none also succeeds.","operationId":"v1_public_setting_customer_portal_bg_delete","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove the customer portal background","tags":["Company settings"],"x-yoprint-docs":{"errors":[{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_setting_customer_portal_bg_update"]}},"post":{"description":"Uploads the background image of your customer portal as `multipart/form-data`, in the field `media`. It replaces the current one.\n\nThe file is checked first, so a refused upload leaves the current background in place. Once the new image is saved, the old one is removed. The response has no data; read the company details for `customer_portal_bg`.","operationId":"v1_public_setting_customer_portal_bg_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"encoding":{"media":{"contentType":"image/png, image/jpeg"}},"schema":{"properties":{"media":{"description":"A JPEG or PNG image, at most 4096 KiB (4 MB). YoPrint reads the type from the file's content, not its name.","format":"binary","type":"string"}},"required":["media"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Upload the customer portal background","tags":["Company settings"],"x-yoprint-docs":{"errors":[{"fix":"Upload one JPEG or PNG file.","status":422,"when":"`media` is missing, is not a JPEG or PNG image, or is larger than 4096 KiB (`validation_failed`; `error.fields.media` says which). The current background stays."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_setting_customer_portal_bg_delete","v1_public_setting_detail_show"],"side_effects":["Customers see the new background the next time they open the portal."]}}},"/v1/api/store/{team_slug}/setting/customer_portal_favicon":{"delete":{"description":"Removes the customer portal favicon. The company details then read `favicon_url: null`. Calling it when there is none also succeeds. The response has no data.","operationId":"v1_public_setting_customer_portal_favicon_delete","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove the customer portal favicon","tags":["Company settings"],"x-yoprint-docs":{"errors":[{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_setting_customer_portal_favicon_update","v1_public_setting_detail_show"]}},"post":{"description":"Uploads the favicon of your customer portal, the small icon in the browser tab, as `multipart/form-data` in the field `media`. It replaces the current one.\n\nYoPrint checks the file's content, not its name: it must really be an ICO, PNG or JPEG file. A renamed file of another kind is refused, and SVG is not accepted. The file is saved with the type YoPrint found (`image/vnd.microsoft.icon` for an ICO).\n\nThe file is checked first, so a refused upload leaves the current favicon in place. Once the new one is saved, the old one is removed. The response has no data; read the company details for `favicon_url`.","operationId":"v1_public_setting_customer_portal_favicon_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"encoding":{"media":{"contentType":"image/vnd.microsoft.icon, image/x-icon, image/png, image/jpeg"}},"schema":{"properties":{"media":{"description":"An ICO, PNG or JPEG file, at most 4096 KiB (4 MB). An ICO must be well formed, with 1 to 256 images, each a PNG or a bitmap.","format":"binary","type":"string"}},"required":["media"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/MediaUploadValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Upload the customer portal favicon","tags":["Company settings"],"x-yoprint-docs":{"errors":[{"fix":"Upload one ICO, PNG or JPEG file.","status":422,"when":"`media` is missing, larger than 4096 KiB, or not a valid ICO, PNG or JPEG file (`validation_failed`; `error.fields.media` says, for example, \"The media must be a valid ICO, PNG, or JPEG file.\"). The current favicon stays."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_setting_customer_portal_favicon_delete","v1_public_setting_detail_show"],"side_effects":["Customers see the new icon the next time they open the portal."]}}},"/v1/api/store/{team_slug}/setting/detail":{"get":{"description":"Returns your team's profile: name, slug, contact details, timezone, units, logo, customer portal background and favicon, custom domain and plan.\n\nIt also lists the payment gateways customers can pay through, with only their public identifiers. Secret keys are never in this response.","operationId":"v1_public_setting_detail_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"channel_id":1001,"custom_domain":"shop.example.com","customer_portal_bg":null,"dimension":"in","email":"alex@example.com","favicon_url":null,"ga_id":"YxPx1001","id":"OutVLW14xRJYLp","logo_url":"https://example.com/logo.png","name":"Northwind Apparel","onboard_status":null,"payment_gateway":[],"phone":"+1 201 555 0123","phone_country":"US","plan":{"active":true,"detail":{"active":true,"name":"default","need_to_select_plan":false,"status":"active"},"features":{"customer_portal":true,"user_limit":5},"type":"paid"},"plan_region":"US","printavo_importer_available":false,"printavo_importer_enabled":false,"seeded":true,"slug":"your-team","tax_number":null,"timezone":"America/New_York","trial_expires_at":"2026-01-15T00:00:00+00:00","website":"https://example.com","weight":"lbs"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"channel_id":{"description":"The team's number, used by YoPrint's live-update channel.","type":"integer"},"custom_domain":{"description":"The host your customer portal is served on, or null.","type":["string","null"]},"customer_portal_bg":{"description":"The customer portal background image, or null.","type":["string","null"]},"dimension":{"description":"Length unit: `m`, `cm`, `mm` or `in`.","type":["string","null"]},"email":{"type":["string","null"]},"favicon_url":{"description":"The customer portal favicon (the icon in the browser tab), or null when none is uploaded.","type":["string","null"]},"ga_id":{"description":"An analytics id: `YxPx` and the team's number (`channel_id`).","example":"YxPx1001","type":"string"},"id":{"example":"OutVLW14xRJYLp","type":"string"},"logo_url":{"type":["string","null"]},"name":{"example":"Northwind Apparel","type":"string"},"onboard_status":{"type":["string","null"]},"payment_gateway":{"description":"The payment gateways your customers can pay through, with only their public identifiers (for example a Stripe publishable key). Empty when the plan has no payment integration.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"plan":{"additionalProperties":false,"description":"The team's YoPrint plan.","properties":{"active":{"description":"Whether the plan is active now.","type":"boolean"},"detail":{"additionalProperties":true,"description":"With a subscription: `name`, `status`, `active` and `need_to_select_plan`. On a trial or free plan: `id`, `name`, `archive`, `need_to_select_plan`, and on a trial `expire_at` and `status` (`active` or `expired`).","properties":{"active":{"type":"boolean"},"archive":{"type":"boolean"},"expire_at":{"format":"date-time","type":["string","null"]},"id":{"type":"string"},"name":{"description":"With a subscription, always `default`; otherwise the trial or free plan's name.","type":["string","null"]},"need_to_select_plan":{"description":"True when the team must choose a plan before it can go on.","type":"boolean"},"status":{"type":["string","null"]}},"type":"object"},"features":{"additionalProperties":true,"description":"What the plan allows: features, limits and integrations, keyed by name.","type":"object"},"type":{"description":"`paid` with a subscription; otherwise `trial` or `free`.","enum":["paid","trial","free"],"type":"string"}},"required":["type","active","detail","features"],"type":"object"},"plan_region":{"type":["string","null"]},"printavo_importer_available":{"type":"boolean"},"printavo_importer_enabled":{"type":"boolean"},"seeded":{"type":"boolean"},"slug":{"description":"The `{team_slug}` in every path.","example":"your-team","type":"string"},"tax_number":{"type":["string","null"]},"timezone":{"example":"America/New_York","type":"string"},"trial_expires_at":{"format":"date-time","type":"string"},"website":{"type":["string","null"]},"weight":{"description":"Weight unit: `kg`, `g`, `lbs` or `oz`.","type":["string","null"]}},"required":["id","name","slug","timezone","custom_domain","payment_gateway","plan"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get your company details","tags":["Company settings"],"x-yoprint-docs":{"group":"Team settings","permission":"Any member of the team.","related":["v1_public_setting_general_update","v1_public_setting_photo_update","v1_public_setting_customer_portal_favicon_update","v1_public_setting_custom_domain_update"]}}},"/v1/api/store/{team_slug}/setting/external_integration":{"get":{"description":"Returns the team's integrations: suppliers, Twilio, GoShippo, QuickBooks Online, Square and Shopify. In the web app they are under Settings > Apps.\n\nEach shows its `type`, `subtype`, `label` and `status`. Check `status` before relying on one: `REAUTH` means someone has to sign in to the provider again. (Answers call it `subtype`; the Search filter key is `sub_type`.) Shopify stores appear only when your plan includes Shopify. Retired integrations (FedEx, UPS, AlphaBroder, Delta Apparel) are left out; find them with \"Search integrations\". A removed Shopify store still waiting to be deleted is included, with `trashed: true`.\n\nSupplier passwords are not in this list. For one integration's settings, get it by id.","operationId":"v1_public_external_integration_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"data":[],"deprecated":false,"has_logs":false,"id":"d9ZxWgBz09mDFq","integration_check_key":"sanmar","label":"SanMar Integration","last_sync":null,"last_token_refresh":null,"option":[],"status":"ENABLED","subtype":"sanmar_v1","trashed":false,"type":"supplier"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"data":{"additionalProperties":true,"type":["object","array","null"]},"deprecated":{"description":"A retired integration: it can only be deleted.","type":"boolean"},"has_logs":{"description":"Whether it keeps a log of sync errors: true for QuickBooks Online only.","type":"boolean"},"id":{"example":"d9ZxWgBz09mDFq","type":"string"},"integration_check_key":{"description":"A fixed key for the kind of integration, such as `sanmar` or `shopify`.","example":"sanmar","type":"string"},"label":{"example":"SanMar Integration","type":"string"},"last_sync":{"format":"date-time","type":["string","null"]},"last_token_refresh":{"format":"date-time","type":["string","null"]},"option":{"additionalProperties":true,"description":"The integration's settings, which differ by type.","type":["object","array","null"]},"shopify_admin_app_url":{"description":"Shopify only.","type":["string","null"]},"shopify_admin_settings_apps_url":{"description":"Shopify only: the store's apps settings page, where the app is uninstalled.","type":["string","null"]},"shopify_admin_url":{"description":"Shopify only: the YoPrint app in the store's Shopify admin. Same as `shopify_admin_app_url`.","type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"description":"Shopify only: where a store data deletion requested by Shopify stands, or null.","type":["object","null"]},"status":{"description":"For example `ENABLED`, `ACTION_REQUIRED`, `REAUTH` (sign in to the provider again), `UNINITIALIZED` (set up but not configured yet) or `DISABLED`.","example":"ENABLED","type":"string"},"subtype":{"description":"Which integration, for example `sanmar_v1`. The same value goes in the create path.","example":"sanmar_v1","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"The kind: `supplier`, `sms` (Twilio), `shipment_v1` (GoShippo), `data_sync` (QuickBooks Online, Shopify), `payment_gateway` (Square), `shipment` (retired FedEx and UPS).","enum":["supplier","sms","shipment_v1","data_sync","payment_gateway","shipment"],"type":"string"}},"required":["id","deprecated","trashed","type","subtype","label","status","has_logs"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List integrations","tags":["Integrations"],"x-yoprint-docs":{"group":"Team settings","permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it. AI apps (MCP connections) need Manage Settings to read it.","related":["v1_public_external_integration_show","v1_public_external_integration_store","v1_public_external_integration_filter"]}}},"/v1/api/store/{team_slug}/setting/external_integration/filter":{"post":{"description":"Returns the team's integrations that match `filters`, a page at a time (the team's page size, 50 by default). Each filter is `{key, operator, value}`:\n\n- `label`, `type`, `sub_type` (the answers' `subtype`), `status`: text, with `eq`, `neq`, `ct` (contains), `sw` (starts with) or `ew` (ends with).\n- `trashed_only`: `true` or `false`, with `eq` or `neq`, to list deleted integrations.\n\nShopify stores are left out when your plan doesn't include Shopify. It changes nothing, but as a POST it needs Manage Settings.","operationId":"v1_public_external_integration_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"filters":[{"key":"type","operator":"eq","value":"supplier"}]},"schema":{"additionalProperties":false,"properties":{"filters":{"items":{"additionalProperties":false,"properties":{"key":{"enum":["trashed_only","label","type","sub_type","status"],"type":"string"},"operator":{"enum":["eq","neq","ct","sw","ew"],"type":"string"},"value":{"type":["string","boolean"]}},"required":["key","operator","value"],"type":"object"},"minItems":1,"type":"array"},"sort":{"description":"Optional sort.","items":{"additionalProperties":true,"type":"object"},"type":"array"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"data":[],"deprecated":false,"has_logs":false,"id":"d9ZxWgBz09mDFq","integration_check_key":"sanmar","label":"SanMar Integration","last_sync":null,"last_token_refresh":null,"option":[],"status":"ENABLED","subtype":"sanmar_v1","trashed":false,"type":"supplier"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"data":{"additionalProperties":true,"type":["object","array","null"]},"deprecated":{"description":"A retired integration: it can only be deleted.","type":"boolean"},"has_logs":{"description":"Whether it keeps a log of sync errors: true for QuickBooks Online only.","type":"boolean"},"id":{"example":"d9ZxWgBz09mDFq","type":"string"},"integration_check_key":{"description":"A fixed key for the kind of integration, such as `sanmar` or `shopify`.","example":"sanmar","type":"string"},"label":{"example":"SanMar Integration","type":"string"},"last_sync":{"format":"date-time","type":["string","null"]},"last_token_refresh":{"format":"date-time","type":["string","null"]},"option":{"additionalProperties":true,"description":"The integration's settings, which differ by type.","type":["object","array","null"]},"shopify_admin_app_url":{"description":"Shopify only.","type":["string","null"]},"shopify_admin_settings_apps_url":{"description":"Shopify only: the store's apps settings page, where the app is uninstalled.","type":["string","null"]},"shopify_admin_url":{"description":"Shopify only: the YoPrint app in the store's Shopify admin. Same as `shopify_admin_app_url`.","type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"description":"Shopify only: where a store data deletion requested by Shopify stands, or null.","type":["object","null"]},"status":{"description":"For example `ENABLED`, `ACTION_REQUIRED`, `REAUTH` (sign in to the provider again), `UNINITIALIZED` (set up but not configured yet) or `DISABLED`.","example":"ENABLED","type":"string"},"subtype":{"description":"Which integration, for example `sanmar_v1`. The same value goes in the create path.","example":"sanmar_v1","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"The kind: `supplier`, `sms` (Twilio), `shipment_v1` (GoShippo), `data_sync` (QuickBooks Online, Shopify), `payment_gateway` (Square), `shipment` (retired FedEx and UPS).","enum":["supplier","sms","shipment_v1","data_sync","payment_gateway","shipment"],"type":"string"}},"required":["id","deprecated","trashed","type","subtype","label","status","has_logs"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Search integrations","tags":["Integrations"],"x-yoprint-docs":{"errors":[{"fix":"Use the keys and operators listed above.","status":422,"when":"A filter has an unknown `key`, or a value or operator that doesn't fit it (`validation_failed`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_external_integration_index"]}}},"/v1/api/store/{team_slug}/setting/external_integration/retry_action/{id}":{"patch":{"description":"**Internal.** Built for YoPrint's own apps, not for integrations. Don't build on it.\n\nAsks YoPrint to retry the step behind one error log entry. The `{id}` is the log entry's id, not the integration's.\n\nIn practice nothing is retried today: no log entry is marked retryable, so the call succeeds without doing anything (200, `data: null`). QuickBooks entries are refused.","operationId":"v1_public_external_integration_retry_action","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The error log entry (not the integration), from the integration's error log. Its hash id from an earlier answer; there is no unique key for it.","example":"i91i7ESuTjjC9i","in":"path","name":"id","required":true,"schema":{"example":"i91i7ESuTjjC9i","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Retry a logged integration error","tags":["Integrations"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Use an id from the error log.","status":404,"when":"No log entry of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Fix the cause in QuickBooks or YoPrint and sync again.","status":500,"when":"The entry belongs to QuickBooks Online: `error.code` `cannot retry for quickbook`."},{"fix":"Upgrade the plan.","status":422,"when":"The entry's integration is not in your plan (`plan_limitation`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_external_integration_logs"],"status":"internal"},"x-internal":true}},"/v1/api/store/{team_slug}/setting/external_integration/shopify/finalize-install":{"post":{"description":"**Internal.** Built for YoPrint's own apps, not for integrations. Don't build on it.\n\nBuilt for YoPrint's web app. After a store owner installs YoPrint from the Shopify admin and picks this team, it turns the pending install (`install_token`) into the team's Shopify integration. Returns the integration.","operationId":"v1_public_external_integration_shopify_finalize_install","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"install_token":"YOUR_INSTALL_TOKEN"},"schema":{"additionalProperties":false,"properties":{"install_token":{"description":"The pending install's token, from the install flow.","type":"string"}},"required":["install_token"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"data":{"currencyCode":"USD","domain":"example.myshopify.com","gid":"gid://shopify/Shop/1001","id":"gid://shopify/Shop/1001","myshopifyDomain":"example.myshopify.com","name":"Northwind Apparel","shop_domain":"example.myshopify.com","shop_url":"example.myshopify.com","url":"https://example.myshopify.com"},"deprecated":false,"has_logs":false,"id":"aDFOUrmqetFJaN","integration_check_key":"shopify","label":"Shopify","last_sync":null,"last_token_refresh":"2026-11-03T09:00:00+00:00","option":[],"shopify_admin_app_url":"https://example.com/shopify-admin/apps/yoprint","shopify_admin_settings_apps_url":"https://example.com/shopify-admin/settings/apps","shopify_admin_url":"https://example.com/shopify-admin/apps/yoprint","shopify_compliance_deletion":null,"status":"UNINITIALIZED","subtype":"shopify_v1","trashed":false,"type":"data_sync"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"data":{"additionalProperties":true,"type":["object","array","null"]},"deprecated":{"description":"A retired integration: it can only be deleted.","type":"boolean"},"has_logs":{"description":"Whether it keeps a log of sync errors: true for QuickBooks Online only.","type":"boolean"},"id":{"example":"d9ZxWgBz09mDFq","type":"string"},"integration_check_key":{"description":"A fixed key for the kind of integration, such as `sanmar` or `shopify`.","example":"sanmar","type":"string"},"label":{"example":"SanMar Integration","type":"string"},"last_sync":{"format":"date-time","type":["string","null"]},"last_token_refresh":{"format":"date-time","type":["string","null"]},"option":{"additionalProperties":true,"description":"The integration's settings, which differ by type.","type":["object","array","null"]},"shopify_admin_app_url":{"description":"Shopify only.","type":["string","null"]},"shopify_admin_settings_apps_url":{"description":"Shopify only: the store's apps settings page, where the app is uninstalled.","type":["string","null"]},"shopify_admin_url":{"description":"Shopify only: the YoPrint app in the store's Shopify admin. Same as `shopify_admin_app_url`.","type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"description":"Shopify only: where a store data deletion requested by Shopify stands, or null.","type":["object","null"]},"status":{"description":"For example `ENABLED`, `ACTION_REQUIRED`, `REAUTH` (sign in to the provider again), `UNINITIALIZED` (set up but not configured yet) or `DISABLED`.","example":"ENABLED","type":"string"},"subtype":{"description":"Which integration, for example `sanmar_v1`. The same value goes in the create path.","example":"sanmar_v1","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"The kind: `supplier`, `sms` (Twilio), `shipment_v1` (GoShippo), `data_sync` (QuickBooks Online, Shopify), `payment_gateway` (Square), `shipment` (retired FedEx and UPS).","enum":["supplier","sms","shipment_v1","data_sync","payment_gateway","shipment"],"type":"string"}},"required":["id","deprecated","trashed","type","subtype","label","status","has_logs"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Finish a Shopify install","tags":["Integrations"],"x-yoprint-docs":{"errors":[{"fix":"Send the token from the install flow.","status":422,"when":"`install_token` is missing (`validation_failed`)."},{"fix":"Start the install again from the Shopify admin.","status":422,"when":"The install can't be finished: `error.code` `pending_install_not_found`, `pending_install_expired` or `pending_install_not_ready`."},{"fix":"Read `error.message`; upgrade the plan, wait, or disconnect the store from the other team first.","status":422,"when":"`plan_limitation` (Shopify is not in your plan), `shopify_store_limit_reached`, `shopify_store_deletion_in_progress`, or `shopify_store_already_connected_other_team`."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_external_integration_shopify_verify_signature","v1_public_external_integration_index"],"side_effects":["Connects the Shopify store to the team."],"status":"internal"},"x-internal":true}},"/v1/api/store/{team_slug}/setting/external_integration/shopify/verify-signature":{"post":{"description":"**Internal.** Built for YoPrint's own apps, not for integrations. Don't build on it.\n\nBuilt for YoPrint's web app, during a Shopify install that starts from the Shopify admin. It checks that the query string Shopify sent (`shopify_signature`, the raw query string with its `hmac`) is signed by Shopify for YoPrint's app. Returns `{\"valid\": true}` or 401.","operationId":"v1_public_external_integration_shopify_verify_signature","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"shopify_signature":"shop=example.myshopify.com&timestamp=1700000000&hmac=EXAMPLE"},"schema":{"additionalProperties":false,"properties":{"shopify_signature":{"description":"The query string Shopify added to the install link.","type":"string"}},"required":["shopify_signature"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"message":"Shopify signature is valid","valid":true},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"message":{"const":"Shopify signature is valid","type":"string"},"valid":{"const":true,"type":"boolean"}},"required":["message","valid"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Check a Shopify install signature","tags":["Integrations"],"x-yoprint-docs":{"errors":[{"fix":"Start the install again from the Shopify admin.","status":401,"when":"The signature doesn't match (`invalid_signature`)."},{"fix":"Send the query string Shopify added.","status":422,"when":"`shopify_signature` is missing or not a string (`validation_failed`)."},{"fix":"Start the install again.","status":500,"when":"The signature could not be checked (`signature_verification_error`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_external_integration_shopify_finalize_install"],"status":"internal"},"x-internal":true}},"/v1/api/store/{team_slug}/setting/external_integration/{external_integration_reference}":{"delete":{"description":"Disconnects an integration. What happens depends on the type:\n\n- **Suppliers and Twilio**: removed from YoPrint, with their saved credentials.\n- **GoShippo**: turned off (`status: DISABLED`) and its shipping methods are deleted. Refused while a shipment package from it is not yet delivered.\n- **Square** and **QuickBooks Online**: YoPrint revokes its access at the provider, then removes it. A Square connection still waiting for a transfer from another team is removed without revoking.\n- **Shopify**: can't be disconnected here. The call answers 422 `shopify_uninstall_from_shopify_required` with links in `error.shopify_admin_url` and `error.shopify_admin_settings_apps_url`: uninstall the app in the Shopify admin.\n\nRetired integrations can be deleted too; find them with \"Search integrations\", since the list leaves them out. The answer is 200 with `data: null`.","operationId":"v1_public_external_integration_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The integration, from the integration list. Its hash id from an earlier answer; there is no unique key for it.","example":"d9ZxWgBz09mDFq","in":"path","name":"external_integration_reference","required":true,"schema":{"example":"d9ZxWgBz09mDFq","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Disconnect an integration","tags":["Integrations"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the list.","status":404,"when":"No integration of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Wait for the packages to be delivered.","status":422,"when":"`error.code` `has_existing_packages`: GoShippo still has packages not yet delivered. Or `plan_limitation`: the integration is not in your plan."},{"fix":"Uninstall the YoPrint app in the store's Shopify admin.","status":422,"when":"Shopify: `shopify_uninstall_from_shopify_required`, with `error.shopify_admin_url`, `error.shopify_admin_app_url` and `error.shopify_admin_settings_apps_url`."},{"fix":"Read the integration again, then retry.","status":500,"when":"The delete itself failed: `error.code` `delete_fail`."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_external_integration_index","v1_public_external_integration_store"],"side_effects":["Square and QuickBooks Online: calls the provider to revoke YoPrint's access.","Team members who have YoPrint open see the change at once."]}},"get":{"description":"Returns one integration with its settings. What comes back depends on the type:\n\n- Suppliers add the account they are connected with: `user` (and `account_number` for SanMar). AS Colour adds only `email`. Supplier passwords and AS Colour's API key are never returned.\n- Twilio adds `selected_phone_number`, `sms_not_supported_msg` and `webhook_url`. The stored Account SID and auth token are never returned.\n- GoShippo adds `webhook_url`, `label_size`, `shipping_phone_number`, the allowed `valid_label_size` values and `carrier_enum`. `goshippo_token` is always null: the stored GoShippo sign-in is never returned.\n- QuickBooks Online and Square put their settings in `option`. A QuickBooks `option.setting.payment_deposit_account_id.value` reads `\"\"` (let QuickBooks decide) until one is chosen, and `sync_invoice_payment` reads false while `sync_invoice` is off. Shopify adds links to the store's Shopify admin.\n\nA retired integration answers 422 `integration_deprecated`: delete it.","operationId":"v1_public_external_integration_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The integration, from the integration list. Its hash id from an earlier answer; there is no unique key for it.","example":"d9ZxWgBz09mDFq","in":"path","name":"external_integration_reference","required":true,"schema":{"example":"d9ZxWgBz09mDFq","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_number":"123456","data":[],"deprecated":false,"has_logs":false,"id":"d9ZxWgBz09mDFq","integration_check_key":"sanmar","label":"SanMar Integration","last_sync":null,"last_token_refresh":null,"option":[],"status":"ENABLED","subtype":"sanmar_v1","trashed":false,"type":"supplier","user":"YOUR_SUPPLIER_USERNAME"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"data":{"additionalProperties":true,"type":["object","array","null"]},"deprecated":{"description":"A retired integration: it can only be deleted.","type":"boolean"},"has_logs":{"description":"Whether it keeps a log of sync errors: true for QuickBooks Online only.","type":"boolean"},"id":{"example":"d9ZxWgBz09mDFq","type":"string"},"integration_check_key":{"description":"A fixed key for the kind of integration, such as `sanmar` or `shopify`.","example":"sanmar","type":"string"},"label":{"example":"SanMar Integration","type":"string"},"last_sync":{"format":"date-time","type":["string","null"]},"last_token_refresh":{"format":"date-time","type":["string","null"]},"option":{"additionalProperties":true,"description":"The integration's settings, which differ by type.","type":["object","array","null"]},"shopify_admin_app_url":{"description":"Shopify only.","type":["string","null"]},"shopify_admin_settings_apps_url":{"description":"Shopify only: the store's apps settings page, where the app is uninstalled.","type":["string","null"]},"shopify_admin_url":{"description":"Shopify only: the YoPrint app in the store's Shopify admin. Same as `shopify_admin_app_url`.","type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"description":"Shopify only: where a store data deletion requested by Shopify stands, or null.","type":["object","null"]},"status":{"description":"For example `ENABLED`, `ACTION_REQUIRED`, `REAUTH` (sign in to the provider again), `UNINITIALIZED` (set up but not configured yet) or `DISABLED`.","example":"ENABLED","type":"string"},"subtype":{"description":"Which integration, for example `sanmar_v1`. The same value goes in the create path.","example":"sanmar_v1","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"The kind: `supplier`, `sms` (Twilio), `shipment_v1` (GoShippo), `data_sync` (QuickBooks Online, Shopify), `payment_gateway` (Square), `shipment` (retired FedEx and UPS).","enum":["supplier","sms","shipment_v1","data_sync","payment_gateway","shipment"],"type":"string"}},"required":["id","deprecated","trashed","type","subtype","label","status","has_logs"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get an integration","tags":["Integrations"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the list.","status":404,"when":"No integration of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Delete a retired one; reconnect GoShippo or Square in Settings > Apps.","status":422,"when":"`error.code` is `integration_deprecated` (retired), `plan_limitation` (Shopify is not in your plan), or `integration_reauth` (GoShippo or Square needs signing in again)."},{"fix":"Try again later, or confirm the move with the `transfer_confirm` action.","status":422,"when":"Square: `integration_offline` (Square can't be reached), or `integration_transfer_pending` (this Square account is connected to another YoPrint team; `error.connected_team_name` names it and `error.same_name` says whether the two team names match)."},{"fix":"Set them with \"Update an integration\".","status":422,"when":"Shopify: `integration_uninitialized` (its default addresses and warehouse aren't set yet)."}],"group":"Team settings","permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_external_integration_update_patch","v1_public_external_integration_index"]}},"patch":{"description":"Changes an integration's settings or credentials. What you send depends on its type:\n\n- **Suppliers**: the full credentials again, as when connecting (SanMar `account_number`, `user`, `pass`; AS Colour `email`, `password`; the others `user`, `pass`). YoPrint checks them with the supplier and saves only if accepted.\n- **Twilio**: `selected_phone_number`, one of your Twilio numbers (read them with the data call, `type: phone_numbers`; YoPrint doesn't check it), and optionally `sms_not_supported_msg`, the reply sent to anyone who texts that number. The credentials can't change here; delete and connect again.\n- **GoShippo**: `label_size` (`PDF`, `PDF_2.3x7.5`, `PDF_4x6`, `PDF_4x8`, `PDF_A4` or `PDF_A6`) and `shipping_phone_number`. YoPrint checks the GoShippo connection first.\n- **QuickBooks Online**: `account`, `tax` and `setting`, each value wrapped as `{\"value\": ...}`. YoPrint checks the accounts and tax codes with QuickBooks first, and reads a new `payment_deposit_account_id` from QuickBooks before saving it.\n- **Square**: `webhook_listen_to_location`, `web_location_id` and `enable_customer_portal_payment`.\n- **Shopify**: `default` (billing address, shipping address and warehouse, all required, plus optional payment method, order prefix and QuickBooks opt-out) and `setting` (sync choices).\n\nPUT and PATCH do the same. Returns the integration, as \"Get an integration\" does.","operationId":"v1_public_external_integration_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The integration, from the integration list. Its hash id from an earlier answer; there is no unique key for it.","example":"d9ZxWgBz09mDFq","in":"path","name":"external_integration_reference","required":true,"schema":{"example":"d9ZxWgBz09mDFq","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"goshippo":{"summary":"GoShippo label size","value":{"label_size":"PDF_4x6"},"x-yoprint-variant":"GoShippo"},"supplier":{"summary":"New S&S Activewear password","value":{"pass":"YOUR_PASSWORD","user":"YOUR_SUPPLIER_USERNAME"},"x-yoprint-variant":"S&S Activewear, SanMar Canada or Momentec"},"twilio":{"summary":"Twilio sending number","value":{"selected_phone_number":"+12015550123","sms_not_supported_msg":"We don't answer texts. Please email us."},"x-yoprint-variant":"Twilio"}},"schema":{"anyOf":[{"additionalProperties":false,"description":"Path `sanmar_v1`. Your SanMar web services account.","properties":{"account_number":{"description":"Your SanMar customer number.","type":"string"},"pass":{"description":"Your password with the supplier. It is never returned.","type":"string"},"user":{"description":"Your username with the supplier.","type":"string"}},"required":["account_number","user","pass"],"title":"SanMar","type":"object"},{"additionalProperties":false,"description":"Paths `ssa_v1`, `ssa_ca_v1`, `sanmar_ca_v1`, `momentec_v2` (Augusta Sportswear) and `momentec_ca_v2`.","properties":{"pass":{"description":"Your password with the supplier. It is never returned.","type":"string"},"user":{"description":"Your username with the supplier.","type":"string"}},"required":["user","pass"],"title":"S&S Activewear, SanMar Canada or Momentec","type":"object"},{"additionalProperties":false,"description":"Path `ascolour_v1`. Your AS Colour account sign-in.","properties":{"email":{"format":"email","type":"string"},"password":{"description":"Never returned.","type":"string"}},"required":["email","password"],"title":"AS Colour","type":"object"},{"additionalProperties":false,"description":"The sending number and the auto-reply.","properties":{"selected_phone_number":{"description":"One of the numbers on your Twilio account, as Twilio formats it.","type":"string"},"sms_not_supported_msg":{"description":"The reply sent to anyone who texts this number. Empty keeps the current one.","type":"string"}},"required":["selected_phone_number"],"title":"Twilio","type":"object"},{"additionalProperties":false,"description":"Label size and the phone number on labels.","properties":{"label_size":{"enum":["PDF","PDF_2.3x7.5","PDF_4x6","PDF_4x8","PDF_A4","PDF_A6"],"type":"string"},"shipping_phone_number":{"type":"string"}},"title":"GoShippo","type":"object"},{"additionalProperties":true,"description":"Account and tax mapping, and sync choices. Each setting is an object with a `value`. Send the parts you change.","properties":{"account":{"additionalProperties":true,"description":"QuickBooks account ids, from the `account` data call.","properties":{"default_tax":{"additionalProperties":false,"description":"The default tax code. `value` must be present; empty clears it.","properties":{"value":{"type":"string"}},"required":["value"],"type":"object"},"purchase_order_line_expense":{"additionalProperties":false,"description":"The expense account for purchase order lines.","properties":{"value":{"type":"string"}},"required":["value"],"type":"object"},"sales":{"additionalProperties":false,"description":"The income account for sales.","properties":{"value":{"type":"string"}},"required":["value"],"type":"object"}},"type":"object"},"setting":{"additionalProperties":true,"properties":{"invoice_date_field":{"additionalProperties":false,"description":"Which date becomes the QuickBooks invoice date.","properties":{"value":{"enum":["issue_date","cust_due_date"],"type":"string"}},"required":["value"],"type":"object"},"invoice_deleted_automatic_sync":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"invoice_due_date_field":{"additionalProperties":false,"description":"Which date becomes its due date.","properties":{"value":{"enum":["due_date","full_amount_due"],"type":"string"}},"required":["value"],"type":"object"},"invoice_updated_automatic_sync":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"payment_deposit_account_id":{"additionalProperties":false,"description":"Where new QuickBooks Payments are recorded: a QuickBooks account id (digits, up to 64), or `\"\"` to let QuickBooks decide. A new account must be an active Bank or Other Current Asset account in your shop's default currency, and not an inventory or prepaid expense account; YoPrint reads it from QuickBooks to check. Payments already in QuickBooks keep their account.","properties":{"value":{"maxLength":64,"type":["string","null"]}},"required":["value"],"type":"object"},"purchase_order_created_automatic_sync":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"purchase_order_deleted_automatic_sync":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"purchase_order_sync_as_bill":{"additionalProperties":false,"description":"Sync purchase orders as bills.","properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"purchase_order_updated_automatic_sync":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"sync_invoice":{"additionalProperties":false,"description":"Sync invoices. Saved off, it turns payment sync off too.","properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"sync_invoice_payment":{"additionalProperties":false,"description":"Sync payments. Payments ride on their invoices: while `sync_invoice` is off this is stored and read as false, and turning invoice sync back on leaves it off until you turn it on.","properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"sync_purchase_order":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"}},"type":"object"},"tax":{"description":"Pairs your tax presets with QuickBooks tax codes.","items":{"additionalProperties":false,"properties":{"id":{"description":"A tax preset's id.","type":"string"},"value":{"description":"A QuickBooks tax code id, from the `tax` data call. Empty removes the pairing.","type":"string"}},"required":["id","value"],"type":"object"},"type":"array"}},"title":"QuickBooks Online","type":"object"},{"additionalProperties":true,"description":"Which locations Square payments are listened for, and the customer portal payment option. Other keys you send are saved in `option` as they are.","properties":{"enable_customer_portal_payment":{"type":"boolean"},"web_location_id":{"description":"The Square location online payments go to.","type":"string"},"webhook_listen_to_location":{"items":{"additionalProperties":true,"properties":{"id":{"description":"A Square location id.","type":"string"}},"type":"object"},"type":"array"}},"title":"Square","type":"object"},{"additionalProperties":true,"description":"How Shopify orders come into YoPrint. `default` must name the billing address, shipping address and warehouse each time.","properties":{"default":{"additionalProperties":true,"properties":{"billing_address_id":{"description":"One of your team's addresses (locations).","type":"string"},"order_prefix":{"maxLength":255,"type":["string","null"]},"payment_method_id":{"description":"A payment method, or null.","type":["string","null"]},"quickbook_disable_sync":{"description":"Keep these orders out of QuickBooks.","type":["boolean","null"]},"shipping_address_id":{"description":"One of your team's addresses.","type":"string"},"warehouse_id":{"description":"One of your team's addresses, used as the warehouse.","type":"string"}},"required":["billing_address_id","shipping_address_id","warehouse_id"],"type":"object"},"setting":{"additionalProperties":true,"properties":{"auto_sync":{"type":["boolean","null"]},"manually_sync":{"type":["boolean","null"]},"notify_user_on_shipment_sync":{"enum":["notify_always","notify_ask","notify_never",null],"type":["string","null"]},"shipments_auto_sync":{"type":["boolean","null"]},"terminal_order_policy":{"description":"What happens to the YoPrint order when its Shopify order is cancelled or deleted.","enum":["delete_synced_order","preserve_mark_deleted",null],"type":["string","null"]}},"type":"object"}},"required":["default"],"title":"Shopify","type":"object"}],"title":"Which integration are you updating?"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"data":[],"deprecated":false,"has_logs":false,"id":"ZnLL4KKEIfEAfb","integration_check_key":"ssa","label":"S&SActiveWear Integration","last_sync":null,"last_token_refresh":null,"option":[],"status":"ENABLED","subtype":"ssa_v1","trashed":false,"type":"supplier","user":"YOUR_SUPPLIER_USERNAME"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"data":{"additionalProperties":true,"type":["object","array","null"]},"deprecated":{"description":"A retired integration: it can only be deleted.","type":"boolean"},"has_logs":{"description":"Whether it keeps a log of sync errors: true for QuickBooks Online only.","type":"boolean"},"id":{"example":"d9ZxWgBz09mDFq","type":"string"},"integration_check_key":{"description":"A fixed key for the kind of integration, such as `sanmar` or `shopify`.","example":"sanmar","type":"string"},"label":{"example":"SanMar Integration","type":"string"},"last_sync":{"format":"date-time","type":["string","null"]},"last_token_refresh":{"format":"date-time","type":["string","null"]},"option":{"additionalProperties":true,"description":"The integration's settings, which differ by type.","type":["object","array","null"]},"shopify_admin_app_url":{"description":"Shopify only.","type":["string","null"]},"shopify_admin_settings_apps_url":{"description":"Shopify only: the store's apps settings page, where the app is uninstalled.","type":["string","null"]},"shopify_admin_url":{"description":"Shopify only: the YoPrint app in the store's Shopify admin. Same as `shopify_admin_app_url`.","type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"description":"Shopify only: where a store data deletion requested by Shopify stands, or null.","type":["object","null"]},"status":{"description":"For example `ENABLED`, `ACTION_REQUIRED`, `REAUTH` (sign in to the provider again), `UNINITIALIZED` (set up but not configured yet) or `DISABLED`.","example":"ENABLED","type":"string"},"subtype":{"description":"Which integration, for example `sanmar_v1`. The same value goes in the create path.","example":"sanmar_v1","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"The kind: `supplier`, `sms` (Twilio), `shipment_v1` (GoShippo), `data_sync` (QuickBooks Online, Shopify), `payment_gateway` (Square), `shipment` (retired FedEx and UPS).","enum":["supplier","sms","shipment_v1","data_sync","payment_gateway","shipment"],"type":"string"}},"required":["id","deprecated","trashed","type","subtype","label","status","has_logs"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update an integration (same as PUT)","tags":["Integrations"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the list.","status":404,"when":"No integration of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Check the credentials, or reconnect GoShippo in Settings > Apps.","status":422,"when":"The supplier rejected the credentials, or GoShippo's connection failed: `error.code` `invalid_key`. A supplier that can't be reached gives `credential_check_unavailable`."},{"fix":"Send the fields listed for this type.","status":422,"when":"A required field is missing or not allowed (`validation_failed`), for example a Shopify update without the three `default` ids."},{"fix":"Confirm the move with the `transfer_confirm` action first.","status":422,"when":"Square: this Square account is connected to another YoPrint team (`integration_transfer_pending`)."},{"fix":"Pick a bank or other current asset account from the `account` data call, or send `\"\"`.","status":422,"when":"QuickBooks Online: the `payment_deposit_account_id` is refused (`validation_failed`, on `setting.payment_deposit_account_id.value`): \"Choose a QuickBooks account.\", \"QuickBooks could not confirm this account. Check the connection and try again.\", \"Choose an active bank or other current asset account in your shop currency.\" or the inventory or prepaid expense message. Nothing is saved."},{"fix":"Upgrade the plan, or use another integration.","status":422,"when":"The integration is not in your plan (`plan_limitation`)."},{"fix":"Delete it and connect an alternative.","status":422,"when":"The integration is retired (`integration_deprecated`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","patch":"same_as_put","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_external_integration_show","v1_public_external_integration_data"],"rules":["Supplier credentials are saved only after the supplier accepts them; until then the old ones stay."],"side_effects":["Suppliers: calls the supplier to check the credentials.","GoShippo: calls GoShippo to check the connection.","Twilio: changes the number YoPrint texts customers from, and the auto-reply on it.","QuickBooks Online: reads your accounts and tax codes from QuickBooks to check the mapping, and a newly chosen deposit account.","QuickBooks Online: when the save turns the connection on with payment sync, or turns payment sync on, customer portal payments that were waiting for QuickBooks are picked up again at the next payment sync.","Shopify: the integration is `ENABLED` once the three `default` ids are set, `UNINITIALIZED` otherwise."]}},"post":{"description":"Connects an integration. The last path segment is the integration's subtype, for example `POST /v1/api/store/{team_slug}/setting/external_integration/sanmar_v1`.\n\n**Suppliers and Twilio take credentials.** YoPrint checks them with the provider before saving, so the call waits for the provider's answer. If the provider rejects them you get 422 `invalid_key` and nothing is saved. The answer never contains them: supplier passwords, AS Colour's API key and Twilio's Account SID and auth token are not returned.\n\n| Subtype | Integration | Body |\n| --- | --- | --- |\n| `sanmar_v1` | SanMar | `account_number`, `user`, `pass` |\n| `sanmar_ca_v1` | SanMar Canada | `user`, `pass` |\n| `ssa_v1`, `ssa_ca_v1` | S&S Activewear, S&S Activewear Canada | `user`, `pass` |\n| `momentec_v2`, `momentec_ca_v2` | Momentec (Augusta Sportswear), Momentec Canada | `user`, `pass` |\n| `ascolour_v1` | AS Colour | `email`, `password` |\n| `twillio_v1` | Twilio | `account_sid`, `auth_token` |\n\n**GoShippo (`goshippo_v1`), QuickBooks Online (`quickbook_v1`) and Square (`square_v2`) connect through the provider's sign-in, in YoPrint's web app.** The call returns `{\"type\": \"oauth\", \"url\": \"...\"}`, but the `url` is a YoPrint connect link that only the web app can use: opened in a browser tab or from a script it shows a refusal page and connects nothing. To connect one of these, a person who can manage settings clicks Connect in Settings > Apps.\n\n**Shopify** is installed from the Shopify admin, never here (422 `shopify_install_from_shopify_required`). FedEx (`fedex_v1`), UPS (`ups_v1`), AlphaBroder (`alphabroder_v1`, `alphabroder_ca_v1`) and Delta Apparel (`deltapp_v1`) are retired (422 `integration_deprecated`).","operationId":"v1_public_external_integration_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The subtype of the integration to connect. Retired ones (`fedex_v1`, `ups_v1`, `alphabroder_v1`, `alphabroder_ca_v1`, `deltapp_v1`) answer 422, and `shopify_v1` is installed from Shopify.","example":"sanmar_v1","in":"path","name":"external_integration_reference","required":true,"schema":{"enum":["sanmar_v1","sanmar_ca_v1","ssa_v1","ssa_ca_v1","momentec_v2","momentec_ca_v2","ascolour_v1","twillio_v1","goshippo_v1","quickbook_v1","square_v2","shopify_v1","fedex_v1","ups_v1","alphabroder_v1","alphabroder_ca_v1","deltapp_v1"],"example":"sanmar_v1","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"ascolour":{"summary":"AS Colour","value":{"email":"alex@example.com","password":"YOUR_PASSWORD"},"x-yoprint-variant":"AS Colour"},"oauth":{"summary":"GoShippo (POST .../external_integration/goshippo_v1)","value":{},"x-yoprint-variant":"Provider sign-in (GoShippo, QuickBooks Online, Square)"},"sanmar":{"summary":"SanMar","value":{"account_number":"123456","pass":"YOUR_PASSWORD","user":"YOUR_SUPPLIER_USERNAME"},"x-yoprint-variant":"SanMar"},"twilio":{"summary":"Twilio","value":{"account_sid":"YOUR_TWILIO_ACCOUNT_SID","auth_token":"YOUR_TWILIO_AUTH_TOKEN"},"x-yoprint-variant":"Twilio"},"user_pass":{"summary":"S&S Activewear (POST .../external_integration/ssa_v1)","value":{"pass":"YOUR_PASSWORD","user":"YOUR_SUPPLIER_USERNAME"},"x-yoprint-variant":"S&S Activewear, SanMar Canada or Momentec"}},"schema":{"oneOf":[{"additionalProperties":false,"description":"Path `sanmar_v1`. Your SanMar web services account.","properties":{"account_number":{"description":"Your SanMar customer number.","type":"string"},"pass":{"description":"Your password with the supplier. It is never returned.","type":"string"},"user":{"description":"Your username with the supplier.","type":"string"}},"required":["account_number","user","pass"],"title":"SanMar","type":"object"},{"additionalProperties":false,"description":"Paths `ssa_v1`, `ssa_ca_v1`, `sanmar_ca_v1`, `momentec_v2` (Augusta Sportswear) and `momentec_ca_v2`.","properties":{"pass":{"description":"Your password with the supplier. It is never returned.","type":"string"},"user":{"description":"Your username with the supplier.","type":"string"}},"required":["user","pass"],"title":"S&S Activewear, SanMar Canada or Momentec","type":"object"},{"additionalProperties":false,"description":"Path `ascolour_v1`. Your AS Colour account sign-in.","properties":{"email":{"format":"email","type":"string"},"password":{"description":"Never returned.","type":"string"}},"required":["email","password"],"title":"AS Colour","type":"object"},{"additionalProperties":false,"description":"Path `twillio_v1` (spelled with two l's). Your Twilio account, for text messages.","properties":{"account_sid":{"description":"Your Twilio Account SID.","type":"string"},"auth_token":{"description":"Your Twilio auth token.","type":"string"}},"required":["account_sid","auth_token"],"title":"Twilio","type":"object"},{"additionalProperties":false,"description":"Paths `goshippo_v1`, `quickbook_v1` and `square_v2`. Send no fields; the answer is a link to sign in at the provider.","properties":{},"title":"Provider sign-in (GoShippo, QuickBooks Online, Square)","type":"object"}],"title":"Which integration are you connecting?"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_number":"123456","data":[],"deprecated":false,"has_logs":false,"id":"d9ZxWgBz09mDFq","integration_check_key":"sanmar","label":"SanMar Integration","last_sync":null,"last_token_refresh":null,"option":[],"status":"ENABLED","subtype":"sanmar_v1","trashed":false,"type":"supplier","user":"YOUR_SUPPLIER_USERNAME"},"status":200,"success":true},"schema":{"properties":{"data":{"oneOf":[{"additionalProperties":true,"description":"As \"Get an integration\" returns it. No stored credential is in it: supplier passwords, Twilio's Account SID and auth token, the GoShippo sign-in and AS Colour's API key are never returned.","properties":{"data":{"additionalProperties":true,"type":["object","array","null"]},"deprecated":{"description":"A retired integration: it can only be deleted.","type":"boolean"},"has_logs":{"description":"Whether it keeps a log of sync errors: true for QuickBooks Online only.","type":"boolean"},"id":{"example":"d9ZxWgBz09mDFq","type":"string"},"integration_check_key":{"description":"A fixed key for the kind of integration, such as `sanmar` or `shopify`.","example":"sanmar","type":"string"},"label":{"example":"SanMar Integration","type":"string"},"last_sync":{"format":"date-time","type":["string","null"]},"last_token_refresh":{"format":"date-time","type":["string","null"]},"option":{"additionalProperties":true,"description":"The integration's settings, which differ by type.","type":["object","array","null"]},"shopify_admin_app_url":{"description":"Shopify only.","type":["string","null"]},"shopify_admin_settings_apps_url":{"description":"Shopify only: the store's apps settings page, where the app is uninstalled.","type":["string","null"]},"shopify_admin_url":{"description":"Shopify only: the YoPrint app in the store's Shopify admin. Same as `shopify_admin_app_url`.","type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"description":"Shopify only: where a store data deletion requested by Shopify stands, or null.","type":["object","null"]},"status":{"description":"For example `ENABLED`, `ACTION_REQUIRED`, `REAUTH` (sign in to the provider again), `UNINITIALIZED` (set up but not configured yet) or `DISABLED`.","example":"ENABLED","type":"string"},"subtype":{"description":"Which integration, for example `sanmar_v1`. The same value goes in the create path.","example":"sanmar_v1","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"The kind: `supplier`, `sms` (Twilio), `shipment_v1` (GoShippo), `data_sync` (QuickBooks Online, Shopify), `payment_gateway` (Square), `shipment` (retired FedEx and UPS).","enum":["supplier","sms","shipment_v1","data_sync","payment_gateway","shipment"],"type":"string"}},"required":["id","deprecated","trashed","type","subtype","label","status","has_logs"],"title":"The integration","type":"object"},{"additionalProperties":false,"description":"A YoPrint connect link that only YoPrint's web app can use. Settings > Apps posts it with the signed-in person's session; YoPrint then ties the connection to that person and browser and sends them on to the provider's sign-in, and the provider sends them back to YoPrint, which saves the connection. Opened any other way (in a browser tab, from a script, or by someone else) it shows a refusal page and connects nothing.","properties":{"type":{"const":"oauth","type":"string"},"url":{"description":"The connect link, on YoPrint's own address (`/callback/integration_connect/...`). It works once, within 2 minutes, and only from YoPrint's web app for the person whose API key asked for it.","format":"uri","type":"string"}},"required":["type","url"],"title":"Connect link","type":"object"}],"title":"What comes back?"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Connect an integration","tags":["Integrations"],"x-yoprint-docs":{"errors":[{"fix":"Use a subtype from the table.","status":404,"when":"The subtype in the path is unknown: `error.code` `page_not_found`, `error.message` null."},{"fix":"Check the credentials with the provider and try again.","status":422,"when":"The provider rejected the credentials: `error.code` `invalid_key` (Twilio's reason is in `error.message`)."},{"fix":"Try again later.","status":422,"when":"The supplier could not be reached to check them: `error.code` `credential_check_unavailable`, with `error.retryable: true`."},{"fix":"Update the existing one.","status":422,"when":"The team already has this integration: `unique_constraint` (Square: `unique_integration_error`). QuickBooks Online is not checked here."},{"fix":"Send every field the table lists.","status":422,"when":"A credential field is missing (`validation_failed`)."},{"fix":"Open the YoPrint app in Shopify.","status":422,"when":"Shopify: it is installed from the Shopify admin (`shopify_install_from_shopify_required`)."},{"fix":"Upgrade the plan, or use another integration.","status":422,"when":"The integration is not in your plan (`plan_limitation`)."},{"fix":"Delete it and connect an alternative.","status":422,"when":"The integration is retired (`integration_deprecated`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["AI apps can connect suppliers. Twilio and the provider sign-ins are done in YoPrint."],"permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_external_integration_index","v1_public_external_integration_update_patch","v1_public_external_integration_destroy"],"rules":["One integration of each subtype per team: 422 `unique_constraint` (Square: `unique_integration_error`). Change the credentials of an existing one with \"Update an integration\". QuickBooks Online is not checked at this step.","The integration must be in your plan (422 `plan_limitation`).","Suppliers and Twilio are saved only after the provider accepts the credentials."],"side_effects":["Calls the supplier or Twilio to check the credentials. No order is placed and no message is sent.","For a provider sign-in, nothing is saved until the person finishes signing in from Settings > Apps."]}},"put":{"description":"Changes an integration's settings or credentials. What you send depends on its type:\n\n- **Suppliers**: the full credentials again, as when connecting (SanMar `account_number`, `user`, `pass`; AS Colour `email`, `password`; the others `user`, `pass`). YoPrint checks them with the supplier and saves only if accepted.\n- **Twilio**: `selected_phone_number`, one of your Twilio numbers (read them with the data call, `type: phone_numbers`; YoPrint doesn't check it), and optionally `sms_not_supported_msg`, the reply sent to anyone who texts that number. The credentials can't change here; delete and connect again.\n- **GoShippo**: `label_size` (`PDF`, `PDF_2.3x7.5`, `PDF_4x6`, `PDF_4x8`, `PDF_A4` or `PDF_A6`) and `shipping_phone_number`. YoPrint checks the GoShippo connection first.\n- **QuickBooks Online**: `account`, `tax` and `setting`, each value wrapped as `{\"value\": ...}`. YoPrint checks the accounts and tax codes with QuickBooks first, and reads a new `payment_deposit_account_id` from QuickBooks before saving it.\n- **Square**: `webhook_listen_to_location`, `web_location_id` and `enable_customer_portal_payment`.\n- **Shopify**: `default` (billing address, shipping address and warehouse, all required, plus optional payment method, order prefix and QuickBooks opt-out) and `setting` (sync choices).\n\nPUT and PATCH do the same. Returns the integration, as \"Get an integration\" does.","operationId":"v1_public_external_integration_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The integration, from the integration list. Its hash id from an earlier answer; there is no unique key for it.","example":"d9ZxWgBz09mDFq","in":"path","name":"external_integration_reference","required":true,"schema":{"example":"d9ZxWgBz09mDFq","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"goshippo":{"summary":"GoShippo label size","value":{"label_size":"PDF_4x6"},"x-yoprint-variant":"GoShippo"},"supplier":{"summary":"New S&S Activewear password","value":{"pass":"YOUR_PASSWORD","user":"YOUR_SUPPLIER_USERNAME"},"x-yoprint-variant":"S&S Activewear, SanMar Canada or Momentec"},"twilio":{"summary":"Twilio sending number","value":{"selected_phone_number":"+12015550123","sms_not_supported_msg":"We don't answer texts. Please email us."},"x-yoprint-variant":"Twilio"}},"schema":{"anyOf":[{"additionalProperties":false,"description":"Path `sanmar_v1`. Your SanMar web services account.","properties":{"account_number":{"description":"Your SanMar customer number.","type":"string"},"pass":{"description":"Your password with the supplier. It is never returned.","type":"string"},"user":{"description":"Your username with the supplier.","type":"string"}},"required":["account_number","user","pass"],"title":"SanMar","type":"object"},{"additionalProperties":false,"description":"Paths `ssa_v1`, `ssa_ca_v1`, `sanmar_ca_v1`, `momentec_v2` (Augusta Sportswear) and `momentec_ca_v2`.","properties":{"pass":{"description":"Your password with the supplier. It is never returned.","type":"string"},"user":{"description":"Your username with the supplier.","type":"string"}},"required":["user","pass"],"title":"S&S Activewear, SanMar Canada or Momentec","type":"object"},{"additionalProperties":false,"description":"Path `ascolour_v1`. Your AS Colour account sign-in.","properties":{"email":{"format":"email","type":"string"},"password":{"description":"Never returned.","type":"string"}},"required":["email","password"],"title":"AS Colour","type":"object"},{"additionalProperties":false,"description":"The sending number and the auto-reply.","properties":{"selected_phone_number":{"description":"One of the numbers on your Twilio account, as Twilio formats it.","type":"string"},"sms_not_supported_msg":{"description":"The reply sent to anyone who texts this number. Empty keeps the current one.","type":"string"}},"required":["selected_phone_number"],"title":"Twilio","type":"object"},{"additionalProperties":false,"description":"Label size and the phone number on labels.","properties":{"label_size":{"enum":["PDF","PDF_2.3x7.5","PDF_4x6","PDF_4x8","PDF_A4","PDF_A6"],"type":"string"},"shipping_phone_number":{"type":"string"}},"title":"GoShippo","type":"object"},{"additionalProperties":true,"description":"Account and tax mapping, and sync choices. Each setting is an object with a `value`. Send the parts you change.","properties":{"account":{"additionalProperties":true,"description":"QuickBooks account ids, from the `account` data call.","properties":{"default_tax":{"additionalProperties":false,"description":"The default tax code. `value` must be present; empty clears it.","properties":{"value":{"type":"string"}},"required":["value"],"type":"object"},"purchase_order_line_expense":{"additionalProperties":false,"description":"The expense account for purchase order lines.","properties":{"value":{"type":"string"}},"required":["value"],"type":"object"},"sales":{"additionalProperties":false,"description":"The income account for sales.","properties":{"value":{"type":"string"}},"required":["value"],"type":"object"}},"type":"object"},"setting":{"additionalProperties":true,"properties":{"invoice_date_field":{"additionalProperties":false,"description":"Which date becomes the QuickBooks invoice date.","properties":{"value":{"enum":["issue_date","cust_due_date"],"type":"string"}},"required":["value"],"type":"object"},"invoice_deleted_automatic_sync":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"invoice_due_date_field":{"additionalProperties":false,"description":"Which date becomes its due date.","properties":{"value":{"enum":["due_date","full_amount_due"],"type":"string"}},"required":["value"],"type":"object"},"invoice_updated_automatic_sync":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"payment_deposit_account_id":{"additionalProperties":false,"description":"Where new QuickBooks Payments are recorded: a QuickBooks account id (digits, up to 64), or `\"\"` to let QuickBooks decide. A new account must be an active Bank or Other Current Asset account in your shop's default currency, and not an inventory or prepaid expense account; YoPrint reads it from QuickBooks to check. Payments already in QuickBooks keep their account.","properties":{"value":{"maxLength":64,"type":["string","null"]}},"required":["value"],"type":"object"},"purchase_order_created_automatic_sync":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"purchase_order_deleted_automatic_sync":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"purchase_order_sync_as_bill":{"additionalProperties":false,"description":"Sync purchase orders as bills.","properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"purchase_order_updated_automatic_sync":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"sync_invoice":{"additionalProperties":false,"description":"Sync invoices. Saved off, it turns payment sync off too.","properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"sync_invoice_payment":{"additionalProperties":false,"description":"Sync payments. Payments ride on their invoices: while `sync_invoice` is off this is stored and read as false, and turning invoice sync back on leaves it off until you turn it on.","properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"sync_purchase_order":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"}},"type":"object"},"tax":{"description":"Pairs your tax presets with QuickBooks tax codes.","items":{"additionalProperties":false,"properties":{"id":{"description":"A tax preset's id.","type":"string"},"value":{"description":"A QuickBooks tax code id, from the `tax` data call. Empty removes the pairing.","type":"string"}},"required":["id","value"],"type":"object"},"type":"array"}},"title":"QuickBooks Online","type":"object"},{"additionalProperties":true,"description":"Which locations Square payments are listened for, and the customer portal payment option. Other keys you send are saved in `option` as they are.","properties":{"enable_customer_portal_payment":{"type":"boolean"},"web_location_id":{"description":"The Square location online payments go to.","type":"string"},"webhook_listen_to_location":{"items":{"additionalProperties":true,"properties":{"id":{"description":"A Square location id.","type":"string"}},"type":"object"},"type":"array"}},"title":"Square","type":"object"},{"additionalProperties":true,"description":"How Shopify orders come into YoPrint. `default` must name the billing address, shipping address and warehouse each time.","properties":{"default":{"additionalProperties":true,"properties":{"billing_address_id":{"description":"One of your team's addresses (locations).","type":"string"},"order_prefix":{"maxLength":255,"type":["string","null"]},"payment_method_id":{"description":"A payment method, or null.","type":["string","null"]},"quickbook_disable_sync":{"description":"Keep these orders out of QuickBooks.","type":["boolean","null"]},"shipping_address_id":{"description":"One of your team's addresses.","type":"string"},"warehouse_id":{"description":"One of your team's addresses, used as the warehouse.","type":"string"}},"required":["billing_address_id","shipping_address_id","warehouse_id"],"type":"object"},"setting":{"additionalProperties":true,"properties":{"auto_sync":{"type":["boolean","null"]},"manually_sync":{"type":["boolean","null"]},"notify_user_on_shipment_sync":{"enum":["notify_always","notify_ask","notify_never",null],"type":["string","null"]},"shipments_auto_sync":{"type":["boolean","null"]},"terminal_order_policy":{"description":"What happens to the YoPrint order when its Shopify order is cancelled or deleted.","enum":["delete_synced_order","preserve_mark_deleted",null],"type":["string","null"]}},"type":"object"}},"required":["default"],"title":"Shopify","type":"object"}],"title":"Which integration are you updating?"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"data":[],"deprecated":false,"has_logs":false,"id":"ZnLL4KKEIfEAfb","integration_check_key":"ssa","label":"S&SActiveWear Integration","last_sync":null,"last_token_refresh":null,"option":[],"status":"ENABLED","subtype":"ssa_v1","trashed":false,"type":"supplier","user":"YOUR_SUPPLIER_USERNAME"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"data":{"additionalProperties":true,"type":["object","array","null"]},"deprecated":{"description":"A retired integration: it can only be deleted.","type":"boolean"},"has_logs":{"description":"Whether it keeps a log of sync errors: true for QuickBooks Online only.","type":"boolean"},"id":{"example":"d9ZxWgBz09mDFq","type":"string"},"integration_check_key":{"description":"A fixed key for the kind of integration, such as `sanmar` or `shopify`.","example":"sanmar","type":"string"},"label":{"example":"SanMar Integration","type":"string"},"last_sync":{"format":"date-time","type":["string","null"]},"last_token_refresh":{"format":"date-time","type":["string","null"]},"option":{"additionalProperties":true,"description":"The integration's settings, which differ by type.","type":["object","array","null"]},"shopify_admin_app_url":{"description":"Shopify only.","type":["string","null"]},"shopify_admin_settings_apps_url":{"description":"Shopify only: the store's apps settings page, where the app is uninstalled.","type":["string","null"]},"shopify_admin_url":{"description":"Shopify only: the YoPrint app in the store's Shopify admin. Same as `shopify_admin_app_url`.","type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"description":"Shopify only: where a store data deletion requested by Shopify stands, or null.","type":["object","null"]},"status":{"description":"For example `ENABLED`, `ACTION_REQUIRED`, `REAUTH` (sign in to the provider again), `UNINITIALIZED` (set up but not configured yet) or `DISABLED`.","example":"ENABLED","type":"string"},"subtype":{"description":"Which integration, for example `sanmar_v1`. The same value goes in the create path.","example":"sanmar_v1","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"The kind: `supplier`, `sms` (Twilio), `shipment_v1` (GoShippo), `data_sync` (QuickBooks Online, Shopify), `payment_gateway` (Square), `shipment` (retired FedEx and UPS).","enum":["supplier","sms","shipment_v1","data_sync","payment_gateway","shipment"],"type":"string"}},"required":["id","deprecated","trashed","type","subtype","label","status","has_logs"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update an integration","tags":["Integrations"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the list.","status":404,"when":"No integration of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Check the credentials, or reconnect GoShippo in Settings > Apps.","status":422,"when":"The supplier rejected the credentials, or GoShippo's connection failed: `error.code` `invalid_key`. A supplier that can't be reached gives `credential_check_unavailable`."},{"fix":"Send the fields listed for this type.","status":422,"when":"A required field is missing or not allowed (`validation_failed`), for example a Shopify update without the three `default` ids."},{"fix":"Confirm the move with the `transfer_confirm` action first.","status":422,"when":"Square: this Square account is connected to another YoPrint team (`integration_transfer_pending`)."},{"fix":"Pick a bank or other current asset account from the `account` data call, or send `\"\"`.","status":422,"when":"QuickBooks Online: the `payment_deposit_account_id` is refused (`validation_failed`, on `setting.payment_deposit_account_id.value`): \"Choose a QuickBooks account.\", \"QuickBooks could not confirm this account. Check the connection and try again.\", \"Choose an active bank or other current asset account in your shop currency.\" or the inventory or prepaid expense message. Nothing is saved."},{"fix":"Upgrade the plan, or use another integration.","status":422,"when":"The integration is not in your plan (`plan_limitation`)."},{"fix":"Delete it and connect an alternative.","status":422,"when":"The integration is retired (`integration_deprecated`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","patch":"same_as_put","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_external_integration_show","v1_public_external_integration_data"],"rules":["Supplier credentials are saved only after the supplier accepts them; until then the old ones stay."],"side_effects":["Suppliers: calls the supplier to check the credentials.","GoShippo: calls GoShippo to check the connection.","Twilio: changes the number YoPrint texts customers from, and the auto-reply on it.","QuickBooks Online: reads your accounts and tax codes from QuickBooks to check the mapping, and a newly chosen deposit account.","QuickBooks Online: when the save turns the connection on with payment sync, or turns payment sync on, customer portal payments that were waiting for QuickBooks are picked up again at the next payment sync.","Shopify: the integration is `ENABLED` once the three `default` ids are set, `UNINITIALIZED` otherwise."]}}},"/v1/api/store/{team_slug}/setting/external_integration/{id}/action":{"put":{"description":"Runs a one-off action on an integration. Send its `type`; the allowed values depend on the integration:\n\n- **QuickBooks Online**: `account` and `tax` (read them), `refresh_account`, `refresh_qbo_accounts`, `refresh_qbo_tax` (reload data from QuickBooks), `check`, `upsert_yoprint_item` (set up YoPrint's item in QuickBooks), `reauth` (a new connect link, usable only in YoPrint's web app), and `customer_payment_sync`: a page of the payments customers made in the customer portal and where each stands in QuickBooks (optionally only one order's, with `order_id`; `page` and `per_page` up to 100). It reads YoPrint only, so it works even while QuickBooks needs signing in again.\n- **GoShippo**: `reauth`, which returns `{\"type\": \"oauth\", \"url\": \"...\"}`.\n- **Square**: `reauth`, or `transfer_confirm` / `transfer_cancel` for a Square account another YoPrint team holds (confirm returns the integration; cancel removes this team's waiting connection and answers `data: null`).\n- **Shopify**: `toggle`, `self_heal_setup`, `manually_sync` (with `shopify_order_id`), `bulk_manually_sync` (with `shopify_order_ids`), and fulfillment actions with `shipment_id` or `shipment_ids`.\n\nA `reauth` link is a YoPrint connect link that only the web app can use: opened in a browser tab or from a script it shows a refusal page. To sign in to the provider again, use Reconnect in Settings > Apps.\n\nSuppliers and Twilio have no actions. The `{id}` is the integration's id from the list.","operationId":"v1_public_external_integration_action","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The integration, from the integration list. Its hash id from an earlier answer; there is no unique key for it.","example":"d9ZxWgBz09mDFq","in":"path","name":"id","required":true,"schema":{"example":"d9ZxWgBz09mDFq","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"goshippo":{"summary":"New GoShippo connect link","value":{"type":"reauth"},"x-yoprint-variant":"GoShippo"},"qbo":{"summary":"Reload QuickBooks accounts","value":{"type":"refresh_qbo_accounts"},"x-yoprint-variant":"QuickBooks Online"},"shopify":{"summary":"Sync one Shopify order","value":{"shopify_order_id":"1001","type":"manually_sync"},"x-yoprint-variant":"Shopify"},"square":{"summary":"New Square connect link","value":{"type":"reauth"},"x-yoprint-variant":"Square"}},"schema":{"anyOf":[{"additionalProperties":true,"description":"Read or refresh the accounts and tax data YoPrint keeps from QuickBooks, check the setup, set up the YoPrint item, get a new connect link (usable only in YoPrint's web app), or list how customer portal payments stand in QuickBooks (`customer_payment_sync`).","properties":{"order_id":{"description":"For `customer_payment_sync`: only the payments on this sales order or quote (its id).","type":"string"},"page":{"description":"For `customer_payment_sync`: the page, from 1.","minimum":1,"type":"integer"},"per_page":{"description":"For `customer_payment_sync`: rows per page, 20 when left out.","maximum":100,"minimum":1,"type":"integer"},"type":{"enum":["account","tax","check","refresh_account","refresh_qbo_accounts","refresh_qbo_tax","upsert_yoprint_item","reauth","customer_payment_sync"],"type":"string"}},"required":["type"],"title":"QuickBooks Online","type":"object"},{"additionalProperties":false,"description":"Get a new GoShippo connect link (usable only in YoPrint's web app).","properties":{"type":{"const":"reauth","type":"string"}},"required":["type"],"title":"GoShippo","type":"object"},{"additionalProperties":true,"description":"Get a new Square connect link (usable only in YoPrint's web app), or confirm or cancel moving a Square account that another team holds.","properties":{"type":{"enum":["reauth","transfer_confirm","transfer_cancel"],"type":"string"}},"required":["type"],"title":"Square","type":"object"},{"additionalProperties":true,"description":"Turn sync on or off, repair the setup, sync orders by hand, or create, update or cancel fulfillments in Shopify.","properties":{"notify_customer":{"description":"For the fulfillment actions: whether Shopify emails the customer.","type":["boolean","null"]},"shipment_id":{"description":"Required for the single fulfillment actions.","type":"string"},"shipment_ids":{"description":"Required for the bulk fulfillment actions.","items":{"type":"string"},"type":"array"},"shopify_order_id":{"description":"Required for `manually_sync`.","type":"string"},"shopify_order_ids":{"description":"Required for `bulk_manually_sync`.","items":{"type":"string"},"type":"array"},"type":{"enum":["self_heal_setup","toggle","manually_sync","bulk_manually_sync","create_fulfillment","update_fulfillment","cancel_fulfillment","bulk_create_fulfillment","bulk_update_fulfillment","bulk_cancel_fulfillment"],"type":"string"}},"required":["type"],"title":"Shopify","type":"object"}],"title":"Which integration?"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"type":"oauth","url":"https://secure.yoprint.com/callback/integration_connect/EXAMPLE_CONNECT_LINK"},"status":200,"success":true},"schema":{"properties":{"data":{"anyOf":[{"additionalProperties":false,"description":"A YoPrint connect link that only YoPrint's web app can use. Settings > Apps posts it with the signed-in person's session; YoPrint then ties the connection to that person and browser and sends them on to the provider's sign-in, and the provider sends them back to YoPrint, which saves the connection. Opened any other way (in a browser tab, from a script, or by someone else) it shows a refusal page and connects nothing.","properties":{"type":{"const":"oauth","type":"string"},"url":{"description":"The connect link, on YoPrint's own address (`/callback/integration_connect/...`). It works once, within 2 minutes, and only from YoPrint's web app for the person whose API key asked for it.","format":"uri","type":"string"}},"required":["type","url"],"title":"Connect link","type":"object"},{"additionalProperties":false,"properties":{"aggregate":{"additionalProperties":false,"description":"A summary: of this page, or with `order_id` of every payment on that order.","properties":{"component":{"const":"bulk_payment_sources","type":"string"},"needs_attention":{"description":"Payments that are `held` or `failed`.","type":"integer"},"pending":{"type":"integer"},"scope":{"enum":["page","order"],"type":"string"},"status":{"enum":["not_applicable","up_to_date","pending","needs_attention"],"type":"string"},"total":{"type":"integer"}},"required":["scope","component","status","total","pending","needs_attention"],"type":"object"},"items":{"description":"Newest first.","items":{"additionalProperties":false,"properties":{"amount":{"description":"The amount paid. A decimal string, such as `\"125.0000\"`; parse it as a decimal.","type":"string"},"confirmed_at":{"description":"When YoPrint last read the Payment back from QuickBooks and found it right, or null.","format":"date-time","type":["string","null"]},"currency":{"description":"Its currency code, such as `USD`.","type":"string"},"customer":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"type":"object"},"funding_id":{"description":"The payment the customer made in the customer portal.","type":"string"},"payment_status":{"enum":["received","partially_refunded","refunded"],"type":"string"},"projection_id":{"description":"YoPrint's record of the matching QuickBooks Payment, or null before one is prepared.","type":["string","null"]},"reason":{"additionalProperties":false,"description":"Why it isn't simply up to date: `code`, a `message` for people, `detail` (or null), and `quickbooks_message`, QuickBooks' own words when it refused (or null). Null when there is nothing to say.","properties":{"code":{"type":"string"},"detail":{"type":["string","null"]},"message":{"type":"string"},"quickbooks_message":{"type":["string","null"]}},"type":["object","null"]},"state":{"description":"`synced`: in QuickBooks and up to date. `pending`: waiting, running, or payment sync is off. `failed`: needs someone to look. `held`: held back, see `reason`. `switched_off`: every order it pays is kept out of QuickBooks. `deleted`: refunded to zero and deleted in QuickBooks.","enum":["synced","pending","failed","held","switched_off","deleted"],"type":"string"}},"required":["funding_id","projection_id","customer","amount","currency","payment_status","state","reason","confirmed_at"],"type":"object"},"type":"array"},"pagination":{"additionalProperties":false,"properties":{"last_page":{"type":"integer"},"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"}},"required":["page","per_page","total","last_page"],"type":"object"}},"required":["items","pagination","aggregate"],"title":"QuickBooks Online `customer_payment_sync`: customer portal payments and their QuickBooks state","type":"object"},{"additionalProperties":true,"description":"Every action but `reauth`: what the provider step returns, which differs by integration and action (for example refreshed QuickBooks data, or null).","title":"Action result","type":["object","array","null"]}],"title":"What comes back?"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Run an integration action","tags":["Integrations"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the list.","status":404,"when":"No integration of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Use a `type` listed for it.","status":422,"when":"`type` is missing or not allowed for this integration (`validation_failed`). Shopify's list has no `oauth`."},{"fix":"They have no actions.","status":500,"when":"A supplier or Twilio integration: `error.code` `no_action`, \"No action found!\"."},{"fix":"Read the integration first.","status":422,"when":"Square `transfer_confirm` or `transfer_cancel` when no transfer is waiting: `error.code` `integration_transfer_not_pending`."},{"fix":"Use a `type` from the list.","status":200,"when":"QuickBooks Online with a `type` it doesn't know: the answer is HTTP 200 with an empty body (not JSON), and nothing happens."},{"fix":"Use a sales order or quote id from your team.","status":404,"when":"QuickBooks `customer_payment_sync`: `order_id` is not the id of one of your team's orders."},{"fix":"Use the key of a member whose permission group has Manage Settings.","status":403,"when":"QuickBooks `customer_payment_sync`: the person behind the key holds no permission group with Manage Settings (`error.code` `customer_payment_sync_not_authorized`). Being the team owner is not enough here."},{"fix":"Send `page` from 1 and `per_page` from 1 to 100.","status":422,"when":"QuickBooks `customer_payment_sync`: `page` or `per_page` is not a whole number in range, or `order_id` is not a string (`validation_failed`)."},{"fix":"Upgrade the plan, or use another integration.","status":422,"when":"The integration is not in your plan (`plan_limitation`)."},{"fix":"Delete it and connect an alternative.","status":422,"when":"The integration is retired (`integration_deprecated`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_external_integration_data","v1_public_external_integration_show"],"side_effects":["Calls the provider. Shopify fulfillment actions change orders in your Shopify store (and may email the customer); QuickBooks `upsert_yoprint_item` writes to QuickBooks; Square `transfer_confirm` disconnects the Square account from the other YoPrint team and emails that team's owner (this integration then reads `ACTION_REQUIRED` until its locations are set); `transfer_cancel` removes this team's waiting connection."]}}},"/v1/api/store/{team_slug}/setting/external_integration/{id}/data":{"put":{"description":"Reads live data from the provider through the integration. Send `type`.\n\n**Check `success`, not only the HTTP status:** when Square doesn't create a pairing code (`create_device_code`), this call answers **HTTP 200** with `{\"status\": 500, \"success\": false, \"error\": {\"code\": 422, \"message\": null}}`. Here `error.code` is the number 422, not a string.\n\n- **Twilio**: `balance`, or `phone_numbers` (200 a page; `page_number` and `page_token` page through). Twilio's records keep Twilio's own field names: use a record's `phoneNumber` as `selected_phone_number`.\n- **Square**: `location` (a list) and `merchant` (one record), as Square returns them; `device`, which refreshes the devices saved in YoPrint from Square and returns them all as connected devices; or `create_device_code` with `device_name`, `device_location_id` and `idempotency_key` to start pairing a terminal. It returns the new connected device, whose `device_config.code` is the pairing code to enter on the terminal.\n- **QuickBooks Online**: it runs the action of the same `type`, so it takes the same values, such as `account`, `tax` and `customer_payment_sync`.\n\nApart from the connected devices, the answer is the provider's data, shaped by the provider, so it has no fixed fields. Suppliers, GoShippo and Shopify have no data here. It is a PUT, so it needs Manage Settings. The `{id}` is the integration's id from the list.","operationId":"v1_public_external_integration_data","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The integration, from the integration list. Its hash id from an earlier answer; there is no unique key for it.","example":"d9ZxWgBz09mDFq","in":"path","name":"id","required":true,"schema":{"example":"d9ZxWgBz09mDFq","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"qbo":{"summary":"QuickBooks accounts","value":{"type":"account"},"x-yoprint-variant":"QuickBooks Online"},"square":{"summary":"Square: pair a terminal","value":{"device_location_id":"YOUR_SQUARE_LOCATION_ID","device_name":"Front counter","idempotency_key":"pair-front-counter-0001","type":"create_device_code"},"x-yoprint-variant":"Square"},"twilio":{"summary":"Twilio phone numbers","value":{"type":"phone_numbers"},"x-yoprint-variant":"Twilio"}},"schema":{"oneOf":[{"additionalProperties":false,"description":"Your Twilio balance, or the phone numbers on your Twilio account (200 a page).","properties":{"page_number":{"description":"For `phone_numbers`: the page to read.","type":"integer"},"page_token":{"description":"For `phone_numbers`: Twilio's page token, from a previous page.","type":"string"},"type":{"enum":["balance","phone_numbers"],"type":"string"}},"required":["type"],"title":"Twilio","type":"object"},{"additionalProperties":false,"description":"Your Square locations, merchant details or devices, or a code to pair a new terminal.","properties":{"device_location_id":{"description":"For `create_device_code`: a Square location id, from `type: location`.","type":"string"},"device_name":{"description":"For `create_device_code`: the terminal's name in YoPrint and Square.","type":"string"},"idempotency_key":{"description":"For `create_device_code`: a unique string per request, which Square requires. Reuse it only to retry the same request.","type":"string"},"type":{"enum":["location","merchant","device","create_device_code"],"type":"string"}},"required":["type"],"title":"Square","type":"object"},{"additionalProperties":true,"description":"Your QuickBooks accounts (`account`) or tax data (`tax`), a setup check, or the customer portal payment list (`customer_payment_sync`). It runs the action of the same `type`, so it takes the same values, including `upsert_yoprint_item`, which writes to QuickBooks.","properties":{"order_id":{"description":"For `customer_payment_sync`: only the payments on this sales order or quote (its id).","type":"string"},"page":{"description":"For `customer_payment_sync`: the page, from 1.","minimum":1,"type":"integer"},"per_page":{"description":"For `customer_payment_sync`: rows per page, 20 when left out.","maximum":100,"minimum":1,"type":"integer"},"type":{"enum":["account","tax","check","refresh_account","refresh_qbo_accounts","refresh_qbo_tax","upsert_yoprint_item","reauth","customer_payment_sync"],"type":"string"}},"required":["type"],"title":"QuickBooks Online","type":"object"}],"title":"Which integration?"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"accepted":{"summary":"Square: the new terminal and its pairing code","value":{"data":{"device_config":{"code":"ABCDEF","created_at":"2026-11-03T09:00:00.000Z","id":"device_code_example_1","location_id":"YOUR_SQUARE_LOCATION_ID","name":"Front counter","pair_by":"2026-11-03T09:05:00.000Z","product_type":"TERMINAL_API","status":"UNPAIRED","version":"1"},"device_id":"device_code_example_1","device_name":"Front counter","device_status":"unpaired","device_type":"square_terminal","id":"fPbIOxwKlAzDsA","is_enabled":true},"status":200,"success":true}},"refused_numeric_code":{"summary":"Refused with HTTP 200: `success` is false and `error.code` is the number 422","value":{"error":{"code":422,"message":null},"status":500,"success":false}}},"schema":{"oneOf":[{"properties":{"data":{"anyOf":[{"additionalProperties":false,"properties":{"device_config":{"description":"The provider's device details as stored, including a Square terminal's pairing `code` and `status` (sensitive; treat as private). Null for AI apps.","type":["object","array","null"]},"device_id":{"description":"The provider's id for it: for a Square terminal, the id of its pairing code.","type":["string","null"]},"device_name":{"type":["string","null"]},"device_status":{"enum":["ready","unpaired","not-found","unknown","disabled"],"type":"string"},"device_type":{"example":"square_terminal","type":"string"},"id":{"type":"string"},"is_enabled":{"type":"boolean"}},"required":["id","device_id","device_name","is_enabled","device_config","device_type","device_status"],"title":"Square `create_device_code`: the new connected device","type":"object"},{"items":{"additionalProperties":false,"properties":{"device_config":{"description":"The provider's device details as stored, including a Square terminal's pairing `code` and `status` (sensitive; treat as private). Null for AI apps.","type":["object","array","null"]},"device_id":{"description":"The provider's id for it: for a Square terminal, the id of its pairing code.","type":["string","null"]},"device_name":{"type":["string","null"]},"device_status":{"enum":["ready","unpaired","not-found","unknown","disabled"],"type":"string"},"device_type":{"example":"square_terminal","type":"string"},"id":{"type":"string"},"is_enabled":{"type":"boolean"}},"required":["id","device_id","device_name","is_enabled","device_config","device_type","device_status"],"type":"object"},"title":"Square `device`: every connected device","type":"array"},{"additionalProperties":false,"properties":{"aggregate":{"additionalProperties":false,"description":"A summary: of this page, or with `order_id` of every payment on that order.","properties":{"component":{"const":"bulk_payment_sources","type":"string"},"needs_attention":{"description":"Payments that are `held` or `failed`.","type":"integer"},"pending":{"type":"integer"},"scope":{"enum":["page","order"],"type":"string"},"status":{"enum":["not_applicable","up_to_date","pending","needs_attention"],"type":"string"},"total":{"type":"integer"}},"required":["scope","component","status","total","pending","needs_attention"],"type":"object"},"items":{"description":"Newest first.","items":{"additionalProperties":false,"properties":{"amount":{"description":"The amount paid. A decimal string, such as `\"125.0000\"`; parse it as a decimal.","type":"string"},"confirmed_at":{"description":"When YoPrint last read the Payment back from QuickBooks and found it right, or null.","format":"date-time","type":["string","null"]},"currency":{"description":"Its currency code, such as `USD`.","type":"string"},"customer":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"type":"object"},"funding_id":{"description":"The payment the customer made in the customer portal.","type":"string"},"payment_status":{"enum":["received","partially_refunded","refunded"],"type":"string"},"projection_id":{"description":"YoPrint's record of the matching QuickBooks Payment, or null before one is prepared.","type":["string","null"]},"reason":{"additionalProperties":false,"description":"Why it isn't simply up to date: `code`, a `message` for people, `detail` (or null), and `quickbooks_message`, QuickBooks' own words when it refused (or null). Null when there is nothing to say.","properties":{"code":{"type":"string"},"detail":{"type":["string","null"]},"message":{"type":"string"},"quickbooks_message":{"type":["string","null"]}},"type":["object","null"]},"state":{"description":"`synced`: in QuickBooks and up to date. `pending`: waiting, running, or payment sync is off. `failed`: needs someone to look. `held`: held back, see `reason`. `switched_off`: every order it pays is kept out of QuickBooks. `deleted`: refunded to zero and deleted in QuickBooks.","enum":["synced","pending","failed","held","switched_off","deleted"],"type":"string"}},"required":["funding_id","projection_id","customer","amount","currency","payment_status","state","reason","confirmed_at"],"type":"object"},"type":"array"},"pagination":{"additionalProperties":false,"properties":{"last_page":{"type":"integer"},"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"}},"required":["page","per_page","total","last_page"],"type":"object"}},"required":["items","pagination","aggregate"],"title":"QuickBooks Online `customer_payment_sync`: customer portal payments and their QuickBooks state","type":"object"},{"additionalProperties":true,"description":"Twilio, Square `location` and `merchant`, and QuickBooks Online: the provider's records, as the provider shapes them.","title":"Provider data","type":["object","array","null"]}],"title":"What comes back?"},"status":{"const":200,"type":"integer"},"success":{"const":true,"type":"boolean"}},"required":["success","status","data"],"title":"Success","type":"object"},{"additionalProperties":false,"properties":{"error":{"additionalProperties":false,"properties":{"code":{"const":422,"description":"A number here, not a string.","type":"integer"},"message":{"type":"null"}},"required":["code","message"],"type":"object"},"status":{"const":500,"description":"Not the HTTP status, which is 200.","type":"integer"},"success":{"const":false,"type":"boolean"}},"required":["status","success","error"],"title":"Refused: Square made no pairing code","type":"object"}]}}},"description":"The provider's data, or (Square `create_device_code` only) a refusal sent with HTTP 200: check `success`."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Read data from an integration's provider","tags":["Integrations"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the list.","status":404,"when":"No integration of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Check the integration's status and the `type`.","status":422,"when":"`type` is missing or not allowed (`validation_failed`), or the provider read failed (`failed_to_retrieve_data` for Twilio and for Square `location` and `merchant`)."},{"fix":"Confirm the move with the `transfer_confirm` action first.","status":422,"when":"Square: this Square account is connected to another YoPrint team (`integration_transfer_pending`)."},{"fix":"Check `device_location_id` and send a new `idempotency_key`. Nothing was saved.","status":200,"when":"Square did not create the pairing code. The HTTP status is 200, but the body is `{\"status\": 500, \"success\": false, \"error\": {\"code\": 422, \"message\": null}}` (`code` is the number 422). This always happens outside Square's production environment. Check `success`."},{"fix":"Use a `type` from the list.","status":200,"when":"QuickBooks Online with a `type` it doesn't know: HTTP 200 with an empty body (not JSON)."},{"fix":"Use Twilio, Square or QuickBooks Online.","status":500,"when":"The integration has no data: `error.code` `data_type_empty`, for example a supplier."},{"fix":"Upgrade the plan, or use another integration.","status":422,"when":"The integration is not in your plan (`plan_limitation`)."},{"fix":"Delete it and connect an alternative.","status":422,"when":"The integration is retired (`integration_deprecated`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_external_integration_update_patch","v1_public_external_integration_action","v1_public_connected_device_index"],"response":"free-form","side_effects":["Calls the provider.","Square `create_device_code` creates a pairing code at Square and a connected device in YoPrint; `device` updates the saved devices from Square.","QuickBooks Online `upsert_yoprint_item` writes to QuickBooks, as the action does."]}}},"/v1/api/store/{team_slug}/setting/external_integration/{id}/logs":{"get":{"description":"Returns the sync errors an integration recorded, newest first, a page at a time (the team's page size). Only QuickBooks Online keeps a log here (`has_logs: true`); for every other integration the answer is `data: null`.\n\nEach entry has `type`, `error_code`, `error_message`, `error_payload`, `retryable` and `created_at`, and names the order it is about in `order` (or null). A QuickBooks payment that is held gets one entry per hold, with the QuickBooks Payment in `quickbooks_payment_id` and QuickBooks' own words in `quickbooks_message`. Provider answers are logged with secrets removed. The `{id}` is the integration's id from the list.","operationId":"v1_public_external_integration_logs","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The integration, from the integration list. Its hash id from an earlier answer; there is no unique key for it.","example":"d9ZxWgBz09mDFq","in":"path","name":"id","required":true,"schema":{"example":"d9ZxWgBz09mDFq","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"created_at":"2026-10-30T09:00:00+00:00","error_code":"6000","error_message":"(Invoice) A business validation error has occurred while processing your request","error_payload":"Business Validation Error: The customer is inactive.","helpscout_article_id":null,"id":"i91i7ESuTjjC9i","order":{"deleted":false,"id":"V4keXwwxMQyXw7","scoped_id":"SO1001","type":"sales_order"},"quickbooks_message":null,"quickbooks_payment_id":null,"retryable":false,"type":"qbo_sync_endpoint_error"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"error_code":{"type":["string","null"]},"error_message":{"type":["string","null"]},"error_payload":{"description":"What the provider sent back, when it did: for a QuickBooks refusal, QuickBooks' detail text.","type":["object","array","string","null"]},"helpscout_article_id":{"type":["string","null"]},"id":{"type":"string"},"order":{"additionalProperties":false,"description":"The sales order or quote the entry is about, or null.","properties":{"deleted":{"type":"boolean"},"id":{"description":"The order's id, as the order operations take it.","type":"string"},"scoped_id":{"description":"The number people see, such as `SO1001`. Not an id.","type":"string"},"type":{"enum":["sales_order","quote"],"type":"string"}},"required":["id","scoped_id","type","deleted"],"type":["object","null"]},"quickbooks_message":{"description":"What QuickBooks said, when it refused a payment.","type":["string","null"]},"quickbooks_payment_id":{"description":"The QuickBooks Payment the entry is about, when it is about one.","type":["string","null"]},"retryable":{"type":"boolean"},"type":{"type":"string"}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List an integration's error log","tags":["Integrations"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the list.","status":404,"when":"No integration of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Upgrade the plan.","status":422,"when":"Shopify is not in your plan (`plan_limitation`)."}],"group":"Team settings","permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it. AI apps (MCP connections) need Manage Settings to read it.","related":["v1_public_external_integration_show"]}}},"/v1/api/store/{team_slug}/setting/external_integration/{id}/proxy_request":{"put":{"description":"**Internal.** Built for YoPrint's own apps, not for integrations. Don't build on it.\n\nBuilt for YoPrint's web app, to browse orders in a connected Shopify store before importing them. Only Shopify answers it, and only `method: fetch_orders` is allowed (403 `proxy_method_not_allowed` otherwise). Other integrations answer 422 `invalid_public_action`.\n\nBecause it lists every order in the store, it needs Manage Settings or permission to view all sales orders. The permission is checked first: a member without Manage Settings gets 403 `user_is_not_authorized` unless they can view all sales orders and send `fetch_orders` to a Shopify integration.\n\nIt reads from Shopify and changes nothing. The `{id}` is the integration's id from the list.","operationId":"v1_public_external_integration_proxy_request","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The Shopify integration. Its hash id from an earlier answer; there is no unique key for it.","example":"aDFOUrmqetFJaN","in":"path","name":"id","required":true,"schema":{"example":"aDFOUrmqetFJaN","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"body":{"per_page":20,"sort_direction":"desc","sort_key":"CREATED_AT"},"method":"fetch_orders"},"schema":{"additionalProperties":false,"properties":{"body":{"additionalProperties":false,"description":"Paging, search and sorting for the order list.","properties":{"cursor":{"description":"A cursor from the previous page's `pagination`.","type":"string"},"direction":{"default":"forward","enum":["forward","backward"],"type":"string"},"per_page":{"default":20,"maximum":250,"minimum":1,"type":"integer"},"query":{"description":"Shopify search text.","type":"string"},"saved_search_id":{"description":"A Shopify saved search.","type":"string"},"sort_direction":{"enum":["asc","desc"],"type":"string"},"sort_key":{"enum":["CREATED_AT","TOTAL_PRICE","CUSTOMER_NAME","FINANCIAL_STATUS","FULFILLMENT_STATUS","ORDER_NUMBER"],"type":"string"}},"type":["object","null"]},"method":{"const":"fetch_orders","type":"string"},"path":{"description":"Not used.","type":["string","null"]}},"required":["method"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"orders":[{"can_sync":true,"created_at":"2026-10-30T09:00:00Z","currency_code":"USD","customer":{"name":"Alex Rivera"},"email":"alex@example.com","financial_status":"PAID","fulfillment_status":"UNFULFILLED","id":"gid://shopify/Order/1001","is_sync":false,"name":"#1001","sync_blocked_reason":null,"total_price":"125.00","updated_at":"2026-10-30T09:05:00Z","yoprint_order_id":null}],"pagination":{"cursor":null,"has_more_pages":false,"has_previous_pages":false,"next_cursor":null,"previous_cursor":null}},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"orders":{"items":{"additionalProperties":true,"properties":{"can_sync":{"type":"boolean"},"created_at":{"format":"date-time","type":["string","null"]},"currency_code":{"type":["string","null"]},"customer":{"additionalProperties":true,"type":["object","null"]},"email":{"type":["string","null"]},"financial_status":{"type":["string","null"]},"fulfillment_status":{"type":["string","null"]},"id":{"description":"Shopify's order id.","type":"string"},"is_sync":{"description":"Whether it is already in YoPrint.","type":"boolean"},"name":{"description":"Shopify's order name, such as `#1001`.","type":["string","null"]},"sync_blocked_reason":{"type":["string","null"]},"total_price":{"description":"A decimal string, as Shopify sends it (`\"125.00\"`); parse it as a decimal.","type":["string","null"]},"updated_at":{"format":"date-time","type":["string","null"]},"yoprint_order_id":{"description":"The YoPrint sales order made from it, or null.","type":["string","null"]}},"type":"object"},"type":"array"},"pagination":{"additionalProperties":false,"properties":{"cursor":{"type":["string","null"]},"has_more_pages":{"type":"boolean"},"has_previous_pages":{"type":"boolean"},"next_cursor":{"type":["string","null"]},"previous_cursor":{"type":["string","null"]}},"type":"object"}},"required":["orders","pagination"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Read Shopify orders through the integration","tags":["Integrations"],"x-yoprint-docs":{"errors":[{"fix":"Ask the team owner to give your permission group view all sales orders, or Manage Settings.","status":403,"when":"You are not the owner and have no Manage Settings, and either you can't view all sales orders or the call is not `fetch_orders` on a Shopify integration. `error.code` `user_is_not_authorized`, \"Your role does not allow this integration action. Ask your team owner to review your permissions.\""},{"fix":"Use `fetch_orders`.","status":403,"when":"`method` is not `fetch_orders`, sent by the owner or a member with Manage Settings: `error.code` `proxy_method_not_allowed`."},{"fix":"Turn it on with the `toggle` action.","status":400,"when":"The Shopify integration is turned off: `error.code` `integration_disabled`."},{"fix":"Use the Shopify integration's id.","status":422,"when":"The integration is not Shopify (`invalid_public_action`), or `method` is missing (`validation_failed`)."},{"fix":"Wait a moment and try again.","status":429,"when":"Shopify's rate limit was hit: `error.code` `shopify_rate_limited`."},{"fix":"Try again later.","status":502,"when":"Shopify answered with an error or could not be reached (`shopify_api_error`, `shopify_connection_error`)."},{"fix":"Try again later.","status":500,"when":"Something else failed: `error.code` `shopify_proxy_error`."}],"group":"Team settings","notes":["AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, members with Manage Settings, and members with permission to view all sales orders (`view_all_order`).","side_effects":["Calls Shopify's Admin API."],"status":"internal"},"x-internal":true}},"/v1/api/store/{team_slug}/setting/external_integration/{id}/public_action":{"put":{"description":"**Internal.** Built for YoPrint's own apps, not for integrations. Don't build on it.\n\nBuilt for YoPrint's web app, which uses it to link YoPrint records to QuickBooks Online and to push them there. Only QuickBooks Online answers it; other integrations answer 422 `invalid_public_action`. Send an `action`:\n\n- `query_customer`, `query_vendor`: up to 20 QuickBooks records whose display name contains `query`. `query_invoice`, `query_bill`, `query_purchase_order`: up to 20 whose document number contains it. Records come as QuickBooks returns them.\n- `sync_order` and `sync_purchase_order`: queue a sync to QuickBooks of 1 to 100 sales orders or purchase orders, by their ids in `objects`. The answer is `data: null`; the sync runs afterwards, on exactly the records YoPrint checked.\n\nEach action checks a permission before anything else, so a member without Manage Settings who lacks it gets 403 `user_is_not_authorized` (see Permission). The `{id}` is the integration's id from the list.","operationId":"v1_public_external_integration_public_action","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The QuickBooks Online integration. Its hash id from an earlier answer; there is no unique key for it.","example":"QF3K07jFrQ1P1B","in":"path","name":"id","required":true,"schema":{"example":"QF3K07jFrQ1P1B","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"query":{"summary":"Find a QuickBooks customer","value":{"action":"query_customer","query":"Northwind"}},"sync":{"summary":"Sync two sales orders","value":{"action":"sync_order","objects":["zGZRXNGeh5cs6M","VDG1ZqxwDQCaZ0"]}}},"schema":{"additionalProperties":false,"properties":{"action":{"enum":["query_customer","query_vendor","query_invoice","query_bill","query_purchase_order","sync_order","sync_purchase_order"],"type":"string"},"objects":{"description":"For the `sync_` actions: 1 to 100 sales order or purchase order ids, as this API returns them. Don't send document numbers such as `1001`: a whole number, or a string of digits only, is read as YoPrint's internal record number and can name a different record.","items":{"type":["string","integer"]},"type":"array"},"query":{"description":"For the `query_` actions: text the display name contains.","type":"string"}},"required":["action"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"DisplayName":"Northwind Apparel","Id":"58"}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"For a `query_` action, up to 20 QuickBooks records as QuickBooks returns them. For a `sync_` action, null.","items":{"additionalProperties":true,"type":"object"},"type":["array","null"]},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Search QuickBooks, or sync records to it","tags":["Integrations"],"x-yoprint-docs":{"errors":[{"fix":"Ask the team owner to give your permission group the permission the action needs, or leave out records you can't view.","status":403,"when":"You are not the owner, have no Manage Settings, and lack the permission the action needs (or can't view one of the records in `objects`). Members without Manage Settings get this for other integrations and for an `action` that is missing or unknown, too. `error.code` `user_is_not_authorized`, \"Your role does not allow this integration action. Ask your team owner to review your permissions.\" (for a sales order you can't view, the message names sales order permissions). Nothing is synced."},{"fix":"Send the ids this API returns.","status":422,"when":"`sync_order` or `sync_purchase_order`: an entry in `objects` is not one of your team's ids or a positive whole number: `error.code` `unreadable_records`, \"Some selected records could not be read. Reload the page and try again.\" Nothing is synced."},{"fix":"Use the QuickBooks integration's id and 1 to 100 records.","status":422,"when":"The integration is not QuickBooks Online (`invalid_public_action`), or `objects` is empty or has more than 100 ids (`validation_error`)."},{"fix":"Leave Shopify orders out.","status":422,"when":"A Shopify order can't be synced to QuickBooks (`validation_error`)."},{"fix":"Send `query` as text and `objects` as a list of ids.","status":422,"when":"`query` is not a string, or `objects` is not a list on a `query_` action (`validation_failed`); or the integration is retired or not in your plan."},{"fix":"Send an `action` from the list.","status":200,"when":"The owner or a member with Manage Settings sends an `action` that is missing or not one of the seven: HTTP 200 with an empty body (not JSON), and nothing happens."}],"group":"Team settings","notes":["AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner and members with Manage Settings can run every action. Other members need, per action: `query_customer`, permission to view all customers (`view_all_customer`); `query_vendor`, permission to view vendors (`view_vendor`); `sync_order`, permission to view all sales orders (`view_all_order`) or their own (`view_self_order`), and every order in `objects` must be one they can view (their own: created by them or assigned to them); `sync_purchase_order`, the same with purchase orders (`view_all_po`, `view_self_po`). `query_invoice`, `query_bill` and `query_purchase_order` need Manage Settings.","response":"free-form","side_effects":["Calls QuickBooks Online. The `sync_` actions queue writes of your records to QuickBooks."],"status":"internal"},"x-internal":true}},"/v1/api/store/{team_slug}/setting/external_integration/{id}/restore":{"patch":{"description":"Brings back a removed Shopify store connection and turns it on again. Only Shopify can be restored; every other type answers 422 `invalid_public_action`. The `{id}` is the integration's id from the list. Find removed ones with \"Search integrations\" and `trashed_only`. Returns the restored integration.","operationId":"v1_public_external_integration_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The removed Shopify integration, from \"Search integrations\" with `trashed_only`. Its hash id from an earlier answer; there is no unique key for it.","example":"aDFOUrmqetFJaN","in":"path","name":"id","required":true,"schema":{"example":"aDFOUrmqetFJaN","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"data":{"currencyCode":"USD","domain":"example.myshopify.com","gid":"gid://shopify/Shop/1001","id":"gid://shopify/Shop/1001","myshopifyDomain":"example.myshopify.com","name":"Northwind Apparel","shop_domain":"example.myshopify.com","shop_url":"example.myshopify.com","url":"https://example.myshopify.com"},"deprecated":false,"has_logs":false,"id":"aDFOUrmqetFJaN","integration_check_key":"shopify","label":"Shopify","last_sync":null,"last_token_refresh":"2026-10-01T09:00:00+00:00","option":[],"shopify_admin_app_url":"https://example.com/shopify-admin/apps/yoprint","shopify_admin_settings_apps_url":"https://example.com/shopify-admin/settings/apps","shopify_admin_url":"https://example.com/shopify-admin/apps/yoprint","shopify_compliance_deletion":null,"status":"ENABLED","subtype":"shopify_v1","trashed":false,"type":"data_sync"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"As \"Get an integration\" returns it. No stored credential is in it: supplier passwords, Twilio's Account SID and auth token, the GoShippo sign-in and AS Colour's API key are never returned.","properties":{"data":{"additionalProperties":true,"type":["object","array","null"]},"deprecated":{"description":"A retired integration: it can only be deleted.","type":"boolean"},"has_logs":{"description":"Whether it keeps a log of sync errors: true for QuickBooks Online only.","type":"boolean"},"id":{"example":"d9ZxWgBz09mDFq","type":"string"},"integration_check_key":{"description":"A fixed key for the kind of integration, such as `sanmar` or `shopify`.","example":"sanmar","type":"string"},"label":{"example":"SanMar Integration","type":"string"},"last_sync":{"format":"date-time","type":["string","null"]},"last_token_refresh":{"format":"date-time","type":["string","null"]},"option":{"additionalProperties":true,"description":"The integration's settings, which differ by type.","type":["object","array","null"]},"shopify_admin_app_url":{"description":"Shopify only.","type":["string","null"]},"shopify_admin_settings_apps_url":{"description":"Shopify only: the store's apps settings page, where the app is uninstalled.","type":["string","null"]},"shopify_admin_url":{"description":"Shopify only: the YoPrint app in the store's Shopify admin. Same as `shopify_admin_app_url`.","type":["string","null"]},"shopify_compliance_deletion":{"additionalProperties":true,"description":"Shopify only: where a store data deletion requested by Shopify stands, or null.","type":["object","null"]},"status":{"description":"For example `ENABLED`, `ACTION_REQUIRED`, `REAUTH` (sign in to the provider again), `UNINITIALIZED` (set up but not configured yet) or `DISABLED`.","example":"ENABLED","type":"string"},"subtype":{"description":"Which integration, for example `sanmar_v1`. The same value goes in the create path.","example":"sanmar_v1","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"The kind: `supplier`, `sms` (Twilio), `shipment_v1` (GoShippo), `data_sync` (QuickBooks Online, Shopify), `payment_gateway` (Square), `shipment` (retired FedEx and UPS).","enum":["supplier","sms","shipment_v1","data_sync","payment_gateway","shipment"],"type":"string"}},"required":["id","deprecated","trashed","type","subtype","label","status","has_logs"],"title":"The integration","type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a removed Shopify store","tags":["Integrations"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Use an id from \"Search integrations\".","status":404,"when":"No integration of your team, removed or not, has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Connect it again instead.","status":422,"when":"The integration is not Shopify: `error.code` `invalid_public_action`."},{"fix":"Nothing to restore.","status":422,"when":"The Shopify store isn't removed: `error.code` `restore_fail`."},{"fix":"Upgrade the plan, or use another integration.","status":422,"when":"The integration is not in your plan (`plan_limitation`)."},{"fix":"Delete it and connect an alternative.","status":422,"when":"The integration is retired (`integration_deprecated`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_external_integration_filter"]}}},"/v1/api/store/{team_slug}/setting/feature_addon/{module}/disable":{"put":{"description":"Turns off an optional feature. The only add-on is `cust_msg_status`, \"customer message statuses\". Its statuses are kept, so turning it on again brings them back.\n\nThis doesn't change your YoPrint bill.\n\nReturns the full settings object, with `cust_msg_status: false`.","operationId":"v1_public_setting_feature_addon_disable","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The add-on. The only one is `cust_msg_status`, \"customer message statuses\".","example":"cust_msg_status","in":"path","name":"module","required":true,"schema":{"enum":["cust_msg_status"],"example":"cust_msg_status","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"column":[],"cust_msg_status":false,"customer_portal_account_login_available":true,"customer_portal_rollout":{"account_only":false,"all_teams_at":null,"configuration_warning":null,"legacy_access_allowed":true,"new_teams_at":null,"reason":"transition"},"default_pricing_strategy":"job_separately","dimension":"in","enable_stock_management":true,"pagination_per_page":50,"payment_amount_policies":{"USD":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null}},"payment_amount_policy":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null},"paypal_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/paypal","pdf_date_format":"us_standard","pdf_sales_order_display_option":["job_summary"],"shipping_label_create_cost_line_item":true,"square_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/square","stripe_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/stripe","web_date_format":"default","weight":"lbs"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"The team's settings: the saved general settings (the keys \"Update general settings\" takes, with their defaults), `column` (list columns), `cust_msg_status` (the add-on), the three payment webhook addresses, the read-only customer portal sign-in and payment minimum fields below, and the payment gateway values stored for the team, which can include secret keys (sensitive; treat as private). A team that never changed its date formats reads `pdf_date_format: \"std\"` and `web_date_format: \"us\"`, values outside the list the update takes.","properties":{"column":{"additionalProperties":true,"description":"List columns, by list name (`sales_order`, `quote`, ...). An empty array `[]` when none is saved.","type":["object","array"]},"cust_msg_status":{"description":"Whether the customer message statuses add-on is on.","type":"boolean"},"customer_portal_account_login_available":{"description":"Read only: whether customers can sign in to your customer portal with an email account. True when your plan includes the customer portal.","type":"boolean"},"customer_portal_rollout":{"additionalProperties":false,"description":"Read only: where the customer portal's move to email-account sign-in stands for your team. YoPrint sets the dates; you can't change them here.","properties":{"account_only":{"description":"True when customers must sign in with an email account: a portal link alone no longer opens the portal.","type":"boolean"},"all_teams_at":{"description":"From when every team is account-only (UTC), or null when not set.","format":"date-time","type":["string","null"]},"configuration_warning":{"description":"Set when YoPrint's own rollout dates are inconsistent; null normally.","enum":["new_teams_cutoff_not_before_all_teams_cutoff","invalid_rollout_date",null],"type":["string","null"]},"legacy_access_allowed":{"description":"The opposite of `account_only`: portal links still open the portal.","type":"boolean"},"new_teams_at":{"description":"From when new teams are account-only (UTC), or null when not set.","format":"date-time","type":["string","null"]},"reason":{"description":"`transition`: links still work. `new_team_cutoff`: the team was created after the date for new teams. `all_teams_cutoff`: the date for every team has passed.","enum":["transition","new_team_cutoff","all_teams_cutoff"],"type":"string"}},"required":["account_only","legacy_access_allowed","reason","new_teams_at","all_teams_at","configuration_warning"],"type":"object"},"pagination_per_page":{"type":"integer"},"payment_amount_policies":{"additionalProperties":{"additionalProperties":false,"properties":{"currency":{"example":"USD","type":"string"},"minimum_payment":{"additionalProperties":false,"description":"A decimal pair whose `value` is a string: the amount is `value` ÷ 10^`dp` (`{\"value\": \"1000\", \"dp\": 3}` is 1.00). YoPrint refuses smaller payments.","properties":{"dp":{"const":3,"type":"integer"},"value":{"type":"string"}},"required":["value","dp"],"type":"object"},"minimum_remaining_balance":{"description":"Always null here.","type":"null"}},"required":["currency","minimum_payment","minimum_remaining_balance"],"type":"object"},"description":"Read only: the same for each of your currencies, deleted ones included, keyed by ISO code (orders keep the currency they were made in). `[]` when the team has none.","type":["object","array"]},"payment_amount_policy":{"anyOf":[{"additionalProperties":false,"properties":{"currency":{"example":"USD","type":"string"},"minimum_payment":{"additionalProperties":false,"description":"A decimal pair whose `value` is a string: the amount is `value` ÷ 10^`dp` (`{\"value\": \"1000\", \"dp\": 3}` is 1.00). YoPrint refuses smaller payments.","properties":{"dp":{"const":3,"type":"integer"},"value":{"type":"string"}},"required":["value","dp"],"type":"object"},"minimum_remaining_balance":{"description":"Always null here.","type":"null"}},"required":["currency","minimum_payment","minimum_remaining_balance"],"type":"object"},{"type":"null"}],"description":"Read only: the smallest payment YoPrint takes in your default currency, or null when the team has no default currency."},"paypal_webhook_url":{"description":"The same for PayPal.","format":"uri","type":"string"},"pdf_date_format":{"description":"Date format on PDFs. `std` is the default for a team that never changed it; PDFs show it like `other_1` (05 Nov 2026). A team whose saved settings have no date format reads `other_1`. \"Update general settings\" accepts only the other five values.","enum":["std","default","british_standard","us_standard","international","other_1"],"type":"string"},"shipping_label_create_cost_line_item":{"description":"Whether \"Create Shipping Cost Line Item\" starts checked when someone buys a shipping label in the web app. `true` until changed.","type":"boolean"},"square_webhook_url":{"description":"The same for Square.","format":"uri","type":"string"},"stripe_webhook_url":{"description":"The address to give Stripe for this team's payment webhooks.","format":"uri","type":"string"},"web_date_format":{"description":"Date format in the web app. `us` is the default for a team that never changed it; the web app shows it like `default` (Nov 05, 2026). A team whose saved settings have no date format reads `default`. \"Update general settings\" accepts only the other five values.","enum":["us","default","british_standard","us_standard","international","other_1"],"type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Turn off a feature add-on","tags":["Feature add-ons"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Use `cust_msg_status`.","status":404,"when":"The module is not `cust_msg_status`: `error.code` `page_not_found`, `error.message` null."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Treat the response as sensitive: besides your preferences it can carry the payment gateway values stored for the team. Don't log or share it."],"permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_setting_feature_addon_enable"],"rules":["`{module}` must be `cust_msg_status`; anything else returns 404."],"side_effects":["Team members who have YoPrint open see the setting change at once."]}}},"/v1/api/store/{team_slug}/setting/feature_addon/{module}/enable":{"put":{"description":"Turns on an optional feature. The only add-on is `cust_msg_status`, \"customer message statuses\": statuses for message threads, so you can track which conversations need a reply.\n\nWhen it is turned on and the team has no message thread statuses (deleted ones don't count), YoPrint adds three to the `customer_message` list: Awaiting Customer Reply (start), Need to Respond and Completed (end). Turning it on again keeps the statuses you have.\n\nThis doesn't change your YoPrint bill.\n\nReturns the full settings object, with `cust_msg_status: true`.","operationId":"v1_public_setting_feature_addon_enable","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The add-on. The only one is `cust_msg_status`, \"customer message statuses\".","example":"cust_msg_status","in":"path","name":"module","required":true,"schema":{"enum":["cust_msg_status"],"example":"cust_msg_status","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"column":[],"cust_msg_status":true,"customer_portal_account_login_available":true,"customer_portal_rollout":{"account_only":false,"all_teams_at":null,"configuration_warning":null,"legacy_access_allowed":true,"new_teams_at":null,"reason":"transition"},"default_pricing_strategy":"job_separately","dimension":"in","enable_stock_management":true,"pagination_per_page":50,"payment_amount_policies":{"USD":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null}},"payment_amount_policy":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null},"paypal_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/paypal","pdf_date_format":"us_standard","pdf_sales_order_display_option":["job_summary"],"shipping_label_create_cost_line_item":true,"square_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/square","stripe_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/stripe","web_date_format":"default","weight":"lbs"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"The team's settings: the saved general settings (the keys \"Update general settings\" takes, with their defaults), `column` (list columns), `cust_msg_status` (the add-on), the three payment webhook addresses, the read-only customer portal sign-in and payment minimum fields below, and the payment gateway values stored for the team, which can include secret keys (sensitive; treat as private). A team that never changed its date formats reads `pdf_date_format: \"std\"` and `web_date_format: \"us\"`, values outside the list the update takes.","properties":{"column":{"additionalProperties":true,"description":"List columns, by list name (`sales_order`, `quote`, ...). An empty array `[]` when none is saved.","type":["object","array"]},"cust_msg_status":{"description":"Whether the customer message statuses add-on is on.","type":"boolean"},"customer_portal_account_login_available":{"description":"Read only: whether customers can sign in to your customer portal with an email account. True when your plan includes the customer portal.","type":"boolean"},"customer_portal_rollout":{"additionalProperties":false,"description":"Read only: where the customer portal's move to email-account sign-in stands for your team. YoPrint sets the dates; you can't change them here.","properties":{"account_only":{"description":"True when customers must sign in with an email account: a portal link alone no longer opens the portal.","type":"boolean"},"all_teams_at":{"description":"From when every team is account-only (UTC), or null when not set.","format":"date-time","type":["string","null"]},"configuration_warning":{"description":"Set when YoPrint's own rollout dates are inconsistent; null normally.","enum":["new_teams_cutoff_not_before_all_teams_cutoff","invalid_rollout_date",null],"type":["string","null"]},"legacy_access_allowed":{"description":"The opposite of `account_only`: portal links still open the portal.","type":"boolean"},"new_teams_at":{"description":"From when new teams are account-only (UTC), or null when not set.","format":"date-time","type":["string","null"]},"reason":{"description":"`transition`: links still work. `new_team_cutoff`: the team was created after the date for new teams. `all_teams_cutoff`: the date for every team has passed.","enum":["transition","new_team_cutoff","all_teams_cutoff"],"type":"string"}},"required":["account_only","legacy_access_allowed","reason","new_teams_at","all_teams_at","configuration_warning"],"type":"object"},"pagination_per_page":{"type":"integer"},"payment_amount_policies":{"additionalProperties":{"additionalProperties":false,"properties":{"currency":{"example":"USD","type":"string"},"minimum_payment":{"additionalProperties":false,"description":"A decimal pair whose `value` is a string: the amount is `value` ÷ 10^`dp` (`{\"value\": \"1000\", \"dp\": 3}` is 1.00). YoPrint refuses smaller payments.","properties":{"dp":{"const":3,"type":"integer"},"value":{"type":"string"}},"required":["value","dp"],"type":"object"},"minimum_remaining_balance":{"description":"Always null here.","type":"null"}},"required":["currency","minimum_payment","minimum_remaining_balance"],"type":"object"},"description":"Read only: the same for each of your currencies, deleted ones included, keyed by ISO code (orders keep the currency they were made in). `[]` when the team has none.","type":["object","array"]},"payment_amount_policy":{"anyOf":[{"additionalProperties":false,"properties":{"currency":{"example":"USD","type":"string"},"minimum_payment":{"additionalProperties":false,"description":"A decimal pair whose `value` is a string: the amount is `value` ÷ 10^`dp` (`{\"value\": \"1000\", \"dp\": 3}` is 1.00). YoPrint refuses smaller payments.","properties":{"dp":{"const":3,"type":"integer"},"value":{"type":"string"}},"required":["value","dp"],"type":"object"},"minimum_remaining_balance":{"description":"Always null here.","type":"null"}},"required":["currency","minimum_payment","minimum_remaining_balance"],"type":"object"},{"type":"null"}],"description":"Read only: the smallest payment YoPrint takes in your default currency, or null when the team has no default currency."},"paypal_webhook_url":{"description":"The same for PayPal.","format":"uri","type":"string"},"pdf_date_format":{"description":"Date format on PDFs. `std` is the default for a team that never changed it; PDFs show it like `other_1` (05 Nov 2026). A team whose saved settings have no date format reads `other_1`. \"Update general settings\" accepts only the other five values.","enum":["std","default","british_standard","us_standard","international","other_1"],"type":"string"},"shipping_label_create_cost_line_item":{"description":"Whether \"Create Shipping Cost Line Item\" starts checked when someone buys a shipping label in the web app. `true` until changed.","type":"boolean"},"square_webhook_url":{"description":"The same for Square.","format":"uri","type":"string"},"stripe_webhook_url":{"description":"The address to give Stripe for this team's payment webhooks.","format":"uri","type":"string"},"web_date_format":{"description":"Date format in the web app. `us` is the default for a team that never changed it; the web app shows it like `default` (Nov 05, 2026). A team whose saved settings have no date format reads `default`. \"Update general settings\" accepts only the other five values.","enum":["us","default","british_standard","us_standard","international","other_1"],"type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Turn on a feature add-on","tags":["Feature add-ons"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Use `cust_msg_status`.","status":404,"when":"The module is not `cust_msg_status`: `error.code` `page_not_found`, `error.message` null."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Treat the response as sensitive: besides your preferences it can carry the payment gateway values stored for the team. Don't log or share it."],"permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_setting_feature_addon_disable","v1_public_status_list_customer_message"],"rules":["`{module}` must be `cust_msg_status`; anything else returns 404."],"side_effects":["Creates the three default message statuses when the list is empty.","Team members who have YoPrint open see the setting change at once."]}}},"/v1/api/store/{team_slug}/setting/fee_preset":{"get":{"description":"Returns all the team's fee presets in one list.\n\nFee presets are saved fee names and prices, such as a rush fee or a setup fee. A fee line item on a sales order does not link to a preset: copy the preset's name and price into the fee line.","operationId":"v1_public_fee_preset_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"id":"dJc8sLZs6Z6IB9","name":"Rush fee","price":25000}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"id":{"example":"dJc8sLZs6Z6IB9","type":"string"},"name":{"example":"Rush fee","type":"string"},"price":{"description":"The price. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). Null when none was set.","example":25000,"type":["integer","null"]}},"required":["id","name","price"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List fee presets","tags":["Fee presets"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_setting_fee_preset_search","v2_public_order_item_store"]}},"post":{"description":"Creates a fee preset and returns it.\n\nFee presets are saved fee names and prices, such as a rush fee or a setup fee. A fee line item on a sales order does not link to a preset: copy the preset's name and price into the fee line.","operationId":"v1_public_fee_preset_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"name":"Rush fee","price":25000},"schema":{"properties":{"name":{"type":"string"},"price":{"description":"The price. Send a whole number of thousandths: `25000` is 25.00.","type":"integer"}},"required":["name"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"id":"dJc8sLZs6Z6IB9","name":"Rush fee","price":25000},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"id":{"example":"dJc8sLZs6Z6IB9","type":"string"},"name":{"example":"Rush fee","type":"string"},"price":{"description":"The price. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). Null when none was set.","example":25000,"type":["integer","null"]}},"required":["id","name","price"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a fee preset","tags":["Fee presets"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`name` is missing, or `price` is not a whole number. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_fee_preset_index"],"rules":["`name` is required. `price` is optional; send a whole number of thousandths (`25000` is 25.00)."]}}},"/v1/api/store/{team_slug}/setting/fee_preset/search":{"post":{"description":"Returns up to 10 fee presets whose name contains `name`. With an empty `name`, it returns up to 10 presets. The order is not defined.\n\nFee presets are saved fee names and prices, such as a rush fee or a setup fee. A fee line item on a sales order does not link to a preset: copy the preset's name and price into the fee line.","operationId":"v1_public_setting_fee_preset_search","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"any":{"summary":"Any 10 presets","value":{"name":""}},"search":{"summary":"Names containing \"rush\"","value":{"name":"rush"}}},"schema":{"properties":{"name":{"description":"Text to look for in preset names. Required, but may be empty.","type":"string"}},"required":["name"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"id":"dJc8sLZs6Z6IB9","name":"Rush fee","price":25000}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"id":{"example":"dJc8sLZs6Z6IB9","type":"string"},"name":{"example":"Rush fee","type":"string"},"price":{"description":"The price. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). Null when none was set.","example":25000,"type":["integer","null"]}},"required":["id","name","price"],"type":"object"},"maxItems":10,"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Search fee presets by name","tags":["Fee presets"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`name` is missing or not a string. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Any team member can call it.","related":["v1_public_fee_preset_index"],"rules":["`name` must be sent. `null` counts as not sent and fails; send `\"\"` to match everything."]}}},"/v1/api/store/{team_slug}/setting/fee_preset/{hash_id}":{"delete":{"description":"Deletes a fee preset for good. Fee lines already on orders don't change.","operationId":"v1_public_fee_preset_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The fee preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"dJc8sLZs6Z6IB9","in":"path","name":"hash_id","required":true,"schema":{"example":"dJc8sLZs6Z6IB9","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a fee preset","tags":["Fee presets"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No fee preset with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Keep it, or rename it.","status":500,"when":"The preset was made by YoPrint (`error.code` is `delete_fail`)."}],"group":"Team settings","notes":["There is no restore."],"permission":"Needs the Manage Settings permission.","rules":["Presets made by YoPrint cannot be deleted. The API doesn't show which presets those are."]}},"get":{"description":"Returns one fee preset.","operationId":"v1_public_fee_preset_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The fee preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"dJc8sLZs6Z6IB9","in":"path","name":"hash_id","required":true,"schema":{"example":"dJc8sLZs6Z6IB9","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"id":"dJc8sLZs6Z6IB9","name":"Rush fee","price":25000},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"id":{"example":"dJc8sLZs6Z6IB9","type":"string"},"name":{"example":"Rush fee","type":"string"},"price":{"description":"The price. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). Null when none was set.","example":25000,"type":["integer","null"]}},"required":["id","name","price"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show a fee preset","tags":["Fee presets"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_fee_preset_update_patch"]}},"patch":{"description":"Use PUT to change a fee preset. PATCH saves the same fields but skips validation, so a price that is not a whole number fails with a server error.","operationId":"v1_public_fee_preset_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The fee preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"dJc8sLZs6Z6IB9","in":"path","name":"hash_id","required":true,"schema":{"example":"dJc8sLZs6Z6IB9","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"price":30000},"schema":{"properties":{"name":{"type":"string"},"price":{"description":"The price. Send a whole number of thousandths: `25000` is 25.00.","type":"integer"}},"required":[],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"id":"dJc8sLZs6Z6IB9","name":"Rush fee","price":30000},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"id":{"example":"dJc8sLZs6Z6IB9","type":"string"},"name":{"example":"Rush fee","type":"string"},"price":{"description":"The price. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). Null when none was set.","example":25000,"type":["integer","null"]}},"required":["id","name","price"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a fee preset without checks","tags":["Fee presets"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No fee preset with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Use PUT, or send `price` as a whole number of thousandths (`25000` is 25.00).","status":500,"when":"`price` is not a whole number. A generic server error, `{\"message\": \"Server Error\"}`; nothing is saved."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_fee_preset_show"]}},"put":{"description":"Changes a fee preset's name or price, and returns it. Fee lines already on orders don't change.","operationId":"v1_public_fee_preset_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The fee preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"dJc8sLZs6Z6IB9","in":"path","name":"hash_id","required":true,"schema":{"example":"dJc8sLZs6Z6IB9","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"price":30000},"schema":{"properties":{"name":{"type":"string"},"price":{"description":"The price. Send a whole number of thousandths: `25000` is 25.00.","type":"integer"}},"required":[],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"id":"dJc8sLZs6Z6IB9","name":"Rush fee","price":30000},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"id":{"example":"dJc8sLZs6Z6IB9","type":"string"},"name":{"example":"Rush fee","type":"string"},"price":{"description":"The price. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). Null when none was set.","example":25000,"type":["integer","null"]}},"required":["id","name","price"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a fee preset","tags":["Fee presets"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No fee preset with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`price` is not a whole number. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_fee_preset_show"]}}},"/v1/api/store/{team_slug}/setting/general":{"put":{"description":"Changes the team's general settings: units and date formats, PDF options, order and quote default dates, customer portal options, approval terms, tax labels, supplier catalogs and inventory automation.\n\nSend only the keys you change; the others keep their values. Keys not in the list are ignored. Arrays replace the saved array.\n\nReturns the full settings object.","operationId":"v1_public_setting_general_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"dimension":"in","pagination_per_page":50,"pdf_date_format":"us_standard","pdf_sales_order_display_option":["job_summary","created_by"],"weight":"lbs"},"schema":{"additionalProperties":false,"properties":{"auto_allocate_inventory_on_job_status_change":{"description":"Allocate inventory automatically when a job's status changes.","type":"boolean"},"auto_allocate_inventory_on_order_status_change":{"description":"Allocate inventory automatically when an order's status changes.","type":"boolean"},"catalog_alp":{"description":"Turns this supplier catalog on or off in product search.","type":"boolean"},"catalog_alpca":{"description":"Turns this supplier catalog on or off in product search.","type":"boolean"},"catalog_asc":{"description":"Turns this supplier catalog on or off in product search.","type":"boolean"},"catalog_augusta":{"description":"Turns this supplier catalog on or off in product search.","type":"boolean"},"catalog_augusta_ca":{"description":"Turns this supplier catalog on or off in product search.","type":"boolean"},"catalog_conde":{"description":"Turns this supplier catalog on or off in product search.","type":"boolean"},"catalog_delta":{"description":"Turns this supplier catalog on or off in product search.","type":"boolean"},"catalog_sanmar":{"description":"Turns this supplier catalog on or off in product search.","type":"boolean"},"catalog_sanmar_ca":{"description":"Turns this supplier catalog on or off in product search.","type":"boolean"},"catalog_ssa":{"description":"Turns this supplier catalog on or off in product search.","type":"boolean"},"catalog_ssaca":{"description":"Turns this supplier catalog on or off in product search.","type":"boolean"},"catalog_tsf":{"description":"Turns this supplier catalog on or off in product search.","type":"boolean"},"conde_markup_percentage":{"type":"number"},"cust_portal_direct_payment_link_bypass_enabled":{"type":"boolean"},"cust_portal_enable_balance_statement":{"type":"boolean"},"cust_portal_payment_option_default_enabled":{"type":"boolean"},"customer_payment_surcharge_test_disabled":{"description":"Used by YoPrint's own tests. It is saved, but YoPrint's production servers ignore it. Leave it out.","type":"boolean"},"default_pricing_strategy":{"description":"How new sales orders price their jobs: `job_separately`, `job_together` or `service_loc_together`.","enum":["job_separately","job_together","service_loc_together"],"type":"string"},"dimension":{"description":"Length unit.","enum":["m","cm","mm","in"],"type":"string"},"email_use_reply_to_as_from_email_address":{"type":"boolean"},"enable_cust_portal_custom_product_description":{"type":"boolean"},"enable_cust_portal_email_login":{"description":"Makes the customer portal's sign-in page ask the customer for their email address. YoPrint's servers only pass the setting on to the portal page. They do not use it to allow or refuse a portal link, so it does not make a link safe to share.","type":"boolean"},"enable_cust_portal_split_payment_button":{"type":"boolean"},"enable_customer_message":{"type":"boolean"},"enable_estimated_profit":{"type":"boolean"},"enable_ship_due_date":{"type":"boolean"},"enable_ship_packed_by":{"type":"boolean"},"enable_stock_management":{"type":"boolean"},"job_approval_term_text":{"description":"The terms customers accept when `show_job_approval_term` is on.","type":"string"},"message_use_customer_portal_link":{"description":"Message buttons link to the customer portal instead of a PDF.","type":"boolean"},"order_approval_term_text":{"description":"The terms customers accept when `show_order_approval_term` is on.","type":"string"},"order_due_day":{"type":"number"},"order_prod_end_day":{"description":"Default days from today to a new sales order's production end.","type":"number"},"order_prod_start_day":{"description":"Default days from today to a new sales order's production start.","type":"number"},"order_term_text":{"description":"The order terms text, used when `show_order_term` is on.","type":"string"},"pagination_per_page":{"description":"Rows per page in lists, and the page size of paged API lists.","maximum":100,"minimum":5,"type":"integer"},"pdf_bill_addr_show_primary_contact":{"description":"Show the primary contact in the billing address on PDFs.","type":"boolean"},"pdf_cp_packing_slip_option":{"items":{"enum":["customer_po_number"],"type":"string"},"type":"array"},"pdf_date_format":{"description":"Date format on PDFs.","enum":["default","british_standard","us_standard","international","other_1"],"type":"string"},"pdf_header_use_logo":{"description":"Show the team logo in PDF headers.","type":"boolean"},"pdf_internal_job_mockup_display_width":{"description":"Mockups per page in job and All Jobs PDFs, the same values. At `quarter` and `sixth` the mockups start on a new page after the job details.","enum":["full","half","quarter","sixth"],"type":"string"},"pdf_invoice_header_text":{"description":"The text printed in the invoice header when `show_pdf_invoice_header_text` is on.","type":"string"},"pdf_job_label_dymo_30336_option":{"items":{"enum":["customer_name","cust_due_date","order_label"],"type":"string"},"type":"array"},"pdf_job_label_option":{"items":{"enum":["customer_po_number"],"type":"string"},"type":"array"},"pdf_mockup_show_caption":{"description":"Print the caption bar (service, option and location, or the design and page name) under each mockup in these PDFs. On by default; off gives the pictures that room.","type":"boolean"},"pdf_order_term_text":{"description":"The terms text shown on PDFs when `show_pdf_order_term` is on.","type":"string"},"pdf_purchase_order_label_options":{"items":{"enum":["name"],"type":"string"},"type":"array"},"pdf_purchase_order_options":{"items":{"enum":["name"],"type":"string"},"type":"array"},"pdf_purchase_order_swap_address_location":{"type":"boolean"},"pdf_sales_order_display_option":{"items":{"enum":["job_summary","shipment_summary","created_by","hide_services"],"type":"string"},"type":"array"},"pdf_sales_order_mockup_display_width":{"description":"Mockups per page in quote and sales order PDFs: `full` 1, `half` 2, `quarter` 4 (two across, two down), `sixth` 6 (two across, three down). Pictures shrink so a page holds at least that many.","enum":["full","half","quarter","sixth"],"type":"string"},"pdf_sales_order_show_custom_product_description":{"type":"boolean"},"pdf_shipment_label_display_option":{"items":{"enum":["related_jobs","dates"],"type":"string"},"type":"array"},"pdf_show_contact_info":{"description":"Where PDFs show your contact details.","items":{"enum":["header_right","footer_left"],"type":"string"},"type":"array"},"pdf_show_packed_by":{"type":"boolean"},"pdf_show_related_order_in_po":{"description":"What a purchase order PDF shows about the sales orders it is for.","enum":["none","all","label_only","detail_only"],"type":"string"},"pdf_tax_show_customer_tax_number":{"description":"Show the customer's tax number.","type":"boolean"},"pdf_tax_show_team_tax_number":{"description":"Show your tax number in the contact details on PDFs.","type":"boolean"},"quote_due_day":{"type":"number"},"quote_prod_end_day":{"description":"Default days from today to a new quote's production end.","type":"number"},"quote_prod_start_day":{"description":"Default days from today to a new quote's production start.","type":"number"},"search_show_quote_invoices":{"description":"Include quotes' invoices in search. Off by default.","type":"boolean"},"search_show_quote_jobs":{"description":"Include quotes' jobs in search. Off by default.","type":"boolean"},"shipping_label_create_cost_line_item":{"description":"Whether \"Create Shipping Cost Line Item\" starts checked when someone buys a shipping label in the web app. Only the web app reads it. `true` or `false`; an empty value is refused.","type":"boolean"},"show_address_label_in_pdf":{"description":"Show the address label on PDFs.","type":"boolean"},"show_job_approval_term":{"description":"Ask customers to accept terms when they approve a job.","type":"boolean"},"show_order_approval_term":{"description":"Ask customers to accept terms when they approve an order.","type":"boolean"},"show_order_term":{"type":"boolean"},"show_payment_history_in_invoice":{"description":"Show the payment history on invoices.","type":"boolean"},"show_pdf_invoice_header_text":{"description":"Print `pdf_invoice_header_text` in the invoice header.","type":"boolean"},"show_pdf_order_term":{"type":"boolean"},"show_so_profit":{"type":"boolean"},"tax_invoice_label":{"description":"What invoices are called, for example `Tax Invoice`.","type":"string"},"tax_label_name":{"description":"The name of the tax column and total, for example `GST`.","type":"string"},"tax_number_label":{"description":"The label before a tax number, for example `TIN`.","type":"string"},"team_wide_notification_order":{"type":"boolean"},"ui_preference":{"additionalProperties":true,"type":"object"},"use_qr_code":{"type":"boolean"},"web_date_format":{"description":"Date format in the web app.","enum":["default","british_standard","us_standard","international","other_1"],"type":"string"},"weight":{"description":"Weight unit.","enum":["kg","g","lbs","oz"],"type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"column":[],"cust_msg_status":false,"customer_portal_account_login_available":true,"customer_portal_rollout":{"account_only":false,"all_teams_at":null,"configuration_warning":null,"legacy_access_allowed":true,"new_teams_at":null,"reason":"transition"},"default_pricing_strategy":"job_separately","dimension":"in","enable_stock_management":true,"pagination_per_page":50,"payment_amount_policies":{"USD":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null}},"payment_amount_policy":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null},"paypal_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/paypal","pdf_date_format":"us_standard","pdf_sales_order_display_option":["job_summary","created_by"],"shipping_label_create_cost_line_item":true,"square_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/square","stripe_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/stripe","web_date_format":"default","weight":"lbs"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"The team's settings: the saved general settings (the keys \"Update general settings\" takes, with their defaults), `column` (list columns), `cust_msg_status` (the add-on), the three payment webhook addresses, the read-only customer portal sign-in and payment minimum fields below, and the payment gateway values stored for the team, which can include secret keys (sensitive; treat as private). A team that never changed its date formats reads `pdf_date_format: \"std\"` and `web_date_format: \"us\"`, values outside the list the update takes.","properties":{"column":{"additionalProperties":true,"description":"List columns, by list name (`sales_order`, `quote`, ...). An empty array `[]` when none is saved.","type":["object","array"]},"cust_msg_status":{"description":"Whether the customer message statuses add-on is on.","type":"boolean"},"customer_portal_account_login_available":{"description":"Read only: whether customers can sign in to your customer portal with an email account. True when your plan includes the customer portal.","type":"boolean"},"customer_portal_rollout":{"additionalProperties":false,"description":"Read only: where the customer portal's move to email-account sign-in stands for your team. YoPrint sets the dates; you can't change them here.","properties":{"account_only":{"description":"True when customers must sign in with an email account: a portal link alone no longer opens the portal.","type":"boolean"},"all_teams_at":{"description":"From when every team is account-only (UTC), or null when not set.","format":"date-time","type":["string","null"]},"configuration_warning":{"description":"Set when YoPrint's own rollout dates are inconsistent; null normally.","enum":["new_teams_cutoff_not_before_all_teams_cutoff","invalid_rollout_date",null],"type":["string","null"]},"legacy_access_allowed":{"description":"The opposite of `account_only`: portal links still open the portal.","type":"boolean"},"new_teams_at":{"description":"From when new teams are account-only (UTC), or null when not set.","format":"date-time","type":["string","null"]},"reason":{"description":"`transition`: links still work. `new_team_cutoff`: the team was created after the date for new teams. `all_teams_cutoff`: the date for every team has passed.","enum":["transition","new_team_cutoff","all_teams_cutoff"],"type":"string"}},"required":["account_only","legacy_access_allowed","reason","new_teams_at","all_teams_at","configuration_warning"],"type":"object"},"pagination_per_page":{"type":"integer"},"payment_amount_policies":{"additionalProperties":{"additionalProperties":false,"properties":{"currency":{"example":"USD","type":"string"},"minimum_payment":{"additionalProperties":false,"description":"A decimal pair whose `value` is a string: the amount is `value` ÷ 10^`dp` (`{\"value\": \"1000\", \"dp\": 3}` is 1.00). YoPrint refuses smaller payments.","properties":{"dp":{"const":3,"type":"integer"},"value":{"type":"string"}},"required":["value","dp"],"type":"object"},"minimum_remaining_balance":{"description":"Always null here.","type":"null"}},"required":["currency","minimum_payment","minimum_remaining_balance"],"type":"object"},"description":"Read only: the same for each of your currencies, deleted ones included, keyed by ISO code (orders keep the currency they were made in). `[]` when the team has none.","type":["object","array"]},"payment_amount_policy":{"anyOf":[{"additionalProperties":false,"properties":{"currency":{"example":"USD","type":"string"},"minimum_payment":{"additionalProperties":false,"description":"A decimal pair whose `value` is a string: the amount is `value` ÷ 10^`dp` (`{\"value\": \"1000\", \"dp\": 3}` is 1.00). YoPrint refuses smaller payments.","properties":{"dp":{"const":3,"type":"integer"},"value":{"type":"string"}},"required":["value","dp"],"type":"object"},"minimum_remaining_balance":{"description":"Always null here.","type":"null"}},"required":["currency","minimum_payment","minimum_remaining_balance"],"type":"object"},{"type":"null"}],"description":"Read only: the smallest payment YoPrint takes in your default currency, or null when the team has no default currency."},"paypal_webhook_url":{"description":"The same for PayPal.","format":"uri","type":"string"},"pdf_date_format":{"description":"Date format on PDFs. `std` is the default for a team that never changed it; PDFs show it like `other_1` (05 Nov 2026). A team whose saved settings have no date format reads `other_1`. \"Update general settings\" accepts only the other five values.","enum":["std","default","british_standard","us_standard","international","other_1"],"type":"string"},"shipping_label_create_cost_line_item":{"description":"Whether \"Create Shipping Cost Line Item\" starts checked when someone buys a shipping label in the web app. `true` until changed.","type":"boolean"},"square_webhook_url":{"description":"The same for Square.","format":"uri","type":"string"},"stripe_webhook_url":{"description":"The address to give Stripe for this team's payment webhooks.","format":"uri","type":"string"},"web_date_format":{"description":"Date format in the web app. `us` is the default for a team that never changed it; the web app shows it like `default` (Nov 05, 2026). A team whose saved settings have no date format reads `default`. \"Update general settings\" accepts only the other five values.","enum":["us","default","british_standard","us_standard","international","other_1"],"type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update general settings","tags":["Company settings"],"x-yoprint-docs":{"errors":[{"fix":"Check the schema for that key.","status":422,"when":"A value has the wrong type or is not one of the allowed values (`validation_failed`; `error.fields` names the key)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Treat the response as sensitive: besides your preferences it can carry the payment gateway values stored for the team. Don't log or share it."],"permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_setting_detail_show","v1_public_setting_column_update"],"rules":["`pagination_per_page` is 5 to 100.","Some settings change what customers see: `enable_cust_portal_email_login` makes customers who open the portal from a link enter their email, and `message_use_customer_portal_link` changes where message buttons point.","`shipping_label_create_cost_line_item`, when sent, must be `true` or `false`: an empty string is refused.","The answer's `customer_portal_account_login_available`, `customer_portal_rollout`, `payment_amount_policy` and `payment_amount_policies` are worked out by YoPrint; sending them changes nothing."],"side_effects":["Applies to everyone on the team, and to the PDFs and portal pages made from now on.","When the job or order approval terms change (`show_job_approval_term`, `job_approval_term_text`, `show_order_approval_term`, `order_approval_term_text`), customers with an open approval of that kind who have the customer portal open get a live update."]}}},"/v1/api/store/{team_slug}/setting/group":{"get":{"description":"Returns all the team's permission groups in one list, with their permissions.\n\nPermission groups decide what members can do. Each member belongs to one group; the team owner can do everything. Teams start with groups such as Super Admin, Shop Manager, Sales Team, Shop Floor Team and Accounting Team. Creating, changing and deleting groups needs a plan with advanced permission management; moving a member to another group doesn't.","operationId":"v1_public_group_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"id":"aaNZmyj0mvmWLU","name":"Sales Team","permissions":["create_order","view_all_order","update_all_order","create_customer","view_all_customer"],"users":[{"avatar_url":null,"email":"alex@example.com","id":"ZiGXY6Fzqgi3AM","name":"Alex Rivera"}],"version":3}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"id":{"example":"aaNZmyj0mvmWLU","type":"string"},"name":{"example":"Sales Team","type":"string"},"permissions":{"description":"Permission keys. `manage_setting` is Manage Settings, `manage_billing` Manage Billing, `manage_stock` Manage Stock. For orders, quotes, purchase orders and customers, `*_all_*` covers every record and `*_self_*` (or `*_assigned_*`) only records assigned to the member. `view_order_finance` is View Sales Order Pricing; `view_customer_finance` is View Customer Sales Aggregates. Listed as saved, repeats included.","example":["create_order","view_all_order","update_all_order","create_customer","view_all_customer"],"items":{"enum":["manage_setting","manage_stock","manage_billing","view_production_board","create_product","update_product","view_product","create_service","update_service","view_service","create_order","view_all_order","view_self_order","update_all_order","update_self_order","message_all_order","message_self_order","create_quote","view_all_quote","view_self_quote","update_all_quote","update_self_quote","create_po","view_all_po","view_self_po","update_all_po","update_self_po","view_all_customer","view_assigned_customer","update_assigned_customer","update_all_customer","create_customer","view_vendor","update_vendor","create_vendor","view_report","view_customer_finance","view_order_finance"],"type":"string"},"type":"array"},"users":{"description":"The members in the group.","example":[{"avatar_url":null,"email":"alex@example.com","id":"ZiGXY6Fzqgi3AM","name":"Alex Rivera"}],"items":{"properties":{"avatar_url":{"example":null,"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"description":"The member's id, as List team members gives it.","example":"ZiGXY6Fzqgi3AM","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name","email","avatar_url"],"type":"object"},"type":"array"},"version":{"description":"The permission format. 3 for every group created or updated through the API.","example":3,"type":"integer"}},"required":["id","name","permissions","version","users"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List permission groups","tags":["Permission groups"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_group_change_user_group","v1_public_user_index"]}},"post":{"description":"Creates a permission group and returns it. Add members with Move a member to a permission group.\n\nPermission groups decide what members can do. Each member belongs to one group; the team owner can do everything. Teams start with groups such as Super Admin, Shop Manager, Sales Team, Shop Floor Team and Accounting Team. Creating, changing and deleting groups needs a plan with advanced permission management; moving a member to another group doesn't.","operationId":"v1_public_group_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"name":"Customer Service","permissions":["view_all_order","message_all_order","view_all_customer"]},"schema":{"properties":{"name":{"type":"string"},"permissions":{"description":"Permission keys. `manage_setting` is Manage Settings, `manage_billing` Manage Billing, `manage_stock` Manage Stock. For orders, quotes, purchase orders and customers, `*_all_*` covers every record and `*_self_*` (or `*_assigned_*`) only records assigned to the member. `view_order_finance` is View Sales Order Pricing; `view_customer_finance` is View Customer Sales Aggregates. Repeated keys are accepted and saved as sent.","items":{"enum":["manage_setting","manage_stock","manage_billing","view_production_board","create_product","update_product","view_product","create_service","update_service","view_service","create_order","view_all_order","view_self_order","update_all_order","update_self_order","message_all_order","message_self_order","create_quote","view_all_quote","view_self_quote","update_all_quote","update_self_quote","create_po","view_all_po","view_self_po","update_all_po","update_self_po","view_all_customer","view_assigned_customer","update_assigned_customer","update_all_customer","create_customer","view_vendor","update_vendor","create_vendor","view_report","view_customer_finance","view_order_finance"],"type":"string"},"minItems":1,"type":"array"}},"required":["name","permissions"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"id":"YwGhLn7Y8wEmF8","name":"Customer Service","permissions":["view_all_order","message_all_order","view_all_customer"],"users":[],"version":3},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"id":{"example":"aaNZmyj0mvmWLU","type":"string"},"name":{"example":"Sales Team","type":"string"},"permissions":{"description":"Permission keys. `manage_setting` is Manage Settings, `manage_billing` Manage Billing, `manage_stock` Manage Stock. For orders, quotes, purchase orders and customers, `*_all_*` covers every record and `*_self_*` (or `*_assigned_*`) only records assigned to the member. `view_order_finance` is View Sales Order Pricing; `view_customer_finance` is View Customer Sales Aggregates. Listed as saved, repeats included.","example":["create_order","view_all_order","update_all_order","create_customer","view_all_customer"],"items":{"enum":["manage_setting","manage_stock","manage_billing","view_production_board","create_product","update_product","view_product","create_service","update_service","view_service","create_order","view_all_order","view_self_order","update_all_order","update_self_order","message_all_order","message_self_order","create_quote","view_all_quote","view_self_quote","update_all_quote","update_self_quote","create_po","view_all_po","view_self_po","update_all_po","update_self_po","view_all_customer","view_assigned_customer","update_assigned_customer","update_all_customer","create_customer","view_vendor","update_vendor","create_vendor","view_report","view_customer_finance","view_order_finance"],"type":"string"},"type":"array"},"users":{"description":"The members in the group.","example":[{"avatar_url":null,"email":"alex@example.com","id":"ZiGXY6Fzqgi3AM","name":"Alex Rivera"}],"items":{"properties":{"avatar_url":{"example":null,"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"description":"The member's id, as List team members gives it.","example":"ZiGXY6Fzqgi3AM","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name","email","avatar_url"],"type":"object"},"type":"array"},"version":{"description":"The permission format. 3 for every group created or updated through the API.","example":3,"type":"integer"}},"required":["id","name","permissions","version","users"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/FeatureGatedValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a permission group","tags":["Permission groups"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Upgrade the plan.","status":422,"when":"The team's plan doesn't include advanced permission management. The body is short: `{\"message\": \"This feature is not available to your team's plan.\"}`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`name` is missing, `permissions` is empty, or it has an unknown key. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team's plan must include advanced permission management.","related":["v1_public_group_change_user_group"],"rules":["`name` and at least one permission are required.","Every permission must be a known key. Repeated keys are accepted and saved as sent."]}}},"/v1/api/store/{team_slug}/setting/group/{hash_id}":{"delete":{"description":"Deletes a permission group for good. A group that still has members cannot be deleted; move them to another group first.","operationId":"v1_public_group_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The permission group's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"aaNZmyj0mvmWLU","in":"path","name":"hash_id","required":true,"schema":{"example":"aaNZmyj0mvmWLU","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/FeatureGatedValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a permission group","tags":["Permission groups"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No permission group with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Upgrade the plan.","status":422,"when":"The team's plan doesn't include advanced permission management. The body is short: `{\"message\": \"This feature is not available to your team's plan.\"}`."},{"fix":"Move its members to another group with Move a member to a permission group.","status":422,"when":"The group still has members (`deleting_role_with_active_users_prohibited`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team's plan must include advanced permission management.","related":["v1_public_group_change_user_group"],"rules":["The group must have no members."]}},"get":{"description":"Returns one permission group with its permissions.","operationId":"v1_public_group_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The permission group's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"aaNZmyj0mvmWLU","in":"path","name":"hash_id","required":true,"schema":{"example":"aaNZmyj0mvmWLU","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"id":"aaNZmyj0mvmWLU","name":"Sales Team","permissions":["create_order","view_all_order","update_all_order","create_customer","view_all_customer"],"users":[{"avatar_url":null,"email":"alex@example.com","id":"ZiGXY6Fzqgi3AM","name":"Alex Rivera"}],"version":3},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"id":{"example":"aaNZmyj0mvmWLU","type":"string"},"name":{"example":"Sales Team","type":"string"},"permissions":{"description":"Permission keys. `manage_setting` is Manage Settings, `manage_billing` Manage Billing, `manage_stock` Manage Stock. For orders, quotes, purchase orders and customers, `*_all_*` covers every record and `*_self_*` (or `*_assigned_*`) only records assigned to the member. `view_order_finance` is View Sales Order Pricing; `view_customer_finance` is View Customer Sales Aggregates. Listed as saved, repeats included.","example":["create_order","view_all_order","update_all_order","create_customer","view_all_customer"],"items":{"enum":["manage_setting","manage_stock","manage_billing","view_production_board","create_product","update_product","view_product","create_service","update_service","view_service","create_order","view_all_order","view_self_order","update_all_order","update_self_order","message_all_order","message_self_order","create_quote","view_all_quote","view_self_quote","update_all_quote","update_self_quote","create_po","view_all_po","view_self_po","update_all_po","update_self_po","view_all_customer","view_assigned_customer","update_assigned_customer","update_all_customer","create_customer","view_vendor","update_vendor","create_vendor","view_report","view_customer_finance","view_order_finance"],"type":"string"},"type":"array"},"users":{"description":"The members in the group.","example":[{"avatar_url":null,"email":"alex@example.com","id":"ZiGXY6Fzqgi3AM","name":"Alex Rivera"}],"items":{"properties":{"avatar_url":{"example":null,"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"description":"The member's id, as List team members gives it.","example":"ZiGXY6Fzqgi3AM","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name","email","avatar_url"],"type":"object"},"type":"array"},"version":{"description":"The permission format. 3 for every group created or updated through the API.","example":3,"type":"integer"}},"required":["id","name","permissions","version","users"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show a permission group","tags":["Permission groups"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_group_update_patch"]}},"patch":{"description":"Use PUT to change a permission group. PATCH changes nothing and returns the group as it is, because YoPrint reads the body only for PUT.","operationId":"v1_public_group_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The permission group's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"aaNZmyj0mvmWLU","in":"path","name":"hash_id","required":true,"schema":{"example":"aaNZmyj0mvmWLU","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"id":"aaNZmyj0mvmWLU","name":"Sales Team","permissions":["create_order","view_all_order","update_all_order","create_customer","view_all_customer"],"users":[{"avatar_url":null,"email":"alex@example.com","id":"ZiGXY6Fzqgi3AM","name":"Alex Rivera"}],"version":3},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"id":{"example":"aaNZmyj0mvmWLU","type":"string"},"name":{"example":"Sales Team","type":"string"},"permissions":{"description":"Permission keys. `manage_setting` is Manage Settings, `manage_billing` Manage Billing, `manage_stock` Manage Stock. For orders, quotes, purchase orders and customers, `*_all_*` covers every record and `*_self_*` (or `*_assigned_*`) only records assigned to the member. `view_order_finance` is View Sales Order Pricing; `view_customer_finance` is View Customer Sales Aggregates. Listed as saved, repeats included.","example":["create_order","view_all_order","update_all_order","create_customer","view_all_customer"],"items":{"enum":["manage_setting","manage_stock","manage_billing","view_production_board","create_product","update_product","view_product","create_service","update_service","view_service","create_order","view_all_order","view_self_order","update_all_order","update_self_order","message_all_order","message_self_order","create_quote","view_all_quote","view_self_quote","update_all_quote","update_self_quote","create_po","view_all_po","view_self_po","update_all_po","update_self_po","view_all_customer","view_assigned_customer","update_assigned_customer","update_all_customer","create_customer","view_vendor","update_vendor","create_vendor","view_report","view_customer_finance","view_order_finance"],"type":"string"},"type":"array"},"users":{"description":"The members in the group.","example":[{"avatar_url":null,"email":"alex@example.com","id":"ZiGXY6Fzqgi3AM","name":"Alex Rivera"}],"items":{"properties":{"avatar_url":{"example":null,"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"description":"The member's id, as List team members gives it.","example":"ZiGXY6Fzqgi3AM","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name","email","avatar_url"],"type":"object"},"type":"array"},"version":{"description":"The permission format. 3 for every group created or updated through the API.","example":3,"type":"integer"}},"required":["id","name","permissions","version","users"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/FeatureGatedValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Touch a permission group","tags":["Permission groups"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No permission group with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Upgrade the plan.","status":422,"when":"The team's plan doesn't include advanced permission management. The body is short: `{\"message\": \"This feature is not available to your team's plan.\"}`."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team's plan must include advanced permission management.","related":["v1_public_group_update_patch"]}},"put":{"description":"Renames a group or replaces its permissions, and returns it. The change applies at once to every member of the group.\n\nThe web app stops you from editing your own group; the API doesn't. Be careful not to remove Manage Settings from your own group.","operationId":"v1_public_group_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The permission group's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"aaNZmyj0mvmWLU","in":"path","name":"hash_id","required":true,"schema":{"example":"aaNZmyj0mvmWLU","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"permissions":["view_all_order","message_all_order","update_all_order","view_all_customer"]},"schema":{"properties":{"name":{"type":"string"},"permissions":{"description":"Replaces the whole list. Permission keys. `manage_setting` is Manage Settings, `manage_billing` Manage Billing, `manage_stock` Manage Stock. For orders, quotes, purchase orders and customers, `*_all_*` covers every record and `*_self_*` (or `*_assigned_*`) only records assigned to the member. `view_order_finance` is View Sales Order Pricing; `view_customer_finance` is View Customer Sales Aggregates. Repeated keys are accepted and saved as sent.","items":{"enum":["manage_setting","manage_stock","manage_billing","view_production_board","create_product","update_product","view_product","create_service","update_service","view_service","create_order","view_all_order","view_self_order","update_all_order","update_self_order","message_all_order","message_self_order","create_quote","view_all_quote","view_self_quote","update_all_quote","update_self_quote","create_po","view_all_po","view_self_po","update_all_po","update_self_po","view_all_customer","view_assigned_customer","update_assigned_customer","update_all_customer","create_customer","view_vendor","update_vendor","create_vendor","view_report","view_customer_finance","view_order_finance"],"type":"string"},"minItems":1,"type":"array"}},"required":[],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"id":"aaNZmyj0mvmWLU","name":"Sales Team","permissions":["view_all_order","message_all_order","update_all_order","view_all_customer"],"users":[{"avatar_url":null,"email":"alex@example.com","id":"ZiGXY6Fzqgi3AM","name":"Alex Rivera"}],"version":3},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"id":{"example":"aaNZmyj0mvmWLU","type":"string"},"name":{"example":"Sales Team","type":"string"},"permissions":{"description":"Permission keys. `manage_setting` is Manage Settings, `manage_billing` Manage Billing, `manage_stock` Manage Stock. For orders, quotes, purchase orders and customers, `*_all_*` covers every record and `*_self_*` (or `*_assigned_*`) only records assigned to the member. `view_order_finance` is View Sales Order Pricing; `view_customer_finance` is View Customer Sales Aggregates. Listed as saved, repeats included.","example":["create_order","view_all_order","update_all_order","create_customer","view_all_customer"],"items":{"enum":["manage_setting","manage_stock","manage_billing","view_production_board","create_product","update_product","view_product","create_service","update_service","view_service","create_order","view_all_order","view_self_order","update_all_order","update_self_order","message_all_order","message_self_order","create_quote","view_all_quote","view_self_quote","update_all_quote","update_self_quote","create_po","view_all_po","view_self_po","update_all_po","update_self_po","view_all_customer","view_assigned_customer","update_assigned_customer","update_all_customer","create_customer","view_vendor","update_vendor","create_vendor","view_report","view_customer_finance","view_order_finance"],"type":"string"},"type":"array"},"users":{"description":"The members in the group.","example":[{"avatar_url":null,"email":"alex@example.com","id":"ZiGXY6Fzqgi3AM","name":"Alex Rivera"}],"items":{"properties":{"avatar_url":{"example":null,"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"description":"The member's id, as List team members gives it.","example":"ZiGXY6Fzqgi3AM","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"required":["id","name","email","avatar_url"],"type":"object"},"type":"array"},"version":{"description":"The permission format. 3 for every group created or updated through the API.","example":3,"type":"integer"}},"required":["id","name","permissions","version","users"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/FeatureGatedValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a permission group","tags":["Permission groups"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No permission group with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Upgrade the plan.","status":422,"when":"The team's plan doesn't include advanced permission management. The body is short: `{\"message\": \"This feature is not available to your team's plan.\"}`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`permissions` is empty or has an unknown key. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team's plan must include advanced permission management.","related":["v1_public_group_show"],"rules":["`permissions`, when sent, has at least one known key and replaces the list."],"side_effects":["Members of the group get the new permissions immediately."]}}},"/v1/api/store/{team_slug}/setting/group/{id}/change_user_group":{"patch":{"description":"Puts a team member in this permission group, taking them out of their current one, and returns the member with their group.\n\nThe path id is the group; `user_id` is the member. The new permissions apply at once.","operationId":"v1_public_group_change_user_group","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The permission group's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"aaNZmyj0mvmWLU","in":"path","name":"id","required":true,"schema":{"example":"aaNZmyj0mvmWLU","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"user_id":"ZiGXY6Fzqgi3AM"},"schema":{"properties":{"user_id":{"description":"The member's id, from List team members.","type":"string"}},"required":["user_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"avatar_url":null,"email":"alex@example.com","id":"ZiGXY6Fzqgi3AM","is_owner":false,"last_login_at":"2026-11-03T15:00:00+00:00","name":"Alex Rivera","roles":[{"id":"aaNZmyj0mvmWLU","name":"Sales Team"}],"timezone":"America/New_York"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"avatar_url":{"example":null,"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"ZiGXY6Fzqgi3AM","type":"string"},"is_owner":{"example":false,"type":"boolean"},"last_login_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":["string","null"]},"name":{"example":"Alex Rivera","type":"string"},"roles":{"description":"The member's permission group.","example":[{"id":"aaNZmyj0mvmWLU","name":"Sales Team"}],"items":{"properties":{"id":{"type":"string"},"name":{"type":"string"}},"type":"object"},"type":"array"},"timezone":{"example":"America/New_York","type":["string","null"]}},"required":["id","name","email","is_owner","roles"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Move a member to a permission group","tags":["Permission groups"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use ids from List permission groups and List team members.","status":404,"when":"No such group, or `user_id` is not a member of this team."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`user_id` is missing or is not a hash id. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_group_index","v1_public_user_index"],"rules":["`user_id` must be a member of this team."],"side_effects":["The member's permissions change at once.","Tells the team's open web app sessions about the change."]}}},"/v1/api/store/{team_slug}/setting/invite":{"get":{"description":"Returns the team's invitations that haven't been accepted yet, expired ones included (`expired: true`).\n\nEach one shows the email, the permission group the person will get, and when it expires. The invitation link itself is never returned.","operationId":"v1_public_invite_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"email":"jordan@example.com","expired":false,"expired_at":"2027-01-03T09:00:00+00:00","id":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","role":{"id":"drvVENtzY33bqP","name":"Production","permissions":["view_all_order","update_all_order"],"users":[{"avatar_url":null,"email":"alex@example.com","id":"E6LjYJJimQNFVF","name":"Alex Rivera"}],"version":3}}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"email":{"example":"jordan@example.com","type":"string"},"expired":{"description":"True two months after the invitation was first created.","type":"boolean"},"expired_at":{"description":"When it expires: two months after it was created. Resending does not move this date.","format":"date-time","type":"string"},"id":{"description":"The invitation's id: a UUID, not a hash id. Use it in the invitation paths.","example":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","format":"uuid","type":"string"},"role":{"additionalProperties":false,"description":"The permission group the person will join with. Null if that group was deleted since.","properties":{"id":{"type":"string"},"name":{"example":"Production","type":"string"},"permissions":{"description":"The group's permission keys, as \"Get a permission group\" returns them.","items":{"type":"string"},"type":"array"},"users":{"description":"The members who already hold this group.","items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"email":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","email","avatar_url"],"type":"object"},"type":"array"},"version":{"type":"integer"}},"required":["id","name","permissions","version","users"],"type":["object","null"]}},"required":["id","email","expired","expired_at"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List invitations","tags":["Team invitations"],"x-yoprint-docs":{"group":"Team settings","notes":["Every invitation in this list, expired or not, counts toward your plan's user limit. Delete the ones you no longer need."],"permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it. AI apps (MCP connections) need Manage Settings to read it.","related":["v1_public_invite_store","v1_public_team_invite_resend","v1_public_invite_destroy"]}},"post":{"description":"Invites a person by email, with the permission group they'll join with, and emails them a link.\n\n- Someone who already has a YoPrint account gets an email to join your team.\n- Anyone else gets an email to create an account and join.\n\nThey join when they accept. Until then the invitation is in the invitations list; it expires after two months.\n\nThe response has no data. Read the invitations list to get the new invitation's id.","operationId":"v1_public_invite_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"email":"jordan@example.com","role_id":"drvVENtzY33bqP"},"schema":{"additionalProperties":false,"properties":{"email":{"description":"Their email address, in standard English letters and symbols. Saved trimmed and in lowercase.","format":"email","type":"string"},"role_id":{"description":"The permission group they join with: an id from `GET /v1/api/store/{team_slug}/setting/group`.","type":"string"}},"required":["email","role_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Invite someone to the team","tags":["Team invitations"],"x-yoprint-docs":{"errors":[{"fix":"Check the email; delete the old invitation before inviting again.","status":422,"when":"`email` or `role_id` is missing or not valid, or the email already has an invitation on this team (`validation_failed`, with `error.fields.email` or `error.fields.role_id`)."},{"fix":"Don't invite members; delete the other invitation first.","status":422,"when":"`error.code` `validation_error`, with `error.message` saying why: \"User is already in the team.\" or \"An invitation for this email address is already pending.\" (an invitation for their account under another address)."},{"fix":"Use a group id from the groups list.","status":404,"when":"`role_id` is not one of your team's permission groups. `error.code` is null; `error.message` names the record type."},{"fix":"Contact YoPrint support before inviting it.","status":422,"when":"The address matches more than one old YoPrint account (`validation_error`)."},{"fix":"Remove a member or an invitation, or upgrade the plan.","status":403,"when":"Your plan's user limit is reached. The body is `{\"message\": \"Plan only allows a maximum of N users\"}`, without the error envelope."},{"fix":"Don't create it again. Resend it once mail works: `PATCH /v1/api/store/{team_slug}/setting/invite/resend/{invite}`.","status":503,"when":"The invitation was saved but the email could not be sent: `error.code` `invitation_delivery_failed`."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_invite_index","v1_public_team_invite_resend","v1_public_group_index"],"rules":["One pending invitation per email address: delete the old one before inviting again.","Someone already on the team can't be invited.","Your plan's user limit counts members plus every invitation in the list. When the next one would pass it, you get 403.","`role_id` must be one of this team's permission groups (404 otherwise)."],"side_effects":["Sends the invitation email."]}}},"/v1/api/store/{team_slug}/setting/invite/resend/{invite}":{"patch":{"description":"Emails the invitation again with a new link. The old link stops working.\n\nThe path takes the invitation's `id` from the list: a UUID, not a hash id.\n\nResending does not extend the invitation: it still expires two months after it was first created. For an expired one, delete it and invite again.","operationId":"v1_public_team_invite_resend","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The invitation's `id` from the invitation list: a UUID, not a hash id.","example":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","in":"path","name":"invite","required":true,"schema":{"example":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"email":"jordan@example.com","expired":false,"expired_at":"2027-01-03T09:00:00+00:00","id":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","role":{"id":"drvVENtzY33bqP","name":"Production","permissions":["view_all_order","update_all_order"],"users":[{"avatar_url":null,"email":"alex@example.com","id":"E6LjYJJimQNFVF","name":"Alex Rivera"}],"version":3}},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"email":{"example":"jordan@example.com","type":"string"},"expired":{"description":"True two months after the invitation was first created.","type":"boolean"},"expired_at":{"description":"When it expires: two months after it was created. Resending does not move this date.","format":"date-time","type":"string"},"id":{"description":"The invitation's id: a UUID, not a hash id. Use it in the invitation paths.","example":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","format":"uuid","type":"string"},"role":{"additionalProperties":false,"description":"The permission group the person will join with. Null if that group was deleted since.","properties":{"id":{"type":"string"},"name":{"example":"Production","type":"string"},"permissions":{"description":"The group's permission keys, as \"Get a permission group\" returns them.","items":{"type":"string"},"type":"array"},"users":{"description":"The members who already hold this group.","items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"email":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","email","avatar_url"],"type":"object"},"type":"array"},"version":{"type":"integer"}},"required":["id","name","permissions","version","users"],"type":["object","null"]}},"required":["id","email","expired","expired_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Resend an invitation","tags":["Team invitations"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Use an `id` from the invitations list.","status":404,"when":"No invitation of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Delete it and send a new invitation.","status":422,"when":"The invitation has expired (\"Invite is expired. Please generate a new one.\"), the invited account no longer exists, or its email changed without being verified. `error.code` is `validation_error`."},{"fix":"Wait a moment and resend.","status":503,"when":"The link was replaced but the email could not be sent: `error.code` `invitation_delivery_failed`."},{"fix":"Wait 10 minutes. The limit applies to AI apps only.","status":429,"when":"An AI app resent the same invitation less than 10 minutes ago: `error.code` `invitation_recently_sent`."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_invite_index","v1_public_invite_store"],"side_effects":["Replaces the invitation link and sends the email again."]}}},"/v1/api/store/{team_slug}/setting/invite/{invite}":{"delete":{"description":"Withdraws an invitation: its link stops working and it no longer counts toward your plan's user limit. No email is sent. The path takes the invitation's `id` from the list: a UUID, not a hash id.","operationId":"v1_public_invite_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The invitation's `id` from the invitation list: a UUID, not a hash id.","example":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","in":"path","name":"invite","required":true,"schema":{"example":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete an invitation","tags":["Team invitations"],"x-yoprint-docs":{"errors":[{"fix":"Use an `id` from the invitations list.","status":404,"when":"No invitation of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_invite_index","v1_public_invite_store"]}},"patch":{"description":"Use PUT to change an invitation's permission group. PATCH always fails with a server error.","operationId":"v1_public_invite_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The invitation's `id` from the invitation list: a UUID, not a hash id.","example":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","in":"path","name":"invite","required":true,"schema":{"example":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"role_id":"drvVENtzY33bqP"},"schema":{"additionalProperties":false,"properties":{"role_id":{"description":"One of this team's permission groups, from `GET /v1/api/store/{team_slug}/setting/group`.","type":"string"}},"required":["role_id"],"type":"object"}}},"required":true},"responses":{"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change an invitation with PATCH","tags":["Team invitations"],"x-yoprint-docs":{"errors":[{"fix":"Use PUT.","status":500,"when":"You called it with PATCH. The body is `{\"message\": \"Server Error\"}`, without the error envelope."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_invite_index","v1_public_group_index"]}},"put":{"description":"Changes which permission group the person will join with. No email is sent.\n\nThe path takes the invitation's `id` from the list: a UUID, not a hash id.\n\nUse PUT. PATCH has no rules and fails with 500.\n\nAn expired invitation is left as it is, and the call still succeeds: check `expired` in the response.","operationId":"v1_public_invite_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The invitation's `id` from the invitation list: a UUID, not a hash id.","example":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","in":"path","name":"invite","required":true,"schema":{"example":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"role_id":"drvVENtzY33bqP"},"schema":{"additionalProperties":false,"properties":{"role_id":{"description":"One of this team's permission groups, from `GET /v1/api/store/{team_slug}/setting/group`.","type":"string"}},"required":["role_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"email":"jordan@example.com","expired":false,"expired_at":"2027-01-03T09:00:00+00:00","id":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","role":{"id":"drvVENtzY33bqP","name":"Production","permissions":["view_all_order","update_all_order"],"users":[{"avatar_url":null,"email":"alex@example.com","id":"E6LjYJJimQNFVF","name":"Alex Rivera"}],"version":3}},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"email":{"example":"jordan@example.com","type":"string"},"expired":{"description":"True two months after the invitation was first created.","type":"boolean"},"expired_at":{"description":"When it expires: two months after it was created. Resending does not move this date.","format":"date-time","type":"string"},"id":{"description":"The invitation's id: a UUID, not a hash id. Use it in the invitation paths.","example":"0b5e8c1a-3f4d-4c2b-9a7e-1d2c3b4a5f60","format":"uuid","type":"string"},"role":{"additionalProperties":false,"description":"The permission group the person will join with. Null if that group was deleted since.","properties":{"id":{"type":"string"},"name":{"example":"Production","type":"string"},"permissions":{"description":"The group's permission keys, as \"Get a permission group\" returns them.","items":{"type":"string"},"type":"array"},"users":{"description":"The members who already hold this group.","items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"email":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","email","avatar_url"],"type":"object"},"type":"array"},"version":{"type":"integer"}},"required":["id","name","permissions","version","users"],"type":["object","null"]}},"required":["id","email","expired","expired_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change an invitation's permission group","tags":["Team invitations"],"x-yoprint-docs":{"errors":[{"fix":"Use an `id` from the invitations list.","status":404,"when":"No invitation of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Send a group id from the groups list.","status":422,"when":"`role_id` is missing or not an id (`validation_failed`)."},{"fix":"Use a group id from the groups list.","status":404,"when":"`role_id` is not one of your team's permission groups. `error.code` is null; `error.message` names the record type."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_invite_index","v1_public_group_index"]}}},"/v1/api/store/{team_slug}/setting/job_preset":{"get":{"description":"Returns all of the team's job presets, sorted by `position`, each with its service lines (`service`), tasks (`pipeline`), the people on the job (`assigned_users`) and its files (`mockup`, `production_file`).\n\nA job preset is a ready-made job. Adding a job from a preset to a sales order or quote copies its name, note, services, tasks, people and files into a new job. Check `needs_review` before you use one: it is true when something the preset points to was deleted, or a person on a task left the team.","operationId":"v1_public_job_preset_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"assigned_users":[],"id":"8vxTyCrd1y1gdf","is_valid":true,"mockup":[{"collection":"mockup","created_at":"2026-11-03T09:00:00+00:00","custom_properties":{"show_in_pdf":true},"file_name":"front-logo.png","id":"uAzgeGQMGvaVK3","is_image":true,"job_preset_id":"8vxTyCrd1y1gdf","job_service":["amcoNda0bOuIpO"],"mime_type":"image/png","name":"Front logo","position":1,"preview":{"large":"https://example.com/media/uAzgeGQMGvaVK3/preview-1200.png","medium":"https://example.com/media/uAzgeGQMGvaVK3/preview-800.png","small":"https://example.com/media/uAzgeGQMGvaVK3/preview-250.png"},"show_in_pdf":true,"size":48211,"source_media_id":null,"url":"https://example.com/media/uAzgeGQMGvaVK3/download","view_url":"https://example.com/media/uAzgeGQMGvaVK3/view"}],"name":"Front print, one color","needs_review":false,"note":"Standard tee front print","pipeline":[{"assigned_users":[{"avatar_url":null,"id":"E6LjYJJimQNFVF","name":"Alex Rivera","removed":false}],"id":"87uNbl9N8J0OPz","is_valid":true,"name":"Print","note":null,"pipeline":{"color":"#FFFFFF","enable":true,"id":"eIOQnV5PP0pp7c","label":"Screen printing","statuses":[{"color":"#f5f5f5","customer_label":"Pending","id":"fA3KDzwnMRc5Cd","label":"To do","pipeline_id":"eIOQnV5PP0pp7c","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#424242","customer_label":"Completed","id":"MIJM9QpP6O0whd","label":"Done","pipeline_id":"eIOQnV5PP0pp7c","position":1,"role":"pipeline","trashed":false,"type":"end"}],"trashed":false,"version":1},"pipeline_color":"#FFFFFF","pipeline_id":"eIOQnV5PP0pp7c","pipeline_name":"Screen printing","position":1,"trashed":false}],"position":"1.0000000000000000","production_file":[],"service":[{"customer_note":"Printed on the front, centered","id":"amcoNda0bOuIpO","location":{"display_name":"Front","id":"t1vO0qwTosoy1d","trashed":false,"type":"database"},"note":null,"option":"1 Color","position":1,"review_reason":null,"service_id":"sV7LFB1gpCcF8O","service_name":"Screen printing","valid":true,"version":1}],"updated_at":"2026-11-03T09:00:00+00:00"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"assigned_users":{"description":"The people on the job itself. Jobs made from the preset get the ones still on your team.","items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"example":"8vxTyCrd1y1gdf","type":"string"},"is_valid":{"description":"False when a service, saved location, or task preset it uses was deleted, or a service option no longer exists.","type":"boolean"},"mockup":{"description":"Mockup images, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"name":{"example":"Front print, one color","type":"string"},"needs_review":{"description":"True when the preset needs review (shown as \"Needs review\" in the web app):\n\n- `is_valid` is false (a service, service option, saved location, or task preset was deleted)\n- A team member assigned to one of its tasks was deleted or left the team (assignees on the job itself do not trigger review)\n\nA preset that needs review still saves. Creating a job from it omits missing tasks and removed teammates.","type":"boolean"},"note":{"type":["string","null"]},"pipeline":{"description":"The tasks.","items":{"additionalProperties":true,"properties":{"assigned_users":{"items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"type":"string"},"is_valid":{"type":"boolean"},"name":{"type":["string","null"]},"note":{"type":["string","null"]},"pipeline":{"additionalProperties":true,"description":"The task preset it follows, as `GET /v1/api/store/{team_slug}/setting/pipeline/{hash_id}` returns it: `id`, `label`, `color`, `version`, `enable`, `trashed`, and its `statuses` (deleted ones included).","properties":{"color":{"type":"string"},"enable":{"type":"boolean"},"id":{"type":"string"},"label":{"type":"string"},"statuses":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"trashed":{"type":"boolean"},"version":{"type":"integer"}},"type":["object","null"]},"pipeline_color":{"description":"The task preset's color.","type":["string","null"]},"pipeline_id":{"type":"string"},"pipeline_name":{"description":"The task preset's name.","type":["string","null"]},"position":{"description":"0 when none was sent.","type":"integer"},"trashed":{"description":"True when its task preset was deleted.","type":"boolean"}},"type":"object"},"type":"array"},"position":{"description":"Sort order within the preset list, lowest first. A decimal string, such as `\"1.0000000000000000\"`; parse it as a decimal.","example":"1.0000000000000000","type":"string"},"production_file":{"description":"Production files, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"service":{"description":"The service lines.","items":{"additionalProperties":true,"properties":{"customer_note":{"type":["string","null"]},"id":{"type":"string"},"location":{"additionalProperties":true,"description":"`type`, `display_name` and `trashed` (true when a saved location was deleted), plus `id` for a saved location or `name` for a custom one.","type":"object"},"note":{"type":["string","null"]},"option":{"type":["string","null"]},"position":{"type":"integer"},"review_reason":{"description":"Why the line needs review: its service was deleted, the service no longer has this option, or its saved location was deleted. Null when the line is fine.","enum":["service_removed","option_removed","location_removed",null],"type":["string","null"]},"service_id":{"type":"string"},"service_name":{"type":["string","null"]},"valid":{"description":"False when `review_reason` is set.","type":"boolean"},"version":{"const":1,"type":"integer"}},"type":"object"},"type":"array"},"updated_at":{"description":"When the preset was last edited (\"Last edited\" in the web app). Every save changes it, even one that changes only its lines; reordering presets doesn't.","format":"date-time","type":["string","null"]}},"required":["id","name","note","position","is_valid","needs_review","updated_at","service","pipeline","assigned_users","mockup","production_file"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List job presets","tags":["Job presets"],"x-yoprint-docs":{"group":"Team settings","notes":["File `view_url` links expire. Read the preset again when you need them."],"permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_setting_job_preset_search","v1_public_job_preset_store"]}},"post":{"description":"Saves a job preset, a ready-made job: a name, an optional note, the service lines (`service`), the tasks (`pipeline`), the people on the job (`assigned_users`) and files (`mockup`, `production_file`). It goes to the end of the list.\n\nEach service line names a service, one of its options and where it goes on the product. Each task names the task preset it follows and who does it. Files are uploaded first with \"Upload a file\", then attached here by the upload's `id`; give a new service line a `tmpid-` id to link a file to it in the same request. Everything is checked against your team first; if anything doesn't match, nothing is saved.\n\nReturns the new preset.","operationId":"v1_public_job_preset_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"mockup":[{"action":"create","id":"uAzgeGQMGvaVK3","job_service":"tmpid-1","name":"Front logo","show_in_pdf":true}],"name":"Front print, one color","note":"Standard tee front print","pipeline":[{"action":"create","assigned_users":[{"id":"E6LjYJJimQNFVF"}],"name":"Print","pipeline_id":"eIOQnV5PP0pp7c","position":1}],"service":[{"action":"create","customer_note":"Printed on the front, centered","id":"tmpid-1","location":{"id":"t1vO0qwTosoy1d","type":"database"},"option":"1 Color","position":1,"service_id":"sV7LFB1gpCcF8O"}]},"schema":{"additionalProperties":false,"properties":{"assigned_users":{"description":"The people on the job itself. Each must be an active member of your team.","items":{"additionalProperties":false,"properties":{"id":{"description":"A team member's id, from `GET /v1/api/store/{team_slug}/setting/user`.","type":"string"}},"required":["id"],"type":"object"},"type":"array"},"mockup":{"description":"Mockup images. A `create` row must be an image file.","items":{"additionalProperties":false,"properties":{"action":{"description":"Send `create`: it attaches a file you uploaded with \"Upload a file\" (`POST /v1/api/store/{team_slug}/async_upload`). A new preset has no files to `update` or `delete` yet.","enum":["create","update","delete"],"type":"string"},"id":{"description":"For `create`, the upload's `id`. For `update` and `delete`, the file's `id` from the preset's `mockup` list.","type":"string"},"job_service":{"description":"The service line, or a list of them, this file belongs to: a line's `id`, or the `tmpid-` id of a line created in the same request. Ids that are not lines of this preset are ignored. When sent, it replaces the file's links; `[]` removes them.","items":{"type":"string"},"type":["string","array"]},"name":{"description":"The file's display name. Left out, it keeps its name.","type":"string"},"position":{"description":"For `update`: where the file sorts among the preset's mockups. A `create` row always goes last.","type":"integer"},"show_in_pdf":{"description":"Whether the mockup shows on PDFs. Jobs made from the preset keep the setting.","type":"boolean"}},"required":["action","id"],"type":"object"},"type":"array"},"name":{"type":"string"},"note":{"type":["string","null"]},"pipeline":{"items":{"additionalProperties":false,"properties":{"action":{"description":"Required, but every task is created on a new preset whatever you send. Send `create`.","enum":["create","update","delete"],"type":"string"},"assigned_users":{"description":"Who the task is assigned to; without it, nobody. Each must be an active member of your team.","items":{"additionalProperties":false,"properties":{"id":{"description":"A team member's id, from `GET /v1/api/store/{team_slug}/setting/user`.","type":"string"}},"required":["id"],"type":"object"},"type":"array"},"name":{"description":"The task's name.","type":"string"},"note":{"type":["string","null"]},"pipeline_id":{"description":"The task preset this task follows, from `GET /v1/api/store/{team_slug}/setting/pipeline`. Required unless `action` is `delete`. A new task, or one that changes it, needs a task preset that isn't deleted.","type":"string"},"position":{"maximum":2147483647,"minimum":-2147483648,"type":"integer"}},"required":["action"],"type":"object"},"type":"array"},"production_file":{"description":"Production files, of any type.","items":{"additionalProperties":false,"properties":{"action":{"description":"Send `create`: it attaches a file you uploaded with \"Upload a file\" (`POST /v1/api/store/{team_slug}/async_upload`). A new preset has no files to `update` or `delete` yet.","enum":["create","update","delete"],"type":"string"},"id":{"description":"For `create`, the upload's `id`. For `update` and `delete`, the file's `id` from the preset's `production_file` list.","type":"string"},"job_service":{"description":"The service line, or a list of them, this file belongs to: a line's `id`, or the `tmpid-` id of a line created in the same request. Ids that are not lines of this preset are ignored. When sent, it replaces the file's links; `[]` removes them.","items":{"type":"string"},"type":["string","array"]},"name":{"description":"The file's display name. Left out, it keeps its name.","type":"string"},"position":{"description":"For `update`: where the file sorts among the preset's production files. A `create` row always goes last.","type":"integer"},"show_in_pdf":{"description":"Saved on the file and copied to jobs made from the preset.","type":"boolean"}},"required":["action","id"],"type":"object"},"type":"array"},"service":{"items":{"additionalProperties":false,"properties":{"action":{"description":"Required, but every line is created on a new preset whatever you send. Send `create`.","enum":["create","update","delete"],"type":"string"},"customer_note":{"description":"A note the customer sees. Jobs made from the preset get it on their service.","type":["string","null"]},"id":{"description":"Optional: a temporary id that starts with `tmpid-` (such as `tmpid-1`), so a file row in the same request can name this line in `job_service`.","type":"string"},"location":{"additionalProperties":false,"description":"Where the service goes on the product. Required unless `action` is `delete`.","properties":{"id":{"description":"Required when `type` is `database`. A new or changed location must not be deleted. Ignored for `custom`.","type":"string"},"name":{"description":"Required when `type` is `custom`.","type":"string"},"type":{"description":"`database`: one of your saved service locations, by `id` (from `GET /v1/api/store/{team_slug}/service_location`). `custom`: a one-off location, by `name`.","enum":["database","custom"],"type":"string"}},"required":["type"],"type":"object"},"note":{"description":"A production note for this service.","type":["string","null"]},"option":{"description":"One of the service's options (a column of its price table). Required unless `action` is `delete`. Any value saves, but one the service doesn't have marks the preset `is_valid: false`.","type":"string"},"position":{"description":"Order of the service lines. Required unless `action` is `delete`.","maximum":2147483647,"minimum":-2147483648,"type":"integer"},"service_id":{"description":"The decoration service ID. Required unless `action` is `delete`. The service must be active (not deleted). Services are not listed directly on the public API; copy `service_id` from an existing job preset (List job presets) or from a job's services.","type":"string"}},"required":["action"],"type":"object"},"type":"array"}},"required":["name"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"id":"8vxTyCrd1y1gdf","is_valid":true,"mockup":[{"collection":"mockup","created_at":"2026-11-03T09:00:00+00:00","custom_properties":{"show_in_pdf":true},"file_name":"front-logo.png","id":"uAzgeGQMGvaVK3","is_image":true,"job_preset_id":"8vxTyCrd1y1gdf","job_service":["amcoNda0bOuIpO"],"mime_type":"image/png","name":"Front logo","position":1,"preview":{"large":"https://example.com/media/uAzgeGQMGvaVK3/preview-1200.png","medium":"https://example.com/media/uAzgeGQMGvaVK3/preview-800.png","small":"https://example.com/media/uAzgeGQMGvaVK3/preview-250.png"},"show_in_pdf":true,"size":48211,"source_media_id":null,"url":"https://example.com/media/uAzgeGQMGvaVK3/download","view_url":"https://example.com/media/uAzgeGQMGvaVK3/view"}],"name":"Front print, one color","needs_review":false,"note":"Standard tee front print","pipeline":[{"assigned_users":[{"avatar_url":null,"id":"E6LjYJJimQNFVF","name":"Alex Rivera","removed":false}],"id":"87uNbl9N8J0OPz","is_valid":true,"name":"Print","note":null,"pipeline":{"color":"#FFFFFF","enable":true,"id":"eIOQnV5PP0pp7c","label":"Screen printing","statuses":[{"color":"#f5f5f5","customer_label":"Pending","id":"fA3KDzwnMRc5Cd","label":"To do","pipeline_id":"eIOQnV5PP0pp7c","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#424242","customer_label":"Completed","id":"MIJM9QpP6O0whd","label":"Done","pipeline_id":"eIOQnV5PP0pp7c","position":1,"role":"pipeline","trashed":false,"type":"end"}],"trashed":false,"version":1},"pipeline_color":"#FFFFFF","pipeline_id":"eIOQnV5PP0pp7c","pipeline_name":"Screen printing","position":1,"trashed":false}],"position":"1.0000000000000000","production_file":[],"service":[{"customer_note":"Printed on the front, centered","id":"amcoNda0bOuIpO","location":{"display_name":"Front","id":"t1vO0qwTosoy1d","trashed":false,"type":"database"},"note":null,"option":"1 Color","position":1,"review_reason":null,"service_id":"sV7LFB1gpCcF8O","service_name":"Screen printing","valid":true,"version":1}],"updated_at":"2026-11-03T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"assigned_users":{"description":"The people on the job itself. Jobs made from the preset get the ones still on your team.","items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"example":"8vxTyCrd1y1gdf","type":"string"},"is_valid":{"description":"False when a service, saved location, or task preset it uses was deleted, or a service option no longer exists.","type":"boolean"},"mockup":{"description":"Mockup images, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"name":{"example":"Front print, one color","type":"string"},"needs_review":{"description":"True when the preset needs review (shown as \"Needs review\" in the web app):\n\n- `is_valid` is false (a service, service option, saved location, or task preset was deleted)\n- A team member assigned to one of its tasks was deleted or left the team (assignees on the job itself do not trigger review)\n\nA preset that needs review still saves. Creating a job from it omits missing tasks and removed teammates.","type":"boolean"},"note":{"type":["string","null"]},"pipeline":{"description":"The tasks.","items":{"additionalProperties":true,"properties":{"assigned_users":{"items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"type":"string"},"is_valid":{"type":"boolean"},"name":{"type":["string","null"]},"note":{"type":["string","null"]},"pipeline":{"additionalProperties":true,"description":"The task preset it follows, as `GET /v1/api/store/{team_slug}/setting/pipeline/{hash_id}` returns it: `id`, `label`, `color`, `version`, `enable`, `trashed`, and its `statuses` (deleted ones included).","properties":{"color":{"type":"string"},"enable":{"type":"boolean"},"id":{"type":"string"},"label":{"type":"string"},"statuses":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"trashed":{"type":"boolean"},"version":{"type":"integer"}},"type":["object","null"]},"pipeline_color":{"description":"The task preset's color.","type":["string","null"]},"pipeline_id":{"type":"string"},"pipeline_name":{"description":"The task preset's name.","type":["string","null"]},"position":{"description":"0 when none was sent.","type":"integer"},"trashed":{"description":"True when its task preset was deleted.","type":"boolean"}},"type":"object"},"type":"array"},"position":{"description":"Sort order within the preset list, lowest first. A decimal string, such as `\"1.0000000000000000\"`; parse it as a decimal.","example":"1.0000000000000000","type":"string"},"production_file":{"description":"Production files, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"service":{"description":"The service lines.","items":{"additionalProperties":true,"properties":{"customer_note":{"type":["string","null"]},"id":{"type":"string"},"location":{"additionalProperties":true,"description":"`type`, `display_name` and `trashed` (true when a saved location was deleted), plus `id` for a saved location or `name` for a custom one.","type":"object"},"note":{"type":["string","null"]},"option":{"type":["string","null"]},"position":{"type":"integer"},"review_reason":{"description":"Why the line needs review: its service was deleted, the service no longer has this option, or its saved location was deleted. Null when the line is fine.","enum":["service_removed","option_removed","location_removed",null],"type":["string","null"]},"service_id":{"type":"string"},"service_name":{"type":["string","null"]},"valid":{"description":"False when `review_reason` is set.","type":"boolean"},"version":{"const":1,"type":"integer"}},"type":"object"},"type":"array"},"updated_at":{"description":"When the preset was last edited (\"Last edited\" in the web app). Every save changes it, even one that changes only its lines; reordering presets doesn't.","format":"date-time","type":["string","null"]}},"required":["id","name","note","position","is_valid","needs_review","updated_at","service","pipeline","assigned_users","mockup","production_file"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a job preset","tags":["Job presets"],"x-yoprint-docs":{"errors":[{"fix":"Send every required field; see the schema.","status":422,"when":"`name` is missing (create), a line or file row has no `action`, a file row has no `id`, or a service line misses `service_id`, `option`, `location.type` or `position` (`validation_failed`)."},{"fix":"Use ids from your own team's lists, and upload files first.","status":422,"when":"A service, location, task preset or person is not your team's, or is deleted where a live one is needed; or a file row names a file that isn't a free upload, or a mockup that isn't an image. `error.code` `job_validation_error`, with a message such as \"Service not found!\", \"Assigned User not found!\", \"Please upload this file before adding it to a job preset.\" or \"Mockups must be image files.\""},{"fix":"Use the upload's `id`, or a file `id` from the preset.","status":404,"when":"A `create` file row names no upload of your team, or an `update` or `delete` file row names a file that isn't this preset's. `error.code` is null."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_async_upload_store","v1_public_job_preset_update_patch","v1_public_job_preset_duplicate","v1_public_pipeline_index"],"rules":["Everything is checked against your team before anything is saved, and the whole save is one transaction: one refusal saves nothing.","A new line, task or person, and any reference you change, must be live: a service, saved location and task preset that aren't deleted, and people who are active members of your team. An `update` line that keeps a deleted service, location or task preset, or a person who has left, still saves.","A service `option` the service doesn't have still saves, but the preset reads `is_valid: false`.","Top-level `assigned_users` sets the people on the job itself: sent, it replaces them (`[]` removes everyone); left out, they stay. On a task `update` line, `assigned_users` works the same way; a task `create` line without it has nobody.","Files: a `create` row attaches a file you uploaded with \"Upload a file\" and not yet attached anywhere; a mockup must be an image. `update` and `delete` rows act only on this preset's own files; one that is already gone is skipped."],"side_effects":["Attaching an upload moves it onto the preset: it is no longer a free upload.","Team members who have YoPrint open see the new preset at once."]}}},"/v1/api/store/{team_slug}/setting/job_preset/arrange":{"put":{"description":"Sets the `position` of the presets you list; the list sorts by it, lowest first. Presets you leave out keep their position. Reordering is not an edit: each preset keeps its `updated_at`.\n\nReturns the whole list in its new order.","operationId":"v1_public_job_preset_arrange","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"items":[{"id":"8vxTyCrd1y1gdf","position":2},{"id":"AzOhNmKymBsfdL","position":1}]},"schema":{"additionalProperties":false,"properties":{"items":{"items":{"additionalProperties":false,"properties":{"id":{"description":"A job preset's id.","type":"string"},"position":{"description":"Its new sort position.","type":"number"}},"required":["id","position"],"type":"object"},"minItems":1,"type":"array"}},"required":["items"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"assigned_users":[],"id":"AzOhNmKymBsfdL","is_valid":true,"mockup":[],"name":"Back print, full color","needs_review":false,"note":null,"pipeline":[],"position":"1.0000000000000000","production_file":[],"service":[],"updated_at":"2026-10-28T09:00:00+00:00"},{"assigned_users":[],"id":"8vxTyCrd1y1gdf","is_valid":true,"mockup":[{"collection":"mockup","created_at":"2026-11-03T09:00:00+00:00","custom_properties":{"show_in_pdf":true},"file_name":"front-logo.png","id":"uAzgeGQMGvaVK3","is_image":true,"job_preset_id":"8vxTyCrd1y1gdf","job_service":["amcoNda0bOuIpO"],"mime_type":"image/png","name":"Front logo","position":1,"preview":{"large":"https://example.com/media/uAzgeGQMGvaVK3/preview-1200.png","medium":"https://example.com/media/uAzgeGQMGvaVK3/preview-800.png","small":"https://example.com/media/uAzgeGQMGvaVK3/preview-250.png"},"show_in_pdf":true,"size":48211,"source_media_id":null,"url":"https://example.com/media/uAzgeGQMGvaVK3/download","view_url":"https://example.com/media/uAzgeGQMGvaVK3/view"}],"name":"Front print, one color","needs_review":false,"note":"Standard tee front print","pipeline":[{"assigned_users":[{"avatar_url":null,"id":"E6LjYJJimQNFVF","name":"Alex Rivera","removed":false}],"id":"87uNbl9N8J0OPz","is_valid":true,"name":"Print","note":null,"pipeline":{"color":"#FFFFFF","enable":true,"id":"eIOQnV5PP0pp7c","label":"Screen printing","statuses":[{"color":"#f5f5f5","customer_label":"Pending","id":"fA3KDzwnMRc5Cd","label":"To do","pipeline_id":"eIOQnV5PP0pp7c","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#424242","customer_label":"Completed","id":"MIJM9QpP6O0whd","label":"Done","pipeline_id":"eIOQnV5PP0pp7c","position":1,"role":"pipeline","trashed":false,"type":"end"}],"trashed":false,"version":1},"pipeline_color":"#FFFFFF","pipeline_id":"eIOQnV5PP0pp7c","pipeline_name":"Screen printing","position":1,"trashed":false}],"position":"2.0000000000000000","production_file":[],"service":[{"customer_note":"Printed on the front, centered","id":"amcoNda0bOuIpO","location":{"display_name":"Front","id":"t1vO0qwTosoy1d","trashed":false,"type":"database"},"note":null,"option":"1 Color","position":1,"review_reason":null,"service_id":"sV7LFB1gpCcF8O","service_name":"Screen printing","valid":true,"version":1}],"updated_at":"2026-11-03T09:00:00+00:00"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"assigned_users":{"description":"The people on the job itself. Jobs made from the preset get the ones still on your team.","items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"example":"8vxTyCrd1y1gdf","type":"string"},"is_valid":{"description":"False when a service, saved location, or task preset it uses was deleted, or a service option no longer exists.","type":"boolean"},"mockup":{"description":"Mockup images, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"name":{"example":"Front print, one color","type":"string"},"needs_review":{"description":"True when the preset needs review (shown as \"Needs review\" in the web app):\n\n- `is_valid` is false (a service, service option, saved location, or task preset was deleted)\n- A team member assigned to one of its tasks was deleted or left the team (assignees on the job itself do not trigger review)\n\nA preset that needs review still saves. Creating a job from it omits missing tasks and removed teammates.","type":"boolean"},"note":{"type":["string","null"]},"pipeline":{"description":"The tasks.","items":{"additionalProperties":true,"properties":{"assigned_users":{"items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"type":"string"},"is_valid":{"type":"boolean"},"name":{"type":["string","null"]},"note":{"type":["string","null"]},"pipeline":{"additionalProperties":true,"description":"The task preset it follows, as `GET /v1/api/store/{team_slug}/setting/pipeline/{hash_id}` returns it: `id`, `label`, `color`, `version`, `enable`, `trashed`, and its `statuses` (deleted ones included).","properties":{"color":{"type":"string"},"enable":{"type":"boolean"},"id":{"type":"string"},"label":{"type":"string"},"statuses":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"trashed":{"type":"boolean"},"version":{"type":"integer"}},"type":["object","null"]},"pipeline_color":{"description":"The task preset's color.","type":["string","null"]},"pipeline_id":{"type":"string"},"pipeline_name":{"description":"The task preset's name.","type":["string","null"]},"position":{"description":"0 when none was sent.","type":"integer"},"trashed":{"description":"True when its task preset was deleted.","type":"boolean"}},"type":"object"},"type":"array"},"position":{"description":"Sort order within the preset list, lowest first. A decimal string, such as `\"1.0000000000000000\"`; parse it as a decimal.","example":"1.0000000000000000","type":"string"},"production_file":{"description":"Production files, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"service":{"description":"The service lines.","items":{"additionalProperties":true,"properties":{"customer_note":{"type":["string","null"]},"id":{"type":"string"},"location":{"additionalProperties":true,"description":"`type`, `display_name` and `trashed` (true when a saved location was deleted), plus `id` for a saved location or `name` for a custom one.","type":"object"},"note":{"type":["string","null"]},"option":{"type":["string","null"]},"position":{"type":"integer"},"review_reason":{"description":"Why the line needs review: its service was deleted, the service no longer has this option, or its saved location was deleted. Null when the line is fine.","enum":["service_removed","option_removed","location_removed",null],"type":["string","null"]},"service_id":{"type":"string"},"service_name":{"type":["string","null"]},"valid":{"description":"False when `review_reason` is set.","type":"boolean"},"version":{"const":1,"type":"integer"}},"type":"object"},"type":"array"},"updated_at":{"description":"When the preset was last edited (\"Last edited\" in the web app). Every save changes it, even one that changes only its lines; reordering presets doesn't.","format":"date-time","type":["string","null"]}},"required":["id","name","note","position","is_valid","needs_review","updated_at","service","pipeline","assigned_users","mockup","production_file"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/BulkValidationPayloadResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Reorder job presets","tags":["Job presets"],"x-yoprint-docs":{"errors":[{"fix":"Use ids from the list.","status":404,"when":"An id is not one of your team's job presets."},{"fix":"Send at least one `{id, position}` pair.","status":422,"when":"`items` is empty, or an item has no `id` or numeric `position` (`validation_failed`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_job_preset_index"],"rules":["All positions are saved together; an unknown id fails the whole request with 404."]}}},"/v1/api/store/{team_slug}/setting/job_preset/search":{"post":{"description":"Returns up to 10 job presets whose name contains `name`, sorted by `position`, in the same shape as the list. Send an empty `name` to get the first 10.\n\nIt is a read: it changes nothing, so it needs no settings permission even though it is a POST.","operationId":"v1_public_setting_job_preset_search","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"name":"front"},"schema":{"additionalProperties":false,"properties":{"name":{"description":"Text to look for anywhere in the name. Must be present; may be empty.","type":"string"}},"required":["name"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"assigned_users":[],"id":"8vxTyCrd1y1gdf","is_valid":true,"mockup":[{"collection":"mockup","created_at":"2026-11-03T09:00:00+00:00","custom_properties":{"show_in_pdf":true},"file_name":"front-logo.png","id":"uAzgeGQMGvaVK3","is_image":true,"job_preset_id":"8vxTyCrd1y1gdf","job_service":["amcoNda0bOuIpO"],"mime_type":"image/png","name":"Front logo","position":1,"preview":{"large":"https://example.com/media/uAzgeGQMGvaVK3/preview-1200.png","medium":"https://example.com/media/uAzgeGQMGvaVK3/preview-800.png","small":"https://example.com/media/uAzgeGQMGvaVK3/preview-250.png"},"show_in_pdf":true,"size":48211,"source_media_id":null,"url":"https://example.com/media/uAzgeGQMGvaVK3/download","view_url":"https://example.com/media/uAzgeGQMGvaVK3/view"}],"name":"Front print, one color","needs_review":false,"note":"Standard tee front print","pipeline":[{"assigned_users":[{"avatar_url":null,"id":"E6LjYJJimQNFVF","name":"Alex Rivera","removed":false}],"id":"87uNbl9N8J0OPz","is_valid":true,"name":"Print","note":null,"pipeline":{"color":"#FFFFFF","enable":true,"id":"eIOQnV5PP0pp7c","label":"Screen printing","statuses":[{"color":"#f5f5f5","customer_label":"Pending","id":"fA3KDzwnMRc5Cd","label":"To do","pipeline_id":"eIOQnV5PP0pp7c","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#424242","customer_label":"Completed","id":"MIJM9QpP6O0whd","label":"Done","pipeline_id":"eIOQnV5PP0pp7c","position":1,"role":"pipeline","trashed":false,"type":"end"}],"trashed":false,"version":1},"pipeline_color":"#FFFFFF","pipeline_id":"eIOQnV5PP0pp7c","pipeline_name":"Screen printing","position":1,"trashed":false}],"position":"1.0000000000000000","production_file":[],"service":[{"customer_note":"Printed on the front, centered","id":"amcoNda0bOuIpO","location":{"display_name":"Front","id":"t1vO0qwTosoy1d","trashed":false,"type":"database"},"note":null,"option":"1 Color","position":1,"review_reason":null,"service_id":"sV7LFB1gpCcF8O","service_name":"Screen printing","valid":true,"version":1}],"updated_at":"2026-11-03T09:00:00+00:00"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"assigned_users":{"description":"The people on the job itself. Jobs made from the preset get the ones still on your team.","items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"example":"8vxTyCrd1y1gdf","type":"string"},"is_valid":{"description":"False when a service, saved location, or task preset it uses was deleted, or a service option no longer exists.","type":"boolean"},"mockup":{"description":"Mockup images, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"name":{"example":"Front print, one color","type":"string"},"needs_review":{"description":"True when the preset needs review (shown as \"Needs review\" in the web app):\n\n- `is_valid` is false (a service, service option, saved location, or task preset was deleted)\n- A team member assigned to one of its tasks was deleted or left the team (assignees on the job itself do not trigger review)\n\nA preset that needs review still saves. Creating a job from it omits missing tasks and removed teammates.","type":"boolean"},"note":{"type":["string","null"]},"pipeline":{"description":"The tasks.","items":{"additionalProperties":true,"properties":{"assigned_users":{"items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"type":"string"},"is_valid":{"type":"boolean"},"name":{"type":["string","null"]},"note":{"type":["string","null"]},"pipeline":{"additionalProperties":true,"description":"The task preset it follows, as `GET /v1/api/store/{team_slug}/setting/pipeline/{hash_id}` returns it: `id`, `label`, `color`, `version`, `enable`, `trashed`, and its `statuses` (deleted ones included).","properties":{"color":{"type":"string"},"enable":{"type":"boolean"},"id":{"type":"string"},"label":{"type":"string"},"statuses":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"trashed":{"type":"boolean"},"version":{"type":"integer"}},"type":["object","null"]},"pipeline_color":{"description":"The task preset's color.","type":["string","null"]},"pipeline_id":{"type":"string"},"pipeline_name":{"description":"The task preset's name.","type":["string","null"]},"position":{"description":"0 when none was sent.","type":"integer"},"trashed":{"description":"True when its task preset was deleted.","type":"boolean"}},"type":"object"},"type":"array"},"position":{"description":"Sort order within the preset list, lowest first. A decimal string, such as `\"1.0000000000000000\"`; parse it as a decimal.","example":"1.0000000000000000","type":"string"},"production_file":{"description":"Production files, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"service":{"description":"The service lines.","items":{"additionalProperties":true,"properties":{"customer_note":{"type":["string","null"]},"id":{"type":"string"},"location":{"additionalProperties":true,"description":"`type`, `display_name` and `trashed` (true when a saved location was deleted), plus `id` for a saved location or `name` for a custom one.","type":"object"},"note":{"type":["string","null"]},"option":{"type":["string","null"]},"position":{"type":"integer"},"review_reason":{"description":"Why the line needs review: its service was deleted, the service no longer has this option, or its saved location was deleted. Null when the line is fine.","enum":["service_removed","option_removed","location_removed",null],"type":["string","null"]},"service_id":{"type":"string"},"service_name":{"type":["string","null"]},"valid":{"description":"False when `review_reason` is set.","type":"boolean"},"version":{"const":1,"type":"integer"}},"type":"object"},"type":"array"},"updated_at":{"description":"When the preset was last edited (\"Last edited\" in the web app). Every save changes it, even one that changes only its lines; reordering presets doesn't.","format":"date-time","type":["string","null"]}},"required":["id","name","note","position","is_valid","needs_review","updated_at","service","pipeline","assigned_users","mockup","production_file"],"type":"object"},"maxItems":10,"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Search job presets by name","tags":["Job presets"],"x-yoprint-docs":{"errors":[{"fix":"Send `{\"name\": \"\"}` to list the first 10.","status":422,"when":"`name` is missing or not a string."}],"group":"Team settings","permission":"Any member of the team.","related":["v1_public_job_preset_index","v1_public_job_preset_show"]}}},"/v1/api/store/{team_slug}/setting/job_preset/{hash_id}":{"delete":{"description":"Deletes a job preset for good, with its files; it can't be restored. Jobs already made from it are copies and don't change: a file a job shares with the preset stays with the job.","operationId":"v1_public_job_preset_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job preset. Its hash id from an earlier answer; there is no unique key for it.","example":"8vxTyCrd1y1gdf","in":"path","name":"hash_id","required":true,"schema":{"example":"8vxTyCrd1y1gdf","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a job preset","tags":["Job presets"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the list.","status":404,"when":"No job preset of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_job_preset_index"],"side_effects":["Team members who have YoPrint open see it disappear at once."]}},"get":{"description":"Returns one job preset with its service lines, tasks, people and files.","operationId":"v1_public_job_preset_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job preset. Its hash id from an earlier answer; there is no unique key for it.","example":"8vxTyCrd1y1gdf","in":"path","name":"hash_id","required":true,"schema":{"example":"8vxTyCrd1y1gdf","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"id":"8vxTyCrd1y1gdf","is_valid":true,"mockup":[{"collection":"mockup","created_at":"2026-11-03T09:00:00+00:00","custom_properties":{"show_in_pdf":true},"file_name":"front-logo.png","id":"uAzgeGQMGvaVK3","is_image":true,"job_preset_id":"8vxTyCrd1y1gdf","job_service":["amcoNda0bOuIpO"],"mime_type":"image/png","name":"Front logo","position":1,"preview":{"large":"https://example.com/media/uAzgeGQMGvaVK3/preview-1200.png","medium":"https://example.com/media/uAzgeGQMGvaVK3/preview-800.png","small":"https://example.com/media/uAzgeGQMGvaVK3/preview-250.png"},"show_in_pdf":true,"size":48211,"source_media_id":null,"url":"https://example.com/media/uAzgeGQMGvaVK3/download","view_url":"https://example.com/media/uAzgeGQMGvaVK3/view"}],"name":"Front print, one color","needs_review":false,"note":"Standard tee front print","pipeline":[{"assigned_users":[{"avatar_url":null,"id":"E6LjYJJimQNFVF","name":"Alex Rivera","removed":false}],"id":"87uNbl9N8J0OPz","is_valid":true,"name":"Print","note":null,"pipeline":{"color":"#FFFFFF","enable":true,"id":"eIOQnV5PP0pp7c","label":"Screen printing","statuses":[{"color":"#f5f5f5","customer_label":"Pending","id":"fA3KDzwnMRc5Cd","label":"To do","pipeline_id":"eIOQnV5PP0pp7c","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#424242","customer_label":"Completed","id":"MIJM9QpP6O0whd","label":"Done","pipeline_id":"eIOQnV5PP0pp7c","position":1,"role":"pipeline","trashed":false,"type":"end"}],"trashed":false,"version":1},"pipeline_color":"#FFFFFF","pipeline_id":"eIOQnV5PP0pp7c","pipeline_name":"Screen printing","position":1,"trashed":false}],"position":"1.0000000000000000","production_file":[],"service":[{"customer_note":"Printed on the front, centered","id":"amcoNda0bOuIpO","location":{"display_name":"Front","id":"t1vO0qwTosoy1d","trashed":false,"type":"database"},"note":null,"option":"1 Color","position":1,"review_reason":null,"service_id":"sV7LFB1gpCcF8O","service_name":"Screen printing","valid":true,"version":1}],"updated_at":"2026-11-03T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"assigned_users":{"description":"The people on the job itself. Jobs made from the preset get the ones still on your team.","items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"example":"8vxTyCrd1y1gdf","type":"string"},"is_valid":{"description":"False when a service, saved location, or task preset it uses was deleted, or a service option no longer exists.","type":"boolean"},"mockup":{"description":"Mockup images, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"name":{"example":"Front print, one color","type":"string"},"needs_review":{"description":"True when the preset needs review (shown as \"Needs review\" in the web app):\n\n- `is_valid` is false (a service, service option, saved location, or task preset was deleted)\n- A team member assigned to one of its tasks was deleted or left the team (assignees on the job itself do not trigger review)\n\nA preset that needs review still saves. Creating a job from it omits missing tasks and removed teammates.","type":"boolean"},"note":{"type":["string","null"]},"pipeline":{"description":"The tasks.","items":{"additionalProperties":true,"properties":{"assigned_users":{"items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"type":"string"},"is_valid":{"type":"boolean"},"name":{"type":["string","null"]},"note":{"type":["string","null"]},"pipeline":{"additionalProperties":true,"description":"The task preset it follows, as `GET /v1/api/store/{team_slug}/setting/pipeline/{hash_id}` returns it: `id`, `label`, `color`, `version`, `enable`, `trashed`, and its `statuses` (deleted ones included).","properties":{"color":{"type":"string"},"enable":{"type":"boolean"},"id":{"type":"string"},"label":{"type":"string"},"statuses":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"trashed":{"type":"boolean"},"version":{"type":"integer"}},"type":["object","null"]},"pipeline_color":{"description":"The task preset's color.","type":["string","null"]},"pipeline_id":{"type":"string"},"pipeline_name":{"description":"The task preset's name.","type":["string","null"]},"position":{"description":"0 when none was sent.","type":"integer"},"trashed":{"description":"True when its task preset was deleted.","type":"boolean"}},"type":"object"},"type":"array"},"position":{"description":"Sort order within the preset list, lowest first. A decimal string, such as `\"1.0000000000000000\"`; parse it as a decimal.","example":"1.0000000000000000","type":"string"},"production_file":{"description":"Production files, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"service":{"description":"The service lines.","items":{"additionalProperties":true,"properties":{"customer_note":{"type":["string","null"]},"id":{"type":"string"},"location":{"additionalProperties":true,"description":"`type`, `display_name` and `trashed` (true when a saved location was deleted), plus `id` for a saved location or `name` for a custom one.","type":"object"},"note":{"type":["string","null"]},"option":{"type":["string","null"]},"position":{"type":"integer"},"review_reason":{"description":"Why the line needs review: its service was deleted, the service no longer has this option, or its saved location was deleted. Null when the line is fine.","enum":["service_removed","option_removed","location_removed",null],"type":["string","null"]},"service_id":{"type":"string"},"service_name":{"type":["string","null"]},"valid":{"description":"False when `review_reason` is set.","type":"boolean"},"version":{"const":1,"type":"integer"}},"type":"object"},"type":"array"},"updated_at":{"description":"When the preset was last edited (\"Last edited\" in the web app). Every save changes it, even one that changes only its lines; reordering presets doesn't.","format":"date-time","type":["string","null"]}},"required":["id","name","note","position","is_valid","needs_review","updated_at","service","pipeline","assigned_users","mockup","production_file"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a job preset","tags":["Job presets"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the list.","status":404,"when":"No job preset of your team has this id. `error.code` is null; `error.message` names the record type."}],"group":"Team settings","permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_job_preset_update_patch","v1_public_job_preset_index"]}},"patch":{"description":"Use PUT to change a job preset. PATCH changes nothing except the `updated_at` time. See Update a job preset (PUT) for what you can send.","operationId":"v1_public_job_preset_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job preset. Its hash id from an earlier answer; there is no unique key for it.","example":"8vxTyCrd1y1gdf","in":"path","name":"hash_id","required":true,"schema":{"example":"8vxTyCrd1y1gdf","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"assigned_users":[{"id":"E6LjYJJimQNFVF"}],"name":"Front print, two colors","pipeline":[{"action":"delete","id":"87uNbl9N8J0OPz"}],"service":[{"action":"update","customer_note":"Printed on the front, centered","id":"amcoNda0bOuIpO","location":{"id":"t1vO0qwTosoy1d","type":"database"},"option":"2 Colors","position":1,"service_id":"sV7LFB1gpCcF8O"},{"action":"create","location":{"name":"Left sleeve","type":"custom"},"option":"1 Color","position":2,"service_id":"sV7LFB1gpCcF8O"}]},"schema":{"additionalProperties":false,"properties":{"assigned_users":{"description":"The people on the job itself. Sent, the list replaces them (`[]` removes everyone); left out, they stay. People you add must be active members of your team.","items":{"additionalProperties":false,"properties":{"id":{"description":"A team member's id, from `GET /v1/api/store/{team_slug}/setting/user`.","type":"string"}},"required":["id"],"type":"object"},"type":"array"},"mockup":{"description":"Mockup images. A `create` row must be an image file.","items":{"additionalProperties":false,"properties":{"action":{"description":"`create` attaches a file you uploaded with \"Upload a file\" (`POST /v1/api/store/{team_slug}/async_upload`). `update` changes one of this preset's files; `delete` removes it.","enum":["create","update","delete"],"type":"string"},"id":{"description":"For `create`, the upload's `id`. For `update` and `delete`, the file's `id` from the preset's `mockup` list.","type":"string"},"job_service":{"description":"The service line, or a list of them, this file belongs to: a line's `id`, or the `tmpid-` id of a line created in the same request. Ids that are not lines of this preset are ignored. When sent, it replaces the file's links; `[]` removes them.","items":{"type":"string"},"type":["string","array"]},"name":{"description":"The file's display name. Left out, it keeps its name.","type":"string"},"position":{"description":"For `update`: where the file sorts among the preset's mockups. A `create` row always goes last.","type":"integer"},"show_in_pdf":{"description":"Whether the mockup shows on PDFs. Jobs made from the preset keep the setting.","type":"boolean"}},"required":["action","id"],"type":"object"},"type":"array"},"name":{"type":"string"},"note":{"type":["string","null"]},"pipeline":{"items":{"additionalProperties":false,"properties":{"action":{"description":"What to do with this task.","enum":["create","update","delete"],"type":"string"},"assigned_users":{"description":"Who the task is assigned to. A `create` line without it has nobody. On an `update` line, leave it out to keep the task's people, or send the whole list to replace them (`[]` removes everyone). People you add must be active members of your team; people already on the task may stay after they leave.","items":{"additionalProperties":false,"properties":{"id":{"description":"A team member's id, from `GET /v1/api/store/{team_slug}/setting/user`.","type":"string"}},"required":["id"],"type":"object"},"type":"array"},"id":{"description":"The task to change, for `update` and `delete`.","type":"string"},"name":{"description":"The task's name.","type":"string"},"note":{"type":["string","null"]},"pipeline_id":{"description":"The task preset this task follows, from `GET /v1/api/store/{team_slug}/setting/pipeline`. Required unless `action` is `delete`. A new task, or one that changes it, needs a task preset that isn't deleted.","type":"string"},"position":{"maximum":2147483647,"minimum":-2147483648,"type":"integer"}},"required":["action"],"type":"object"},"type":"array"},"production_file":{"description":"Production files, of any type.","items":{"additionalProperties":false,"properties":{"action":{"description":"`create` attaches a file you uploaded with \"Upload a file\" (`POST /v1/api/store/{team_slug}/async_upload`). `update` changes one of this preset's files; `delete` removes it.","enum":["create","update","delete"],"type":"string"},"id":{"description":"For `create`, the upload's `id`. For `update` and `delete`, the file's `id` from the preset's `production_file` list.","type":"string"},"job_service":{"description":"The service line, or a list of them, this file belongs to: a line's `id`, or the `tmpid-` id of a line created in the same request. Ids that are not lines of this preset are ignored. When sent, it replaces the file's links; `[]` removes them.","items":{"type":"string"},"type":["string","array"]},"name":{"description":"The file's display name. Left out, it keeps its name.","type":"string"},"position":{"description":"For `update`: where the file sorts among the preset's production files. A `create` row always goes last.","type":"integer"},"show_in_pdf":{"description":"Saved on the file and copied to jobs made from the preset.","type":"boolean"}},"required":["action","id"],"type":"object"},"type":"array"},"service":{"items":{"additionalProperties":false,"properties":{"action":{"description":"What to do with this service line.","enum":["create","update","delete"],"type":"string"},"customer_note":{"description":"A note the customer sees. Jobs made from the preset get it on their service.","type":["string","null"]},"id":{"description":"For `update` and `delete`: the service line to change. On a `create` line you may send a temporary id that starts with `tmpid-` (such as `tmpid-1`), so a file row in the same request can name the new line in `job_service`.","type":"string"},"location":{"additionalProperties":false,"description":"Where the service goes on the product. Required unless `action` is `delete`.","properties":{"id":{"description":"Required when `type` is `database`. A new or changed location must not be deleted. Ignored for `custom`.","type":"string"},"name":{"description":"Required when `type` is `custom`.","type":"string"},"type":{"description":"`database`: one of your saved service locations, by `id` (from `GET /v1/api/store/{team_slug}/service_location`). `custom`: a one-off location, by `name`.","enum":["database","custom"],"type":"string"}},"required":["type"],"type":"object"},"note":{"description":"A production note for this service.","type":["string","null"]},"option":{"description":"One of the service's options (a column of its price table). Required unless `action` is `delete`. Any value saves, but one the service doesn't have marks the preset `is_valid: false`.","type":"string"},"position":{"description":"Order of the service lines. Required unless `action` is `delete`.","maximum":2147483647,"minimum":-2147483648,"type":"integer"},"service_id":{"description":"The decoration service ID. Required unless `action` is `delete`. The service must be active (not deleted). Services are not listed directly on the public API; copy `service_id` from an existing job preset (List job presets) or from a job's services.","type":"string"}},"required":["action"],"type":"object"},"type":"array"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[{"avatar_url":null,"id":"E6LjYJJimQNFVF","name":"Alex Rivera","removed":false}],"id":"8vxTyCrd1y1gdf","is_valid":true,"mockup":[{"collection":"mockup","created_at":"2026-11-03T09:00:00+00:00","custom_properties":{"show_in_pdf":true},"file_name":"front-logo.png","id":"uAzgeGQMGvaVK3","is_image":true,"job_preset_id":"8vxTyCrd1y1gdf","job_service":["amcoNda0bOuIpO"],"mime_type":"image/png","name":"Front logo","position":1,"preview":{"large":"https://example.com/media/uAzgeGQMGvaVK3/preview-1200.png","medium":"https://example.com/media/uAzgeGQMGvaVK3/preview-800.png","small":"https://example.com/media/uAzgeGQMGvaVK3/preview-250.png"},"show_in_pdf":true,"size":48211,"source_media_id":null,"url":"https://example.com/media/uAzgeGQMGvaVK3/download","view_url":"https://example.com/media/uAzgeGQMGvaVK3/view"}],"name":"Front print, two colors","needs_review":false,"note":"Standard tee front print","pipeline":[],"position":"1.0000000000000000","production_file":[],"service":[{"customer_note":"Printed on the front, centered","id":"amcoNda0bOuIpO","location":{"display_name":"Front","id":"t1vO0qwTosoy1d","trashed":false,"type":"database"},"note":null,"option":"2 Colors","position":1,"review_reason":null,"service_id":"sV7LFB1gpCcF8O","service_name":"Screen printing","valid":true,"version":1},{"customer_note":null,"id":"3G6bb0Whg2ApYW","location":{"display_name":"Left sleeve","name":"Left sleeve","trashed":false,"type":"custom"},"note":null,"option":"1 Color","position":2,"review_reason":null,"service_id":"sV7LFB1gpCcF8O","service_name":"Screen printing","valid":true,"version":1}],"updated_at":"2026-11-04T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"assigned_users":{"description":"The people on the job itself. Jobs made from the preset get the ones still on your team.","items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"example":"8vxTyCrd1y1gdf","type":"string"},"is_valid":{"description":"False when a service, saved location, or task preset it uses was deleted, or a service option no longer exists.","type":"boolean"},"mockup":{"description":"Mockup images, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"name":{"example":"Front print, one color","type":"string"},"needs_review":{"description":"True when the preset needs review (shown as \"Needs review\" in the web app):\n\n- `is_valid` is false (a service, service option, saved location, or task preset was deleted)\n- A team member assigned to one of its tasks was deleted or left the team (assignees on the job itself do not trigger review)\n\nA preset that needs review still saves. Creating a job from it omits missing tasks and removed teammates.","type":"boolean"},"note":{"type":["string","null"]},"pipeline":{"description":"The tasks.","items":{"additionalProperties":true,"properties":{"assigned_users":{"items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"type":"string"},"is_valid":{"type":"boolean"},"name":{"type":["string","null"]},"note":{"type":["string","null"]},"pipeline":{"additionalProperties":true,"description":"The task preset it follows, as `GET /v1/api/store/{team_slug}/setting/pipeline/{hash_id}` returns it: `id`, `label`, `color`, `version`, `enable`, `trashed`, and its `statuses` (deleted ones included).","properties":{"color":{"type":"string"},"enable":{"type":"boolean"},"id":{"type":"string"},"label":{"type":"string"},"statuses":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"trashed":{"type":"boolean"},"version":{"type":"integer"}},"type":["object","null"]},"pipeline_color":{"description":"The task preset's color.","type":["string","null"]},"pipeline_id":{"type":"string"},"pipeline_name":{"description":"The task preset's name.","type":["string","null"]},"position":{"description":"0 when none was sent.","type":"integer"},"trashed":{"description":"True when its task preset was deleted.","type":"boolean"}},"type":"object"},"type":"array"},"position":{"description":"Sort order within the preset list, lowest first. A decimal string, such as `\"1.0000000000000000\"`; parse it as a decimal.","example":"1.0000000000000000","type":"string"},"production_file":{"description":"Production files, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"service":{"description":"The service lines.","items":{"additionalProperties":true,"properties":{"customer_note":{"type":["string","null"]},"id":{"type":"string"},"location":{"additionalProperties":true,"description":"`type`, `display_name` and `trashed` (true when a saved location was deleted), plus `id` for a saved location or `name` for a custom one.","type":"object"},"note":{"type":["string","null"]},"option":{"type":["string","null"]},"position":{"type":"integer"},"review_reason":{"description":"Why the line needs review: its service was deleted, the service no longer has this option, or its saved location was deleted. Null when the line is fine.","enum":["service_removed","option_removed","location_removed",null],"type":["string","null"]},"service_id":{"type":"string"},"service_name":{"type":["string","null"]},"valid":{"description":"False when `review_reason` is set.","type":"boolean"},"version":{"const":1,"type":"integer"}},"type":"object"},"type":"array"},"updated_at":{"description":"When the preset was last edited (\"Last edited\" in the web app). Every save changes it, even one that changes only its lines; reordering presets doesn't.","format":"date-time","type":["string","null"]}},"required":["id","name","note","position","is_valid","needs_review","updated_at","service","pipeline","assigned_users","mockup","production_file"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Touch a job preset","tags":["Job presets"],"x-yoprint-docs":{"errors":[{"fix":"Read the preset first and use its line ids.","status":404,"when":"The preset, or a line or task named by `id`, is not found in this preset."},{"fix":"Send every required field; see the schema.","status":422,"when":"`name` is missing (create), a line or file row has no `action`, a file row has no `id`, or a service line misses `service_id`, `option`, `location.type` or `position` (`validation_failed`)."},{"fix":"Use ids from your own team's lists, and upload files first.","status":422,"when":"A service, location, task preset or person is not your team's, or is deleted where a live one is needed; or a file row names a file that isn't a free upload, or a mockup that isn't an image. `error.code` `job_validation_error`, with a message such as \"Service not found!\", \"Assigned User not found!\", \"Please upload this file before adding it to a job preset.\" or \"Mockups must be image files.\""},{"fix":"Use the upload's `id`, or a file `id` from the preset.","status":404,"when":"A `create` file row names no upload of your team, or an `update` or `delete` file row names a file that isn't this preset's. `error.code` is null."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_job_preset_show","v1_public_job_preset_destroy","v1_public_async_upload_store"],"rules":["Everything is checked against your team before anything is saved, and the whole save is one transaction: one refusal saves nothing.","A new line, task or person, and any reference you change, must be live: a service, saved location and task preset that aren't deleted, and people who are active members of your team. An `update` line that keeps a deleted service, location or task preset, or a person who has left, still saves.","A service `option` the service doesn't have still saves, but the preset reads `is_valid: false`.","Top-level `assigned_users` sets the people on the job itself: sent, it replaces them (`[]` removes everyone); left out, they stay. On a task `update` line, `assigned_users` works the same way; a task `create` line without it has nobody.","Files: a `create` row attaches a file you uploaded with \"Upload a file\" and not yet attached anywhere; a mockup must be an image. `update` and `delete` rows act only on this preset's own files; one that is already gone is skipped.","`update` and `delete` line and task ids must be this preset's; another preset's line returns 404 and nothing is saved."],"side_effects":["A `delete` file row removes the file from the preset. Jobs made from the preset earlier keep their copy of it.","Team members who have YoPrint open see the change at once."]}},"put":{"description":"Changes a job preset. Send `name`, `note` or `assigned_users` to change them, and list only the service lines, tasks and files that change, each with an `action`:\n\n- `create`: a new line or task, with the same fields as when creating a preset, or a new file from an upload.\n- `update`: an existing line, task or file by `id`, with its fields.\n- `delete`: an existing line, task or file by `id`.\n\nLines and files you leave out stay as they are; an empty list changes nothing. A task `update` without `assigned_users` keeps its people.\n\nUse PUT. PATCH runs no rules and saves nothing but a new `updated_at`.\n\nReturns the updated preset. Jobs already made from it don't change.","operationId":"v1_public_job_preset_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job preset. Its hash id from an earlier answer; there is no unique key for it.","example":"8vxTyCrd1y1gdf","in":"path","name":"hash_id","required":true,"schema":{"example":"8vxTyCrd1y1gdf","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"assigned_users":[{"id":"E6LjYJJimQNFVF"}],"name":"Front print, two colors","pipeline":[{"action":"delete","id":"87uNbl9N8J0OPz"}],"service":[{"action":"update","customer_note":"Printed on the front, centered","id":"amcoNda0bOuIpO","location":{"id":"t1vO0qwTosoy1d","type":"database"},"option":"2 Colors","position":1,"service_id":"sV7LFB1gpCcF8O"},{"action":"create","location":{"name":"Left sleeve","type":"custom"},"option":"1 Color","position":2,"service_id":"sV7LFB1gpCcF8O"}]},"schema":{"additionalProperties":false,"properties":{"assigned_users":{"description":"The people on the job itself. Sent, the list replaces them (`[]` removes everyone); left out, they stay. People you add must be active members of your team.","items":{"additionalProperties":false,"properties":{"id":{"description":"A team member's id, from `GET /v1/api/store/{team_slug}/setting/user`.","type":"string"}},"required":["id"],"type":"object"},"type":"array"},"mockup":{"description":"Mockup images. A `create` row must be an image file.","items":{"additionalProperties":false,"properties":{"action":{"description":"`create` attaches a file you uploaded with \"Upload a file\" (`POST /v1/api/store/{team_slug}/async_upload`). `update` changes one of this preset's files; `delete` removes it.","enum":["create","update","delete"],"type":"string"},"id":{"description":"For `create`, the upload's `id`. For `update` and `delete`, the file's `id` from the preset's `mockup` list.","type":"string"},"job_service":{"description":"The service line, or a list of them, this file belongs to: a line's `id`, or the `tmpid-` id of a line created in the same request. Ids that are not lines of this preset are ignored. When sent, it replaces the file's links; `[]` removes them.","items":{"type":"string"},"type":["string","array"]},"name":{"description":"The file's display name. Left out, it keeps its name.","type":"string"},"position":{"description":"For `update`: where the file sorts among the preset's mockups. A `create` row always goes last.","type":"integer"},"show_in_pdf":{"description":"Whether the mockup shows on PDFs. Jobs made from the preset keep the setting.","type":"boolean"}},"required":["action","id"],"type":"object"},"type":"array"},"name":{"type":"string"},"note":{"type":["string","null"]},"pipeline":{"items":{"additionalProperties":false,"properties":{"action":{"description":"What to do with this task.","enum":["create","update","delete"],"type":"string"},"assigned_users":{"description":"Who the task is assigned to. A `create` line without it has nobody. On an `update` line, leave it out to keep the task's people, or send the whole list to replace them (`[]` removes everyone). People you add must be active members of your team; people already on the task may stay after they leave.","items":{"additionalProperties":false,"properties":{"id":{"description":"A team member's id, from `GET /v1/api/store/{team_slug}/setting/user`.","type":"string"}},"required":["id"],"type":"object"},"type":"array"},"id":{"description":"The task to change, for `update` and `delete`.","type":"string"},"name":{"description":"The task's name.","type":"string"},"note":{"type":["string","null"]},"pipeline_id":{"description":"The task preset this task follows, from `GET /v1/api/store/{team_slug}/setting/pipeline`. Required unless `action` is `delete`. A new task, or one that changes it, needs a task preset that isn't deleted.","type":"string"},"position":{"maximum":2147483647,"minimum":-2147483648,"type":"integer"}},"required":["action"],"type":"object"},"type":"array"},"production_file":{"description":"Production files, of any type.","items":{"additionalProperties":false,"properties":{"action":{"description":"`create` attaches a file you uploaded with \"Upload a file\" (`POST /v1/api/store/{team_slug}/async_upload`). `update` changes one of this preset's files; `delete` removes it.","enum":["create","update","delete"],"type":"string"},"id":{"description":"For `create`, the upload's `id`. For `update` and `delete`, the file's `id` from the preset's `production_file` list.","type":"string"},"job_service":{"description":"The service line, or a list of them, this file belongs to: a line's `id`, or the `tmpid-` id of a line created in the same request. Ids that are not lines of this preset are ignored. When sent, it replaces the file's links; `[]` removes them.","items":{"type":"string"},"type":["string","array"]},"name":{"description":"The file's display name. Left out, it keeps its name.","type":"string"},"position":{"description":"For `update`: where the file sorts among the preset's production files. A `create` row always goes last.","type":"integer"},"show_in_pdf":{"description":"Saved on the file and copied to jobs made from the preset.","type":"boolean"}},"required":["action","id"],"type":"object"},"type":"array"},"service":{"items":{"additionalProperties":false,"properties":{"action":{"description":"What to do with this service line.","enum":["create","update","delete"],"type":"string"},"customer_note":{"description":"A note the customer sees. Jobs made from the preset get it on their service.","type":["string","null"]},"id":{"description":"For `update` and `delete`: the service line to change. On a `create` line you may send a temporary id that starts with `tmpid-` (such as `tmpid-1`), so a file row in the same request can name the new line in `job_service`.","type":"string"},"location":{"additionalProperties":false,"description":"Where the service goes on the product. Required unless `action` is `delete`.","properties":{"id":{"description":"Required when `type` is `database`. A new or changed location must not be deleted. Ignored for `custom`.","type":"string"},"name":{"description":"Required when `type` is `custom`.","type":"string"},"type":{"description":"`database`: one of your saved service locations, by `id` (from `GET /v1/api/store/{team_slug}/service_location`). `custom`: a one-off location, by `name`.","enum":["database","custom"],"type":"string"}},"required":["type"],"type":"object"},"note":{"description":"A production note for this service.","type":["string","null"]},"option":{"description":"One of the service's options (a column of its price table). Required unless `action` is `delete`. Any value saves, but one the service doesn't have marks the preset `is_valid: false`.","type":"string"},"position":{"description":"Order of the service lines. Required unless `action` is `delete`.","maximum":2147483647,"minimum":-2147483648,"type":"integer"},"service_id":{"description":"The decoration service ID. Required unless `action` is `delete`. The service must be active (not deleted). Services are not listed directly on the public API; copy `service_id` from an existing job preset (List job presets) or from a job's services.","type":"string"}},"required":["action"],"type":"object"},"type":"array"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[{"avatar_url":null,"id":"E6LjYJJimQNFVF","name":"Alex Rivera","removed":false}],"id":"8vxTyCrd1y1gdf","is_valid":true,"mockup":[{"collection":"mockup","created_at":"2026-11-03T09:00:00+00:00","custom_properties":{"show_in_pdf":true},"file_name":"front-logo.png","id":"uAzgeGQMGvaVK3","is_image":true,"job_preset_id":"8vxTyCrd1y1gdf","job_service":["amcoNda0bOuIpO"],"mime_type":"image/png","name":"Front logo","position":1,"preview":{"large":"https://example.com/media/uAzgeGQMGvaVK3/preview-1200.png","medium":"https://example.com/media/uAzgeGQMGvaVK3/preview-800.png","small":"https://example.com/media/uAzgeGQMGvaVK3/preview-250.png"},"show_in_pdf":true,"size":48211,"source_media_id":null,"url":"https://example.com/media/uAzgeGQMGvaVK3/download","view_url":"https://example.com/media/uAzgeGQMGvaVK3/view"}],"name":"Front print, two colors","needs_review":false,"note":"Standard tee front print","pipeline":[],"position":"1.0000000000000000","production_file":[],"service":[{"customer_note":"Printed on the front, centered","id":"amcoNda0bOuIpO","location":{"display_name":"Front","id":"t1vO0qwTosoy1d","trashed":false,"type":"database"},"note":null,"option":"2 Colors","position":1,"review_reason":null,"service_id":"sV7LFB1gpCcF8O","service_name":"Screen printing","valid":true,"version":1},{"customer_note":null,"id":"3G6bb0Whg2ApYW","location":{"display_name":"Left sleeve","name":"Left sleeve","trashed":false,"type":"custom"},"note":null,"option":"1 Color","position":2,"review_reason":null,"service_id":"sV7LFB1gpCcF8O","service_name":"Screen printing","valid":true,"version":1}],"updated_at":"2026-11-04T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"assigned_users":{"description":"The people on the job itself. Jobs made from the preset get the ones still on your team.","items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"example":"8vxTyCrd1y1gdf","type":"string"},"is_valid":{"description":"False when a service, saved location, or task preset it uses was deleted, or a service option no longer exists.","type":"boolean"},"mockup":{"description":"Mockup images, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"name":{"example":"Front print, one color","type":"string"},"needs_review":{"description":"True when the preset needs review (shown as \"Needs review\" in the web app):\n\n- `is_valid` is false (a service, service option, saved location, or task preset was deleted)\n- A team member assigned to one of its tasks was deleted or left the team (assignees on the job itself do not trigger review)\n\nA preset that needs review still saves. Creating a job from it omits missing tasks and removed teammates.","type":"boolean"},"note":{"type":["string","null"]},"pipeline":{"description":"The tasks.","items":{"additionalProperties":true,"properties":{"assigned_users":{"items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"type":"string"},"is_valid":{"type":"boolean"},"name":{"type":["string","null"]},"note":{"type":["string","null"]},"pipeline":{"additionalProperties":true,"description":"The task preset it follows, as `GET /v1/api/store/{team_slug}/setting/pipeline/{hash_id}` returns it: `id`, `label`, `color`, `version`, `enable`, `trashed`, and its `statuses` (deleted ones included).","properties":{"color":{"type":"string"},"enable":{"type":"boolean"},"id":{"type":"string"},"label":{"type":"string"},"statuses":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"trashed":{"type":"boolean"},"version":{"type":"integer"}},"type":["object","null"]},"pipeline_color":{"description":"The task preset's color.","type":["string","null"]},"pipeline_id":{"type":"string"},"pipeline_name":{"description":"The task preset's name.","type":["string","null"]},"position":{"description":"0 when none was sent.","type":"integer"},"trashed":{"description":"True when its task preset was deleted.","type":"boolean"}},"type":"object"},"type":"array"},"position":{"description":"Sort order within the preset list, lowest first. A decimal string, such as `\"1.0000000000000000\"`; parse it as a decimal.","example":"1.0000000000000000","type":"string"},"production_file":{"description":"Production files, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"service":{"description":"The service lines.","items":{"additionalProperties":true,"properties":{"customer_note":{"type":["string","null"]},"id":{"type":"string"},"location":{"additionalProperties":true,"description":"`type`, `display_name` and `trashed` (true when a saved location was deleted), plus `id` for a saved location or `name` for a custom one.","type":"object"},"note":{"type":["string","null"]},"option":{"type":["string","null"]},"position":{"type":"integer"},"review_reason":{"description":"Why the line needs review: its service was deleted, the service no longer has this option, or its saved location was deleted. Null when the line is fine.","enum":["service_removed","option_removed","location_removed",null],"type":["string","null"]},"service_id":{"type":"string"},"service_name":{"type":["string","null"]},"valid":{"description":"False when `review_reason` is set.","type":"boolean"},"version":{"const":1,"type":"integer"}},"type":"object"},"type":"array"},"updated_at":{"description":"When the preset was last edited (\"Last edited\" in the web app). Every save changes it, even one that changes only its lines; reordering presets doesn't.","format":"date-time","type":["string","null"]}},"required":["id","name","note","position","is_valid","needs_review","updated_at","service","pipeline","assigned_users","mockup","production_file"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a job preset","tags":["Job presets"],"x-yoprint-docs":{"errors":[{"fix":"Read the preset first and use its line ids.","status":404,"when":"The preset, or a line or task named by `id`, is not found in this preset."},{"fix":"Send every required field; see the schema.","status":422,"when":"`name` is missing (create), a line or file row has no `action`, a file row has no `id`, or a service line misses `service_id`, `option`, `location.type` or `position` (`validation_failed`)."},{"fix":"Use ids from your own team's lists, and upload files first.","status":422,"when":"A service, location, task preset or person is not your team's, or is deleted where a live one is needed; or a file row names a file that isn't a free upload, or a mockup that isn't an image. `error.code` `job_validation_error`, with a message such as \"Service not found!\", \"Assigned User not found!\", \"Please upload this file before adding it to a job preset.\" or \"Mockups must be image files.\""},{"fix":"Use the upload's `id`, or a file `id` from the preset.","status":404,"when":"A `create` file row names no upload of your team, or an `update` or `delete` file row names a file that isn't this preset's. `error.code` is null."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_job_preset_show","v1_public_job_preset_destroy","v1_public_async_upload_store"],"rules":["Everything is checked against your team before anything is saved, and the whole save is one transaction: one refusal saves nothing.","A new line, task or person, and any reference you change, must be live: a service, saved location and task preset that aren't deleted, and people who are active members of your team. An `update` line that keeps a deleted service, location or task preset, or a person who has left, still saves.","A service `option` the service doesn't have still saves, but the preset reads `is_valid: false`.","Top-level `assigned_users` sets the people on the job itself: sent, it replaces them (`[]` removes everyone); left out, they stay. On a task `update` line, `assigned_users` works the same way; a task `create` line without it has nobody.","Files: a `create` row attaches a file you uploaded with \"Upload a file\" and not yet attached anywhere; a mockup must be an image. `update` and `delete` rows act only on this preset's own files; one that is already gone is skipped.","`update` and `delete` line and task ids must be this preset's; another preset's line returns 404 and nothing is saved."],"side_effects":["A `delete` file row removes the file from the preset. Jobs made from the preset earlier keep their copy of it.","Team members who have YoPrint open see the change at once."]}}},"/v1/api/store/{team_slug}/setting/job_preset/{hash_id}/duplicate":{"post":{"description":"Copies a job preset to the end of the list, named like it with \" (copy)\" added (the original name is shortened if the result would pass 191 characters).\n\nThe copy gets the note, the service lines, the tasks, the people still on your team, and the files. Copied files share the stored file with the original and keep their links to the copied service lines. People who were deleted or left your team are not copied.\n\nIt takes no body. Returns the new preset.","operationId":"v1_public_job_preset_duplicate","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job preset to copy. Its hash id from an earlier answer; there is no unique key for it.","example":"8vxTyCrd1y1gdf","in":"path","name":"hash_id","required":true,"schema":{"example":"8vxTyCrd1y1gdf","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"id":"fWPTmWjX0LWtNl","is_valid":true,"mockup":[{"collection":"mockup","created_at":"2026-11-04T09:00:00+00:00","custom_properties":{"show_in_pdf":true,"source_media_id":1001},"file_name":"front-logo.png","id":"z7X5WcBkhsQvUZ","is_image":true,"job_preset_id":"fWPTmWjX0LWtNl","job_service":["OtVSA8cEfjTUZ7"],"mime_type":"image/png","name":"Front logo","position":1,"preview":{"large":"https://example.com/media/z7X5WcBkhsQvUZ/preview-1200.png","medium":"https://example.com/media/z7X5WcBkhsQvUZ/preview-800.png","small":"https://example.com/media/z7X5WcBkhsQvUZ/preview-250.png"},"show_in_pdf":true,"size":48211,"source_media_id":null,"url":"https://example.com/media/z7X5WcBkhsQvUZ/download","view_url":"https://example.com/media/z7X5WcBkhsQvUZ/view"}],"name":"Front print, one color (copy)","needs_review":false,"note":"Standard tee front print","pipeline":[{"assigned_users":[{"avatar_url":null,"id":"E6LjYJJimQNFVF","name":"Alex Rivera","removed":false}],"id":"uA2Q5KwD3jCbFp","is_valid":true,"name":"Print","note":null,"pipeline":{"color":"#FFFFFF","enable":true,"id":"eIOQnV5PP0pp7c","label":"Screen printing","statuses":[{"color":"#f5f5f5","customer_label":"Pending","id":"fA3KDzwnMRc5Cd","label":"To do","pipeline_id":"eIOQnV5PP0pp7c","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#424242","customer_label":"Completed","id":"MIJM9QpP6O0whd","label":"Done","pipeline_id":"eIOQnV5PP0pp7c","position":1,"role":"pipeline","trashed":false,"type":"end"}],"trashed":false,"version":1},"pipeline_color":"#FFFFFF","pipeline_id":"eIOQnV5PP0pp7c","pipeline_name":"Screen printing","position":1,"trashed":false}],"position":"2.0000000000000000","production_file":[],"service":[{"customer_note":"Printed on the front, centered","id":"OtVSA8cEfjTUZ7","location":{"display_name":"Front","id":"t1vO0qwTosoy1d","trashed":false,"type":"database"},"note":null,"option":"1 Color","position":1,"review_reason":null,"service_id":"sV7LFB1gpCcF8O","service_name":"Screen printing","valid":true,"version":1}],"updated_at":"2026-11-04T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"assigned_users":{"description":"The people on the job itself. Jobs made from the preset get the ones still on your team.","items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"example":"8vxTyCrd1y1gdf","type":"string"},"is_valid":{"description":"False when a service, saved location, or task preset it uses was deleted, or a service option no longer exists.","type":"boolean"},"mockup":{"description":"Mockup images, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"name":{"example":"Front print, one color","type":"string"},"needs_review":{"description":"True when the preset needs review (shown as \"Needs review\" in the web app):\n\n- `is_valid` is false (a service, service option, saved location, or task preset was deleted)\n- A team member assigned to one of its tasks was deleted or left the team (assignees on the job itself do not trigger review)\n\nA preset that needs review still saves. Creating a job from it omits missing tasks and removed teammates.","type":"boolean"},"note":{"type":["string","null"]},"pipeline":{"description":"The tasks.","items":{"additionalProperties":true,"properties":{"assigned_users":{"items":{"additionalProperties":false,"properties":{"avatar_url":{"description":"Their profile picture, or null.","type":["string","null"]},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"removed":{"description":"True when the person was deleted or is no longer on your team. They stay listed until someone takes them off; jobs made from the preset leave them out.","type":"boolean"}},"required":["id","avatar_url","name","removed"],"type":"object"},"type":"array"},"id":{"type":"string"},"is_valid":{"type":"boolean"},"name":{"type":["string","null"]},"note":{"type":["string","null"]},"pipeline":{"additionalProperties":true,"description":"The task preset it follows, as `GET /v1/api/store/{team_slug}/setting/pipeline/{hash_id}` returns it: `id`, `label`, `color`, `version`, `enable`, `trashed`, and its `statuses` (deleted ones included).","properties":{"color":{"type":"string"},"enable":{"type":"boolean"},"id":{"type":"string"},"label":{"type":"string"},"statuses":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"trashed":{"type":"boolean"},"version":{"type":"integer"}},"type":["object","null"]},"pipeline_color":{"description":"The task preset's color.","type":["string","null"]},"pipeline_id":{"type":"string"},"pipeline_name":{"description":"The task preset's name.","type":["string","null"]},"position":{"description":"0 when none was sent.","type":"integer"},"trashed":{"description":"True when its task preset was deleted.","type":"boolean"}},"type":"object"},"type":"array"},"position":{"description":"Sort order within the preset list, lowest first. A decimal string, such as `\"1.0000000000000000\"`; parse it as a decimal.","example":"1.0000000000000000","type":"string"},"production_file":{"description":"Production files, in their order.","items":{"additionalProperties":false,"properties":{"collection":{"enum":["mockup","production_file"],"type":"string"},"created_at":{"description":"When the file record was made: the upload time, or for a duplicated preset, when it was copied.","format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"description":"The file's id: use it in `update` and `delete` file rows.","type":"string"},"is_image":{"type":"boolean"},"job_preset_id":{"description":"The preset the file belongs to.","type":"string"},"job_service":{"description":"The ids of this preset's service lines the file belongs to. A job made from the preset links its copy to the matching new services.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts, lowest first.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Null when it was never set.","type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"description":"Always null on a preset's files.","type":"null"},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","mime_type","is_image","show_in_pdf","source_media_id","name","file_name","size","url","view_url","preview","custom_properties","position","created_at","job_preset_id","job_service"],"type":"object"},"type":"array"},"service":{"description":"The service lines.","items":{"additionalProperties":true,"properties":{"customer_note":{"type":["string","null"]},"id":{"type":"string"},"location":{"additionalProperties":true,"description":"`type`, `display_name` and `trashed` (true when a saved location was deleted), plus `id` for a saved location or `name` for a custom one.","type":"object"},"note":{"type":["string","null"]},"option":{"type":["string","null"]},"position":{"type":"integer"},"review_reason":{"description":"Why the line needs review: its service was deleted, the service no longer has this option, or its saved location was deleted. Null when the line is fine.","enum":["service_removed","option_removed","location_removed",null],"type":["string","null"]},"service_id":{"type":"string"},"service_name":{"type":["string","null"]},"valid":{"description":"False when `review_reason` is set.","type":"boolean"},"version":{"const":1,"type":"integer"}},"type":"object"},"type":"array"},"updated_at":{"description":"When the preset was last edited (\"Last edited\" in the web app). Every save changes it, even one that changes only its lines; reordering presets doesn't.","format":"date-time","type":["string","null"]}},"required":["id","name","note","position","is_valid","needs_review","updated_at","service","pipeline","assigned_users","mockup","production_file"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Duplicate a job preset","tags":["Job presets"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Use an id from the list.","status":404,"when":"No job preset of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Edit the preset to remove that line, then try again.","status":422,"when":"A service, saved location or task preset the preset points to can't be found for your team, not even among deleted ones: `error.code` `job_validation_error`, such as \"Service not found!\". Nothing is copied."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_job_preset_show","v1_public_job_preset_update_patch","v1_public_job_preset_index"],"rules":["Deleted services, locations and task presets are copied as they are, so a preset that needs review gives a copy that needs review too."],"side_effects":["Team members who have YoPrint open see the new preset at once."]}}},"/v1/api/store/{team_slug}/setting/location":{"get":{"description":"Returns all the team's company locations in one list.\n\nBy default the list holds current locations only. Send `mode=history` to include deleted ones and older versions as well.\n\nCompany locations are the team's own addresses. Each one can play several parts:\n\n- **Primary location** (`is_primary`): the team's primary billing address. There is always exactly one.\n- **Warehouse** (`hold_stock`): a location that holds stock. Turning a location into a warehouse is permanent. How many warehouses a team can have depends on its plan.\n- **Default warehouse** (`is_default_warehouse`): the warehouse a new sales order uses when its customer has no default warehouse. Without one, YoPrint uses the first warehouse.\n- **Tax nexus** (`nexus`): a place where the team collects sales tax. For US-plan teams with Auto Tax, Auto Tax looks up rates only when the team has a current US location with nexus.\n\nOrders, purchase orders, stock and stock adjustments refer to a location by its id, so editing a location changes it everywhere it is used.","operationId":"v1_public_location_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"`history` also returns deleted and replaced locations. Any other value means `current`.","in":"query","name":"mode","required":false,"schema":{"default":"current","enum":["current","history"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"address1":"100 Example Street","address2":null,"address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List company locations","tags":["Company locations"],"x-yoprint-docs":{"group":"Team settings","notes":["Pick warehouses with `hold_stock: true`. The location with `is_default_warehouse: true` is the default."],"permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_location_store","v1_public_location_hold_stock","v1_public_location_default_warehouse"]}},"post":{"description":"Adds a company location and returns it. It doesn't hold stock; make it a warehouse with Set a location as a warehouse. The team's first location becomes its primary location; to move the primary role later, call Set the primary location.\n\nCompany locations are the team's own addresses. Each one can play several parts:\n\n- **Primary location** (`is_primary`): the team's primary billing address. There is always exactly one.\n- **Warehouse** (`hold_stock`): a location that holds stock. Turning a location into a warehouse is permanent. How many warehouses a team can have depends on its plan.\n- **Default warehouse** (`is_default_warehouse`): the warehouse a new sales order uses when its customer has no default warehouse. Without one, YoPrint uses the first warehouse.\n- **Tax nexus** (`nexus`): a place where the team collects sales tax. For US-plan teams with Auto Tax, Auto Tax looks up rates only when the team has a current US location with nexus.\n\nOrders, purchase orders, stock and stock adjustments refer to a location by its id, so editing a location changes it everywhere it is used.","operationId":"v1_public_location_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"address1":"100 Example Street","city":"Springfield","country_code":"US","is_primary":false,"label":"Warehouse 2","nexus":true,"postcode":"62701","state":"Illinois","state_code":"IL"},"schema":{"properties":{"address1":{"type":"string"},"address2":{"type":"string"},"city":{"type":"string"},"country":{"description":"The country name. Left out, none is stored, and answers show the name for `country_code`.","type":"string"},"country_code":{"description":"The two-letter country code, such as `US`. Saved in capitals.","type":"string"},"is_primary":{"description":"Optional and ignored: use Set the primary location.","type":"boolean"},"label":{"description":"A name for the location.","type":"string"},"nexus":{"description":"Whether the team collects sales tax here. Defaults to true.","type":"boolean"},"note":{"type":"string"},"postcode":{"type":"string"},"state":{"description":"The state or province name. For US and Canadian addresses it must be a real state or province; send it or `state_code`, and YoPrint fills in the other.","type":["string","null"]},"state_code":{"description":"The state or province code, such as `IL`. Saved in capitals.","type":["string","null"]}},"required":["label","address1","country_code"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"address1":"100 Example Street","address2":null,"address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":false,"id":"U4jnocbiJfXxQ9","is_current_source":true,"is_default_warehouse":false,"is_external":false,"is_primary":false,"label":"Warehouse 2","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a company location","tags":["Company locations"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A required field is missing, or a US or Canadian state is unknown or doesn't match `state_code` (\"Select a valid United States or Canada state/province.\"). `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_location_hold_stock","v1_public_location_primary"],"rules":["`label`, `address1` and `country_code` are required.","For US and Canadian addresses, `state` or `state_code` must be a real state or province. Send either one and YoPrint fills in the other; when you send both, they must match."],"side_effects":["A new location has tax nexus unless you send `nexus: false`. For US-plan teams this can turn on Auto Tax rate lookups."]}}},"/v1/api/store/{team_slug}/setting/location/{hash_id}":{"delete":{"description":"Deletes a company location. Orders and documents that used it keep showing it; it can be restored.\n\nWhen you delete the team's last warehouse, YoPrint turns the primary location into a warehouse so the team still has one.","operationId":"v1_public_location_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The company location's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"5ySODwONuta7hu","in":"path","name":"hash_id","required":true,"schema":{"example":"5ySODwONuta7hu","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"examples":{"blocked":{"summary":"A replaced version","value":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Unit 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"message_code":"blocked_superseded_historical_address","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_superseded_historical_address","stale_base":null},"message":"blocked_superseded_historical_address","success":false}},"last_warehouse":{"summary":"The last warehouse, with no primary location to take over","value":{"error":{"code":"hold_stock_repair_failed","message":"Cannot delete this warehouse because no current primary location is available to hold stock"},"status":409,"success":false}}},"schema":{"oneOf":[{"properties":{"address_save_result":{"properties":{"current_address":{"description":"On a 409: the location as it is now (for a replaced version, its current version). Null on a 200.","example":null,"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"},"used_by_active_profile":{"description":"Whether a customer profile uses this address. Normally false for company locations.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":["object","null"]},"message_code":{"description":"The same as `save_mode`.","example":"updated_operational_location_in_place","type":"string"},"operation_key":{"description":"Null: these operations take no key.","example":null,"type":["string","null"]},"previous_address":{"example":null,"type":["object","null"]},"replacement_address":{"example":null,"type":["object","null"]},"save_mode":{"enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"example":"blocked_superseded_historical_address","type":"string"},"stale_base":{"description":"On `stale_address`: `address_id`, your `base_revision_number` and the `current_revision_number`.","example":null,"type":["object","null"]}},"required":["save_mode","message_code","operation_key","previous_address","replacement_address","current_address","stale_base"],"type":"object"},"message":{"description":"The same as `save_mode`.","type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"title":"Not a current location","type":"object"},{"$ref":"#/components/schemas/ErrorResponse"}]}}},"description":"Not deleted: the id is a replaced, external or redacted row, or it is the last warehouse and no current primary location can take over."},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a company location","tags":["Company locations"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No company location with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Make another location primary first.","status":422,"when":"It is the primary location (`primary_delete_err`)."},{"fix":"Make another location a warehouse first.","status":409,"when":"It is the last warehouse and there is no current primary location to take over (`error.code` `hold_stock_repair_failed`)."},{"fix":"Use the current location instead.","status":409,"when":"It is a replaced version, or an external or redacted address. The body is the one Update a company location gives on a 409, `{success: false, address_save_result, message}`, with `save_mode` `blocked_superseded_historical_address` or `blocked_external_or_compliance`."}],"group":"Team settings","notes":["YoPrint doesn't move the default warehouse when you delete it. Set another default warehouse afterwards."],"permission":"Needs the Manage Settings permission.","related":["v1_public_location_restore","v1_public_location_primary"],"rules":["The primary location cannot be deleted.","Replaced versions and external addresses cannot be deleted."],"side_effects":["Deleting the last warehouse makes the primary location a warehouse."]}},"get":{"description":"Returns one company location, deleted or not.","operationId":"v1_public_location_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The company location's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"5ySODwONuta7hu","in":"path","name":"hash_id","required":true,"schema":{"example":"5ySODwONuta7hu","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"address1":"100 Example Street","address2":null,"address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show a company location","tags":["Company locations"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_location_update_patch"]}},"patch":{"description":"Use PUT to change a company location. PATCH saves the same fields but skips most field validation.\n\nChanges a location's address, label, note or tax nexus in place: the id stays the same, so every order, purchase order and stock record that uses it shows the new address.\n\nThe response is not in the usual envelope: it is `{success, address_save_result, data}`, with no `status` key. The `save_mode` in `address_save_result` says what happened: `updated_operational_location_in_place`, or `no_address_fields_changed` when nothing differed.\n\nSend `base_revision_number` (the `revision_number` you read) to avoid overwriting someone else's edit: if it no longer matches, nothing is saved and you get 409 `stale_address`.","operationId":"v1_public_location_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The company location's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"5ySODwONuta7hu","in":"path","name":"hash_id","required":true,"schema":{"example":"5ySODwONuta7hu","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"address2":"Unit 4","base_revision_number":1,"label":"Main shop","operation_key":"location-edit-1001"},"schema":{"description":"Send only what changes. Fields you leave out keep their stored values.","properties":{"address1":{"type":"string"},"address2":{"type":"string"},"base_revision_number":{"description":"The `revision_number` you last read. When it no longer matches, nothing is saved and you get 409 `stale_address`.","type":"integer"},"city":{"type":"string"},"country":{"description":"The country name. Left out, the stored name stays, even when you change `country_code`: send both together. With no stored name, answers show the name for `country_code`.","type":"string"},"country_code":{"description":"The two-letter country code, such as `US`. Saved in capitals.","type":"string"},"is_primary":{"description":"Ignored: use Set the primary location.","type":"boolean"},"label":{"description":"A name for the location.","type":"string"},"nexus":{"description":"Whether the team collects sales tax here. Left out, it stays as it is.","type":"boolean"},"note":{"type":"string"},"operation_key":{"description":"Your own key for this edit, echoed back in `address_save_result`.","type":"string"},"postcode":{"type":"string"},"state":{"description":"The state or province name. For US and Canadian addresses it must be a real state or province; send it or `state_code`, and YoPrint fills in the other.","type":["string","null"]},"state_code":{"description":"The state or province code, such as `IL`. Saved in capitals.","type":["string","null"]}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"address_save_result":{"current_address":null,"message_code":"updated_operational_location_in_place","operation_key":"location-edit-1001","previous_address":null,"replacement_address":null,"save_mode":"updated_operational_location_in_place","stale_base":null},"data":{"address1":"100 Example Street","address2":"Unit 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false},"success":true},"schema":{"properties":{"address_save_result":{"properties":{"current_address":{"description":"On a 409: the location as it is now (for a replaced version, its current version). Null on a 200.","example":null,"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"},"used_by_active_profile":{"description":"Whether a customer profile uses this address. Normally false for company locations.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":["object","null"]},"message_code":{"description":"The same as `save_mode`.","example":"updated_operational_location_in_place","type":"string"},"operation_key":{"description":"Your `operation_key`, or one YoPrint made.","example":"location-edit-1001","type":"string"},"previous_address":{"example":null,"type":["object","null"]},"replacement_address":{"example":null,"type":["object","null"]},"save_mode":{"enum":["updated_operational_location_in_place","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"example":"updated_operational_location_in_place","type":"string"},"stale_base":{"description":"On `stale_address`: `address_id`, your `base_revision_number` and the `current_revision_number`.","example":null,"type":["object","null"]}},"required":["save_mode","message_code","operation_key","previous_address","replacement_address","current_address","stale_base"],"type":"object"},"data":{"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"},"used_by_active_profile":{"description":"Whether a customer profile uses this address. Normally false for company locations.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","address_save_result","data"],"type":"object"}}},"description":"Saved, or nothing to change."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Unit 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false},"message_code":"stale_address","operation_key":"location-edit-1001","previous_address":null,"replacement_address":null,"save_mode":"stale_address","stale_base":{"address_id":"5ySODwONuta7hu","base_revision_number":1,"current_revision_number":2}},"message":"stale_address","success":false},"schema":{"properties":{"address_save_result":{"properties":{"current_address":{"description":"On a 409: the location as it is now (for a replaced version, its current version). Null on a 200.","example":null,"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"},"used_by_active_profile":{"description":"Whether a customer profile uses this address. Normally false for company locations.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":["object","null"]},"message_code":{"description":"The same as `save_mode`.","example":"updated_operational_location_in_place","type":"string"},"operation_key":{"description":"Your `operation_key`, or one YoPrint made.","example":"location-edit-1001","type":"string"},"previous_address":{"example":null,"type":["object","null"]},"replacement_address":{"example":null,"type":["object","null"]},"save_mode":{"enum":["updated_operational_location_in_place","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"example":"updated_operational_location_in_place","type":"string"},"stale_base":{"description":"On `stale_address`: `address_id`, your `base_revision_number` and the `current_revision_number`.","example":null,"type":["object","null"]}},"required":["save_mode","message_code","operation_key","previous_address","replacement_address","current_address","stale_base"],"type":"object"},"message":{"description":"The same as `save_mode`.","type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"type":"object"}}},"description":"Not saved: the location changed since you read it (`stale_address`), or it is a replaced, external or redacted row."},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a company location without checks","tags":["Company locations"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No current company location with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A US or Canadian state is unknown or doesn't match `state_code`. On PATCH this is the only field check. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."},{"fix":"Read the location again (`current_address` holds it), then retry with its `revision_number`.","status":409,"when":"`stale_address`: `base_revision_number` doesn't match. Or the row is a replaced version, or an external or redacted address."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_location_show"],"rules":["Only the address fields, `label`, `note` and `nexus` are saved. `is_primary` and warehouse settings have their own operations.","For US and Canadian addresses, `state` or `state_code` must be a real state or province. Send either one and YoPrint fills in the other; when you send both, they must match.","A deleted location cannot be updated."],"side_effects":["Changes the address everywhere it is used, including open orders, purchase orders and new PDFs.","Turning `nexus` on or off can change Auto Tax for US-plan teams."]}},"put":{"description":"Changes a location's address, label, note or tax nexus in place: the id stays the same, so every order, purchase order and stock record that uses it shows the new address.\n\nThe response is not in the usual envelope: it is `{success, address_save_result, data}`, with no `status` key. The `save_mode` in `address_save_result` says what happened: `updated_operational_location_in_place`, or `no_address_fields_changed` when nothing differed.\n\nSend `base_revision_number` (the `revision_number` you read) to avoid overwriting someone else's edit: if it no longer matches, nothing is saved and you get 409 `stale_address`.","operationId":"v1_public_location_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The company location's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"5ySODwONuta7hu","in":"path","name":"hash_id","required":true,"schema":{"example":"5ySODwONuta7hu","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"address2":"Unit 4","base_revision_number":1,"label":"Main shop","operation_key":"location-edit-1001"},"schema":{"description":"Send only what changes. Fields you leave out keep their stored values.","properties":{"address1":{"type":"string"},"address2":{"type":"string"},"base_revision_number":{"description":"The `revision_number` you last read. When it no longer matches, nothing is saved and you get 409 `stale_address`.","type":"integer"},"city":{"type":"string"},"country":{"description":"The country name. Left out, the stored name stays, even when you change `country_code`: send both together. With no stored name, answers show the name for `country_code`.","type":"string"},"country_code":{"description":"The two-letter country code, such as `US`. Saved in capitals.","type":"string"},"is_primary":{"description":"Ignored: use Set the primary location.","type":"boolean"},"label":{"description":"A name for the location.","type":"string"},"nexus":{"description":"Whether the team collects sales tax here. Left out, it stays as it is.","type":"boolean"},"note":{"type":"string"},"operation_key":{"description":"Your own key for this edit, echoed back in `address_save_result`.","type":"string"},"postcode":{"type":"string"},"state":{"description":"The state or province name. For US and Canadian addresses it must be a real state or province; send it or `state_code`, and YoPrint fills in the other.","type":["string","null"]},"state_code":{"description":"The state or province code, such as `IL`. Saved in capitals.","type":["string","null"]}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"address_save_result":{"current_address":null,"message_code":"updated_operational_location_in_place","operation_key":"location-edit-1001","previous_address":null,"replacement_address":null,"save_mode":"updated_operational_location_in_place","stale_base":null},"data":{"address1":"100 Example Street","address2":"Unit 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false},"success":true},"schema":{"properties":{"address_save_result":{"properties":{"current_address":{"description":"On a 409: the location as it is now (for a replaced version, its current version). Null on a 200.","example":null,"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"},"used_by_active_profile":{"description":"Whether a customer profile uses this address. Normally false for company locations.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":["object","null"]},"message_code":{"description":"The same as `save_mode`.","example":"updated_operational_location_in_place","type":"string"},"operation_key":{"description":"Your `operation_key`, or one YoPrint made.","example":"location-edit-1001","type":"string"},"previous_address":{"example":null,"type":["object","null"]},"replacement_address":{"example":null,"type":["object","null"]},"save_mode":{"enum":["updated_operational_location_in_place","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"example":"updated_operational_location_in_place","type":"string"},"stale_base":{"description":"On `stale_address`: `address_id`, your `base_revision_number` and the `current_revision_number`.","example":null,"type":["object","null"]}},"required":["save_mode","message_code","operation_key","previous_address","replacement_address","current_address","stale_base"],"type":"object"},"data":{"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"},"used_by_active_profile":{"description":"Whether a customer profile uses this address. Normally false for company locations.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","address_save_result","data"],"type":"object"}}},"description":"Saved, or nothing to change."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Unit 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false,"used_by_active_profile":false},"message_code":"stale_address","operation_key":"location-edit-1001","previous_address":null,"replacement_address":null,"save_mode":"stale_address","stale_base":{"address_id":"5ySODwONuta7hu","base_revision_number":1,"current_revision_number":2}},"message":"stale_address","success":false},"schema":{"properties":{"address_save_result":{"properties":{"current_address":{"description":"On a 409: the location as it is now (for a replaced version, its current version). Null on a 200.","example":null,"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"},"used_by_active_profile":{"description":"Whether a customer profile uses this address. Normally false for company locations.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":["object","null"]},"message_code":{"description":"The same as `save_mode`.","example":"updated_operational_location_in_place","type":"string"},"operation_key":{"description":"Your `operation_key`, or one YoPrint made.","example":"location-edit-1001","type":"string"},"previous_address":{"example":null,"type":["object","null"]},"replacement_address":{"example":null,"type":["object","null"]},"save_mode":{"enum":["updated_operational_location_in_place","no_address_fields_changed","stale_address","blocked_superseded_historical_address","blocked_external_or_compliance"],"example":"updated_operational_location_in_place","type":"string"},"stale_base":{"description":"On `stale_address`: `address_id`, your `base_revision_number` and the `current_revision_number`.","example":null,"type":["object","null"]}},"required":["save_mode","message_code","operation_key","previous_address","replacement_address","current_address","stale_base"],"type":"object"},"message":{"description":"The same as `save_mode`.","type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"type":"object"}}},"description":"Not saved: the location changed since you read it (`stale_address`), or it is a replaced, external or redacted row."},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a company location","tags":["Company locations"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No current company location with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A field has the wrong type, or a US or Canadian state is unknown or doesn't match `state_code`. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."},{"fix":"Read the location again (`current_address` holds it), then retry with its `revision_number`.","status":409,"when":"`stale_address`: `base_revision_number` doesn't match. Or the row is a replaced version, or an external or redacted address."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_location_show"],"rules":["Only the address fields, `label`, `note` and `nexus` are saved. `is_primary` and warehouse settings have their own operations.","For US and Canadian addresses, `state` or `state_code` must be a real state or province. Send either one and YoPrint fills in the other; when you send both, they must match.","A deleted location cannot be updated."],"side_effects":["Changes the address everywhere it is used, including open orders, purchase orders and new PDFs.","Turning `nexus` on or off can change Auto Tax for US-plan teams."]}}},"/v1/api/store/{team_slug}/setting/location/{id}/default_warehouse":{"patch":{"description":"Makes this warehouse the team's default warehouse and returns it. New sales orders use it when their customer has no default warehouse. The location must already hold stock.","operationId":"v1_public_location_default_warehouse","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The company location's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"5ySODwONuta7hu","in":"path","name":"id","required":true,"schema":{"example":"5ySODwONuta7hu","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"address1":"100 Example Street","address2":null,"address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Unit 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"message_code":"blocked_superseded_historical_address","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_superseded_historical_address","stale_base":null},"message":"blocked_superseded_historical_address","success":false},"schema":{"properties":{"address_save_result":{"properties":{"current_address":{"description":"On a 409: the location as it is now (for a replaced version, its current version). Null on a 200.","example":null,"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"},"used_by_active_profile":{"description":"Whether a customer profile uses this address. Normally false for company locations.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":["object","null"]},"message_code":{"description":"The same as `save_mode`.","example":"updated_operational_location_in_place","type":"string"},"operation_key":{"description":"Null: these operations take no key.","example":null,"type":["string","null"]},"previous_address":{"example":null,"type":["object","null"]},"replacement_address":{"example":null,"type":["object","null"]},"save_mode":{"enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"example":"blocked_superseded_historical_address","type":"string"},"stale_base":{"description":"On `stale_address`: `address_id`, your `base_revision_number` and the `current_revision_number`.","example":null,"type":["object","null"]}},"required":["save_mode","message_code","operation_key","previous_address","replacement_address","current_address","stale_base"],"type":"object"},"message":{"description":"The same as `save_mode`.","type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"title":"Not a current location","type":"object"}}},"description":"Not done: the id is a replaced version, or an external or redacted address. `current_address` holds the current version, when there is one."},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set the default warehouse","tags":["Company locations"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No current company location with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Use the current location's id, from `current_address` in the answer.","status":409,"when":"The location is a replaced version, or an external or redacted address. The body is the one Update a company location gives on a 409, `{success: false, address_save_result, message}`, with `save_mode` `blocked_superseded_historical_address` or `blocked_external_or_compliance`."},{"fix":"Call Set a location as a warehouse first.","status":422,"when":"The location doesn't hold stock (`not_a_warehouse`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_location_hold_stock"],"rules":["The location must be a warehouse (`hold_stock: true`)."]}}},"/v1/api/store/{team_slug}/setting/location/{id}/hold_stock":{"patch":{"description":"Turns a company location into a warehouse that can hold stock (`hold_stock: true`) and returns it. This is permanent: no operation turns it back. The number of warehouses is limited by the team's plan.","operationId":"v1_public_location_hold_stock","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The company location's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"5ySODwONuta7hu","in":"path","name":"id","required":true,"schema":{"example":"5ySODwONuta7hu","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"address1":"100 Example Street","address2":null,"address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Unit 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"message_code":"blocked_superseded_historical_address","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_superseded_historical_address","stale_base":null},"message":"blocked_superseded_historical_address","success":false},"schema":{"properties":{"address_save_result":{"properties":{"current_address":{"description":"On a 409: the location as it is now (for a replaced version, its current version). Null on a 200.","example":null,"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"},"used_by_active_profile":{"description":"Whether a customer profile uses this address. Normally false for company locations.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":["object","null"]},"message_code":{"description":"The same as `save_mode`.","example":"updated_operational_location_in_place","type":"string"},"operation_key":{"description":"Null: these operations take no key.","example":null,"type":["string","null"]},"previous_address":{"example":null,"type":["object","null"]},"replacement_address":{"example":null,"type":["object","null"]},"save_mode":{"enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"example":"blocked_superseded_historical_address","type":"string"},"stale_base":{"description":"On `stale_address`: `address_id`, your `base_revision_number` and the `current_revision_number`.","example":null,"type":["object","null"]}},"required":["save_mode","message_code","operation_key","previous_address","replacement_address","current_address","stale_base"],"type":"object"},"message":{"description":"The same as `save_mode`.","type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"title":"Not a current location","type":"object"}}},"description":"Not done: the id is a replaced version, or an external or redacted address. `current_address` holds the current version, when there is one."}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set a location as a warehouse","tags":["Company locations"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No current company location with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Use the current location's id, from `current_address` in the answer.","status":409,"when":"The location is a replaced version, or an external or redacted address. The body is the one Update a company location gives on a 409, `{success: false, address_save_result, message}`, with `save_mode` `blocked_superseded_historical_address` or `blocked_external_or_compliance`."},{"fix":"Upgrade the plan, or use an existing warehouse.","status":403,"when":"The plan's warehouse limit is reached. The body is short: `{\"message\": \"Plan only allow maximum of N warehouses to hold stock\"}` (`warehouse` when N is 1)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_location_default_warehouse"],"rules":["Permanent.","The team's plan must allow another warehouse."],"side_effects":["Stock can now be received, adjusted and allocated at this location."]}}},"/v1/api/store/{team_slug}/setting/location/{id}/primary":{"patch":{"description":"Makes this company location the team's primary location (its primary billing address) and returns it. The previous primary location stops being primary.","operationId":"v1_public_location_primary","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The company location's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"5ySODwONuta7hu","in":"path","name":"id","required":true,"schema":{"example":"5ySODwONuta7hu","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"address1":"100 Example Street","address2":null,"address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":1,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Unit 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"message_code":"blocked_superseded_historical_address","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_superseded_historical_address","stale_base":null},"message":"blocked_superseded_historical_address","success":false},"schema":{"properties":{"address_save_result":{"properties":{"current_address":{"description":"On a 409: the location as it is now (for a replaced version, its current version). Null on a 200.","example":null,"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"},"used_by_active_profile":{"description":"Whether a customer profile uses this address. Normally false for company locations.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":["object","null"]},"message_code":{"description":"The same as `save_mode`.","example":"updated_operational_location_in_place","type":"string"},"operation_key":{"description":"Null: these operations take no key.","example":null,"type":["string","null"]},"previous_address":{"example":null,"type":["object","null"]},"replacement_address":{"example":null,"type":["object","null"]},"save_mode":{"enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"example":"blocked_superseded_historical_address","type":"string"},"stale_base":{"description":"On `stale_address`: `address_id`, your `base_revision_number` and the `current_revision_number`.","example":null,"type":["object","null"]}},"required":["save_mode","message_code","operation_key","previous_address","replacement_address","current_address","stale_base"],"type":"object"},"message":{"description":"The same as `save_mode`.","type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"title":"Not a current location","type":"object"}}},"description":"Not done: the id is a replaced version, or an external or redacted address. `current_address` holds the current version, when there is one."}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set the primary location","tags":["Company locations"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No current company location with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Use the current location's id, from `current_address` in the answer.","status":409,"when":"The location is a replaced version, or an external or redacted address. The body is the one Update a company location gives on a 409, `{success: false, address_save_result, message}`, with `save_mode` `blocked_superseded_historical_address` or `blocked_external_or_compliance`."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_location_index"],"side_effects":["Tells the team's open web app sessions that the primary location changed."]}}},"/v1/api/store/{team_slug}/setting/location/{id}/restore":{"patch":{"description":"Brings back a deleted company location. Get its id from List company locations with `mode=history`.","operationId":"v1_public_location_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The company location's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"5ySODwONuta7hu","in":"path","name":"id","required":true,"schema":{"example":"5ySODwONuta7hu","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"address_save_result":{"current_address":{"address1":"100 Example Street","address2":"Unit 4","address_family_id":null,"city":"Springfield","copied_from_address_id":null,"country":"United States","country_code":"US","external_type":null,"hold_stock":true,"id":"5ySODwONuta7hu","is_current_source":true,"is_default_warehouse":true,"is_external":false,"is_primary":true,"label":"Main shop","nexus":true,"note":null,"owner_id":"U9KHQle41wSkHO","owner_type":"team","postal_can_validate":false,"postal_is_valid":false,"postal_validated":false,"postcode":"62701","revision_number":2,"role":"store_location","source":"company_location","state":"Illinois","state_code":"IL","superseded_at":null,"superseded_by_address_id":null,"trashed":false},"message_code":"blocked_superseded_historical_address","operation_key":null,"previous_address":null,"replacement_address":null,"save_mode":"blocked_superseded_historical_address","stale_base":null},"message":"blocked_superseded_historical_address","success":false},"schema":{"properties":{"address_save_result":{"properties":{"current_address":{"description":"On a 409: the location as it is now (for a replaced version, its current version). Null on a 200.","example":null,"properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"example":null,"type":["string","null"]},"address_family_id":{"description":"Groups an address with the versions that replaced it.","example":null,"type":["string","null"]},"city":{"example":"Springfield","type":["string","null"]},"copied_from_address_id":{"description":"The address this one replaced, if any.","example":null,"type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"external_type":{"example":null,"type":["string","null"]},"hold_stock":{"description":"Whether it is a warehouse that holds stock. Permanent once set.","example":true,"type":"boolean"},"id":{"example":"5ySODwONuta7hu","type":"string"},"is_current_source":{"description":"False for deleted or replaced rows.","example":true,"type":"boolean"},"is_default_warehouse":{"description":"The default warehouse for new sales orders.","example":true,"type":"boolean"},"is_external":{"example":false,"type":"boolean"},"is_primary":{"description":"The team's primary location: its primary billing address. Exactly one.","example":true,"type":"boolean"},"label":{"example":"Main shop","type":["string","null"]},"nexus":{"description":"Whether the team collects sales tax here (tax nexus).","example":true,"type":"boolean"},"note":{"example":null,"type":["string","null"]},"owner_id":{"description":"For company locations, the team, encoded with the team's own hash ids. It is not the same string as the team `id` that Get your company details returns.","example":"U9KHQle41wSkHO","type":["string","null"]},"owner_type":{"example":"team","type":"string"},"postal_can_validate":{"example":false,"type":"boolean"},"postal_is_valid":{"example":false,"type":"boolean"},"postal_validated":{"example":false,"type":"boolean"},"postcode":{"example":"62701","type":["string","null"]},"revision_number":{"description":"Goes up by one on every saved change. Send it back as `base_revision_number` to avoid overwriting someone else's edit.","example":1,"type":"integer"},"role":{"description":"Always `store_location` for company locations.","example":"store_location","type":"string"},"source":{"example":"company_location","type":"string"},"state":{"example":"Illinois","type":["string","null"]},"state_code":{"example":"IL","type":["string","null"]},"superseded_at":{"description":"When it was replaced, if it was.","example":null,"format":"date-time","type":["string","null"]},"superseded_by_address_id":{"description":"The address that replaced this one, if any. Company locations are edited in place, so this is normally null.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted location.","example":false,"type":"boolean"},"used_by_active_profile":{"description":"Whether a customer profile uses this address. Normally false for company locations.","example":false,"type":"boolean"}},"required":["id","label","address1","city","country_code","role","is_primary","is_default_warehouse","hold_stock","nexus","trashed","revision_number","is_current_source"],"type":["object","null"]},"message_code":{"description":"The same as `save_mode`.","example":"updated_operational_location_in_place","type":"string"},"operation_key":{"description":"Null: these operations take no key.","example":null,"type":["string","null"]},"previous_address":{"example":null,"type":["object","null"]},"replacement_address":{"example":null,"type":["object","null"]},"save_mode":{"enum":["blocked_superseded_historical_address","blocked_external_or_compliance"],"example":"blocked_superseded_historical_address","type":"string"},"stale_base":{"description":"On `stale_address`: `address_id`, your `base_revision_number` and the `current_revision_number`.","example":null,"type":["object","null"]}},"required":["save_mode","message_code","operation_key","previous_address","replacement_address","current_address","stale_base"],"type":"object"},"message":{"description":"The same as `save_mode`.","type":"string"},"success":{"const":false,"type":"boolean"}},"required":["success","address_save_result","message"],"title":"Not a current location","type":"object"}}},"description":"Not done: the id is a replaced version, or an external or redacted address. `current_address` holds the current version, when there is one."}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a company location","tags":["Company locations"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No company location with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Use the current location instead.","status":409,"when":"It is a replaced version, or an external or redacted address. The body is the one Update a company location gives on a 409, `{success: false, address_save_result, message}`, with `save_mode` `blocked_superseded_historical_address` or `blocked_external_or_compliance`."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_location_index"]}}},"/v1/api/store/{team_slug}/setting/payment_gateway":{"put":{"description":"Turns card payment gateways on or off and stores their credentials: Stripe, PayPal, Square, Charge It Pro and Authorize.Net. Returns the team settings, as Show team settings does.\n\nSend only the gateways you are changing; stored values you leave out stay as they are. Turning a gateway off (`enable_stripe: false`, for example) keeps its stored credentials.\n\nBefore saving, YoPrint checks the credentials with the provider and sets up the provider's notifications to YoPrint:\n\n- **Stripe:** reads your Stripe account with the key, then creates or updates a webhook endpoint in your Stripe account, pointing at `stripe_webhook_url`, for refunds (`charge.refunded`, `charge.refund.updated`, `refund.created`, `refund.updated`, `refund.failed`), disputes (`charge.dispute.created`, `.updated`, `.closed`, `.funds_withdrawn`, `.funds_reinstated`) and payments (`payment_intent.succeeded`, `payment_intent.payment_failed`, `payment_intent.canceled`). An existing endpoint on another Stripe API version is deleted and made again.\n- **PayPal:** checks the credentials (they must be live), then creates or updates a PayPal webhook for payment capture, refund and dispute events.\n- **Square:** for each location in `square_webhook_locations`, turns on Square's `PAYMENT_UPDATED` notification. Add YoPrint's `square_webhook_url` in the Square Developer Dashboard first.\n- **Authorize.Net:** checks the login id, transaction key and client key, then creates a webhook.\n- **Charge It Pro** (Gravity Payments in the web app) is being retired. You can't connect it as a new gateway: the call is refused with 422 `charge_it_pro_retired`. A team that already has it on can still change its settings, until Charge It Pro is retired (planned for 1 January 2027). Turning it off while a payment is still being processed is refused with 422 `charge_it_pro_payment_in_progress`: try again later. Connect another gateway to take card payments. For a team that can still save its settings, YoPrint doesn't call Gravity Payments: when `charge_it_pro_oid` or `charge_it_pro_auth_key` differs from the stored value, it checks only that both are present and not too long.\n\nWhen the save changes a gateway's credentials, YoPrint records who changed which gateway (never the values) and emails the team owner.\n\nThis operation only configures gateways. Card charges and refunds go through the sales order payment operations (see Related).","operationId":"v1_public_setting_payment_gateway_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"off":{"summary":"Turn off PayPal","value":{"enable_paypal":false}},"stripe":{"summary":"Turn on Stripe","value":{"enable_stripe":true,"publishable_key":"YOUR_PUBLISHABLE_KEY","stripe_secret_key":"YOUR_GATEWAY_SECRET"}}},"schema":{"properties":{"authorize_client_key":{"description":"Your public client key. Required when `enable_authorize_net` is true.","type":"string"},"authorize_login_id":{"description":"Required when `enable_authorize_net` is true.","type":"string"},"authorize_sig_key":{"description":"Your signature key. Required when `enable_authorize_net` is true.","type":"string"},"authorize_trans_key":{"description":"Required when `enable_authorize_net` is true.","type":"string"},"charge_it_pro_auth_key":{"description":"Retired. Required when `enable_charge_it_pro` is true.","type":"string"},"charge_it_pro_device_id":{"description":"Retired. The default card device. Required when `charge_it_pro_mode` is `in-person` or `both`.","type":"string"},"charge_it_pro_mode":{"description":"Retired. Required when `enable_charge_it_pro` is true.","enum":["in-person","online","both"],"type":"string"},"charge_it_pro_oid":{"description":"Retired. Required when `enable_charge_it_pro` is true.","type":"string"},"enable_authorize_net":{"description":"Turns Authorize.Net on or off.","type":"boolean"},"enable_charge_it_pro":{"description":"Retired. Turns Charge It Pro off. Turning it on for a team that does not already have it is refused with 422 `charge_it_pro_retired`.","type":"boolean"},"enable_paypal":{"description":"Turns PayPal on or off.","type":"boolean"},"enable_square":{"description":"Turns Square on or off.","type":"boolean"},"enable_square_payment":{"description":"Whether online payments go to Square. Required when `enable_square` is true.","type":"boolean"},"enable_stripe":{"description":"Turns Stripe card payments on or off.","type":"boolean"},"paypal_client_id":{"description":"Required when `enable_paypal` is true. Use live credentials.","type":"string"},"paypal_secret":{"description":"Required when `enable_paypal` is true.","type":"string"},"publishable_key":{"description":"Your Stripe publishable key, starting with `pk_live_` or `pk_test_`. Required when `enable_stripe` is true.","example":"YOUR_PUBLISHABLE_KEY","type":"string"},"square_access_token":{"description":"Required when `enable_square` is true.","type":"string"},"square_client_id":{"description":"Your Square application id. Required when `enable_square` is true.","type":"string"},"square_location_id":{"description":"The Square location online payments are credited to. Required when `enable_square_payment` is true. Get ids from List Square locations.","type":"string"},"square_webhook_locations":{"description":"The Square locations whose payments YoPrint listens to. Required when `enable_square` is true.","items":{"properties":{"id":{"description":"A Square location id.","type":"string"}},"required":["id"],"type":"object"},"type":"array"},"square_webhook_sig":{"description":"The signature key of the webhook you added in Square. Required when `enable_square` is true.","type":"string"},"stripe_secret_key":{"description":"Your Stripe secret key (`sk_live_`, `sk_test_`) or restricted key (`rk_live_`, `rk_test_`). A restricted key needs Accounts (under Connect) set to Read and Webhook Endpoints set to Write. Required when `enable_stripe` is true.","example":"YOUR_GATEWAY_SECRET","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"cust_msg_status":true,"customer_portal_account_login_available":true,"customer_portal_rollout":{"account_only":false,"all_teams_at":null,"configuration_warning":null,"legacy_access_allowed":true,"new_teams_at":null,"reason":"transition"},"default_pricing_strategy":"job_separately","enable_stripe":true,"payment_amount_policies":{"USD":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null}},"payment_amount_policy":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null},"paypal_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/paypal","pdf_date_format":"other_1","shipping_label_create_cost_line_item":true,"square_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/square","stripe_webhook_url":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/stripe","tax_label_name":"Tax","web_date_format":"default"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"Every stored team setting, keyed by name, with defaults filled in for the display options, and the team's stored payment gateway values: all of them for the team owner and members with Manage Settings, only the account identifiers for other members (see Show team settings).","properties":{"cust_msg_status":{"example":true,"type":"boolean"},"customer_portal_account_login_available":{"description":"Worked out by YoPrint: whether customers can sign in to your customer portal with an email account. True when your plan includes the customer portal.","example":true,"type":"boolean"},"customer_portal_rollout":{"additionalProperties":false,"description":"Worked out by YoPrint: where the customer portal's move to email-account sign-in stands for your team. YoPrint sets the dates; you can't change them here.","properties":{"account_only":{"description":"True when customers must sign in with an email account: a direct portal link alone no longer opens the portal.","example":false,"type":"boolean"},"all_teams_at":{"description":"When account login becomes mandatory for all teams (UTC), or null if not set.","example":null,"format":"date-time","type":["string","null"]},"configuration_warning":{"description":"A system warning if rollout dates are inconsistent (`new_teams_cutoff_not_before_all_teams_cutoff` or `invalid_rollout_date`), or null.","enum":["new_teams_cutoff_not_before_all_teams_cutoff","invalid_rollout_date",null],"example":null,"type":["string","null"]},"legacy_access_allowed":{"description":"True when direct portal links still open the portal without an account sign-in.","example":true,"type":"boolean"},"new_teams_at":{"description":"When account login became mandatory for new teams (UTC), or null if not set.","example":null,"format":"date-time","type":["string","null"]},"reason":{"description":"Why this rollout policy applies to your team: `transition` (standard rollout period), `new_team_cutoff` (new team policy), or `all_teams_cutoff` (mandatory for all teams).","enum":["transition","new_team_cutoff","all_teams_cutoff"],"example":"transition","type":"string"}},"required":["account_only","legacy_access_allowed","reason","new_teams_at","all_teams_at","configuration_warning"],"type":"object"},"default_pricing_strategy":{"description":"How new jobs are priced by default. `job_separately` when never set.","enum":["job_separately","job_together","service_loc_together"],"example":"job_separately","type":"string"},"enable_stripe":{"description":"Present once it was sent to Update payment gateway settings, with the value sent. The same for `enable_paypal`, `enable_square`, `enable_square_payment`, `enable_charge_it_pro`, `enable_authorize_net` and `charge_it_pro_mode`.","example":true,"type":"boolean"},"payment_amount_policies":{"additionalProperties":{"additionalProperties":true,"type":"object"},"description":"Read only: the minimum payment policy for each of your currencies (deleted ones included), keyed by ISO currency code. An empty list `[]` when the team has no currencies.","example":{"USD":{"currency":"USD","minimum_payment":{"dp":3,"value":"1000"},"minimum_remaining_balance":null}},"type":["object","array"]},"payment_amount_policy":{"description":"Read only: the smallest payment YoPrint accepts in your default currency, or null when the team has no default currency.","properties":{"currency":{"description":"The currency code.","example":"USD","type":"string"},"minimum_payment":{"description":"A decimal pair whose `value` is a string: the amount is `value` ÷ 10^`dp` (`{\"value\": \"1000\", \"dp\": 3}` is 1.00). YoPrint refuses smaller payments.","properties":{"dp":{"const":3,"description":"Always 3.","example":3,"type":"integer"},"value":{"description":"The unscaled amount as a string.","example":"1000","type":"string"}},"required":["value","dp"],"type":"object"},"minimum_remaining_balance":{"description":"Always null here.","example":null,"type":"null"}},"type":["object","null"]},"paypal_webhook_url":{"example":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/paypal","type":"string"},"pdf_date_format":{"description":"The date format on PDFs. `std` is the default for a team that never changed it; PDFs show it like `other_1` (05 Nov 2026). A team whose saved settings have no date format reads `other_1`. Update general settings accepts only the other five values.","enum":["std","default","british_standard","us_standard","international","other_1"],"example":"other_1","type":"string"},"shipping_label_create_cost_line_item":{"description":"Whether \"Create Shipping Cost Line Item\" starts checked when someone buys a shipping label in the web app. `true` when never set.","example":true,"type":"boolean"},"square_webhook_url":{"description":"Add this URL in the Square Developer Dashboard before you turn Square on.","example":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/square","type":"string"},"stripe_webhook_url":{"description":"The URL Stripe calls for this team. YoPrint registers it in your Stripe account when you save Stripe settings.","example":"https://secure.yoprint.com/api/store/your-team/webhook/v1/payment/stripe","type":"string"},"tax_label_name":{"description":"The name used for tax on documents. `Tax` when never set.","example":"Tax","type":"string"},"web_date_format":{"description":"The date format in the web app. `us` is the default for a team that never changed it; the web app shows it like `default` (Nov 05, 2026). A team whose saved settings have no date format reads `default`. Update general settings accepts only the other five values.","enum":["us","default","british_standard","us_standard","international","other_1"],"example":"default","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update payment gateway settings","tags":["Payment gateways"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A required credential is missing or malformed. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."},{"fix":"For `missing_permission`, edit the key in Stripe: Accounts (under Connect) Read for `connected_account_read`, Webhook Endpoints Write for `webhook_write`. For `key_rejected`, paste the key again or make a new restricted key. Otherwise try again in a minute.","status":422,"when":"Stripe refused or failed: `error.code` `stripe_setup_error`, with `error.reason` and `error.stripe_permission`. `reason` is `missing_permission` (the key lacks a permission; `stripe_permission` is `connected_account_read` or `webhook_write`), `key_rejected` (Stripe didn't accept the key), `stripe_unreachable` (YoPrint couldn't check the key) or `webhook_failed` (the webhook couldn't be set up); `stripe_permission` is null for the last three. `error.message` says what to do."},{"fix":"Check the credentials in the provider's dashboard. For Square, add YoPrint's webhook URL in Square first.","status":422,"when":"Another provider rejected the credentials or the webhook setup. `error.code` is `paypal_setup_error`, `square_setup_error` or `authorize_setup_error`, with a message."},{"fix":"Connect Stripe, PayPal, Square or Authorize.Net instead.","status":422,"when":"Charge It Pro is retired: you sent a Charge It Pro key or setting for a team that does not have it on, or after it was retired (`charge_it_pro_retired`, \"Gravity Payments is no longer supported in YoPrint. Connect another payment provider to take card payments.\")."},{"fix":"Try again later.","status":422,"when":"You turned Charge It Pro off while one of its payments is still being processed (`charge_it_pro_payment_in_progress`, \"A Gravity Payments payment is still being processed, so Gravity Payments can't be removed yet. Try again later.\")."},{"fix":"Copy the org id and auth key again from Gravity Payments.","status":422,"when":"Charge It Pro: a new org id or auth key is blank or too long (`charge_it_pro_setup_error`, \"Charge It Pro Credentials are Invalid\"). YoPrint doesn't ask Gravity Payments, so a well-formed wrong key is saved."}],"group":"Team settings","notes":["Never put real credentials in source control or logs. The examples use placeholders.","Use Show team settings to read which gateways are on (`enable_*`) and the webhook URLs to register with providers."],"permission":"Needs the Manage Settings permission.","related":["v1_public_setting_show","v1_public_setting_payment_gateway_square_location_list","v2_public_sales_order_payment_gateway_execute","v2_public_sales_order_payment_gateway_refund"],"rules":["Turning a gateway on (`enable_*: true`) requires all of its credential fields in the same request.","The Stripe secret key must start with `sk_live_`, `sk_test_`, `rk_live_` or `rk_test_`, and the publishable key with `pk_live_` or `pk_test_`, followed by letters and digits only.","Each gateway is checked only when it is being turned on in this request. Charge It Pro is checked only when its org id or auth key also changes: each must be non-blank, the org id at most 100 characters and the key at most 4,096 (surrounding spaces ignored).","YoPrint checks the gateways in this order: Square, Stripe, Charge It Pro, PayPal, Authorize.Net. The first refusal ends the request and nothing is saved in YoPrint, but webhook changes already made at providers checked earlier in the same request stay."],"side_effects":["Calls the providers to check credentials and to create or update their webhooks (Stripe, PayPal, Square, Authorize.Net). No money moves.","Stores the credentials with the team.","When a credential field changes (a Stripe key, PayPal client id or secret, Square application id, access token, location id or signature key, Charge It Pro org id, auth key or device id, or an Authorize.Net key), YoPrint records a security event naming who changed which gateway and fields, never the values, and emails the team owner which gateways changed and who changed them. Re-sending the stored values, or only turning a gateway off, records and sends nothing."]}}},"/v1/api/store/{team_slug}/setting/payment_gateway/get_square_location_list":{"put":{"description":"Asks Square for the locations a Square access token can see, and returns each one's id, name and status. Use the ids for `square_location_id` and `square_webhook_locations` in Update payment gateway settings.\n\nNothing is saved. The token is used for this one call.","operationId":"v1_public_setting_payment_gateway_square_location_list","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"square_access_token":"YOUR_GATEWAY_SECRET"},"schema":{"properties":{"square_access_token":{"description":"A Square access token.","type":"string"}},"required":["square_access_token"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"id":"L8EXAMPLE01","name":"Main shop","status":"ACTIVE"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"id":{"description":"The Square location id.","example":"L8EXAMPLE01","type":"string"},"name":{"example":"Main shop","type":"string"},"status":{"description":"Square's location status, such as `ACTIVE`.","example":"ACTIVE","type":"string"}},"required":["id","name","status"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List Square locations","tags":["Payment gateways"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`square_access_token` is missing. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."},{"fix":"Check the access token in the Square Developer Dashboard, then try again.","status":500,"when":"Square refused the token (for example a wrong or expired one) or couldn't be reached. YoPrint answers with a generic server error, `{\"message\": \"Server Error\"}`, that doesn't say which."}],"group":"Team settings","permission":"Needs the Manage Settings permission. It uses PUT although it only reads.","related":["v1_public_setting_payment_gateway_update"],"side_effects":["Calls Square's Locations API."]}}},"/v1/api/store/{team_slug}/setting/payment_method":{"get":{"description":"Returns all the team's payment methods in one list, including deleted ones (`trashed: true`).\n\nPayment methods are the labels for payments you record yourself, such as Cash, Check or Bank Transfer. A manual payment on a sales order and a customer credit deposit name one with `payment_method_id`, and payment webhooks report it as `payment_method_name`. Card payments through a payment gateway are separate.","operationId":"v1_public_payment_method_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"created_at":"2026-11-03T15:00:00+00:00","default":false,"id":"XbLngLA87AC5t5","name":"Bank Transfer","trashed":false}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"default":{"description":"Whether it is the team's default payment method.","example":false,"type":"boolean"},"id":{"example":"XbLngLA87AC5t5","type":"string"},"name":{"example":"Bank Transfer","type":"string"},"trashed":{"description":"True for a deleted payment method.","example":false,"type":"boolean"}},"required":["id","name","default","created_at","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List payment methods","tags":["Payment methods"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_payment_method_store","v2_public_sales_order_manual_payment_store"]}},"post":{"description":"Creates a payment method and returns it. `default: true` makes it the team default.\n\nPayment methods are the labels for payments you record yourself, such as Cash, Check or Bank Transfer. A manual payment on a sales order and a customer credit deposit name one with `payment_method_id`, and payment webhooks report it as `payment_method_name`. Card payments through a payment gateway are separate.","operationId":"v1_public_payment_method_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"name":"Check"},"schema":{"properties":{"default":{"description":"`true` makes it the team's default payment method. `false` does nothing.","type":"boolean"},"name":{"type":"string"}},"required":["name"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-03T15:00:00+00:00","default":false,"id":"LOB1scuXDnIQbo","name":"Check","trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"default":{"description":"Whether it is the team's default payment method.","example":false,"type":"boolean"},"id":{"example":"XbLngLA87AC5t5","type":"string"},"name":{"example":"Bank Transfer","type":"string"},"trashed":{"description":"True for a deleted payment method.","example":false,"type":"boolean"}},"required":["id","name","default","created_at","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a payment method","tags":["Payment methods"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`name` is missing. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_payment_method_index"],"rules":["`name` is required. Names don't have to be unique."]}}},"/v1/api/store/{team_slug}/setting/payment_method/{hash_id}":{"delete":{"description":"Deletes a payment method. It stays in the list with `trashed: true` and can be restored. Payments recorded with it keep showing its name.","operationId":"v1_public_payment_method_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment method's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"XbLngLA87AC5t5","in":"path","name":"hash_id","required":true,"schema":{"example":"XbLngLA87AC5t5","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a payment method","tags":["Payment methods"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No payment method with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Make another one the default first, then delete this one.","status":500,"when":"The payment method is the team default. YoPrint refuses with HTTP 500 and `{\"status\": 500, \"success\": false, \"error\": {\"code\": \"delete_fail\", \"message\": null}}`; nothing is deleted. Don't retry it."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_payment_method_restore"],"rules":["The default payment method cannot be deleted."]}},"get":{"description":"Returns one payment method, deleted or not.","operationId":"v1_public_payment_method_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment method's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"XbLngLA87AC5t5","in":"path","name":"hash_id","required":true,"schema":{"example":"XbLngLA87AC5t5","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-03T15:00:00+00:00","default":false,"id":"XbLngLA87AC5t5","name":"Bank Transfer","trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"default":{"description":"Whether it is the team's default payment method.","example":false,"type":"boolean"},"id":{"example":"XbLngLA87AC5t5","type":"string"},"name":{"example":"Bank Transfer","type":"string"},"trashed":{"description":"True for a deleted payment method.","example":false,"type":"boolean"}},"required":["id","name","default","created_at","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show a payment method","tags":["Payment methods"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_payment_method_update_patch"]}},"patch":{"description":"Use PUT to change this record. PATCH saves the same fields but skips validation, so a bad value can be stored or fail with a server error.","operationId":"v1_public_payment_method_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment method's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"XbLngLA87AC5t5","in":"path","name":"hash_id","required":true,"schema":{"example":"XbLngLA87AC5t5","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"name":"Company check"},"schema":{"properties":{"default":{"description":"`true` makes it the team's default payment method. `false` does nothing.","type":"boolean"},"name":{"type":"string"}},"required":[],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-03T15:00:00+00:00","default":false,"id":"XbLngLA87AC5t5","name":"Company check","trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"default":{"description":"Whether it is the team's default payment method.","example":false,"type":"boolean"},"id":{"example":"XbLngLA87AC5t5","type":"string"},"name":{"example":"Bank Transfer","type":"string"},"trashed":{"description":"True for a deleted payment method.","example":false,"type":"boolean"}},"required":["id","name","default","created_at","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a payment method without checks","tags":["Payment methods"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No payment method with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_payment_method_show"]}},"put":{"description":"Renames a payment method or makes it the default, and returns it. Payments already recorded with it show the new name.","operationId":"v1_public_payment_method_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment method's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"XbLngLA87AC5t5","in":"path","name":"hash_id","required":true,"schema":{"example":"XbLngLA87AC5t5","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"name":"Company check"},"schema":{"properties":{"default":{"description":"`true` makes it the team's default payment method. `false` does nothing.","type":"boolean"},"name":{"type":"string"}},"required":[],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-03T15:00:00+00:00","default":false,"id":"XbLngLA87AC5t5","name":"Company check","trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"default":{"description":"Whether it is the team's default payment method.","example":false,"type":"boolean"},"id":{"example":"XbLngLA87AC5t5","type":"string"},"name":{"example":"Bank Transfer","type":"string"},"trashed":{"description":"True for a deleted payment method.","example":false,"type":"boolean"}},"required":["id","name","default","created_at","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a payment method","tags":["Payment methods"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No payment method with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`name` is not a string, or `default` is not a boolean. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_payment_method_show"]}}},"/v1/api/store/{team_slug}/setting/payment_method/{id}/restore":{"patch":{"description":"Brings back a deleted payment method.","operationId":"v1_public_payment_method_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment method's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"XbLngLA87AC5t5","in":"path","name":"id","required":true,"schema":{"example":"XbLngLA87AC5t5","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a payment method","tags":["Payment methods"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No payment method with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_payment_method_destroy"]}}},"/v1/api/store/{team_slug}/setting/payment_term":{"get":{"description":"Returns all the team's payment terms in one list, including deleted ones (`trashed: true`).\n\nA payment term says whether an order needs a deposit, how big, and when the deposit and full payment are due. A new sales order or quote takes the customer's default payment term, or else the team's default. YoPrint copies the term onto the order: the deposit requirement and percentage, a full payment due date `full_amount_due` days after the order is created and, when a deposit is required, a deposit due date `deposit_due` days after it. Changing or deleting a term later doesn't change existing orders.","operationId":"v1_public_payment_term_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"default":true,"deposit_due":30,"deposit_due_from":"issue_date","deposit_percent":20000,"enable_deposit":true,"full_amount_due":30,"full_amount_due_from":"issue_date","id":"H3J5exdciYshbk","name":"20/80 (20% deposit/upfront)","trashed":false}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"default":{"description":"Whether it is the team's default payment term.","example":true,"type":"boolean"},"deposit_due":{"description":"Days until the deposit is due. 0 when never set.","example":30,"type":"integer"},"deposit_due_from":{"enum":["issue_date",null],"example":"issue_date","type":["string","null"]},"deposit_percent":{"description":"The deposit percentage. A percentage ×1000: `8250` is 8.25% (`20000` is 20%). With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":20000,"type":["integer","null"]},"enable_deposit":{"description":"Whether a deposit is required before production.","example":true,"type":"boolean"},"full_amount_due":{"description":"Days until full payment is due.","example":30,"type":"integer"},"full_amount_due_from":{"description":"What the days count from: the issue date, or the customer due date.","enum":["issue_date","customer_due_date"],"example":"issue_date","type":"string"},"id":{"example":"H3J5exdciYshbk","type":"string"},"name":{"example":"20/80 (20% deposit/upfront)","type":"string"},"trashed":{"description":"True for a deleted payment term.","example":false,"type":"boolean"}},"required":["id","name","enable_deposit","deposit_percent","deposit_due","deposit_due_from","full_amount_due","full_amount_due_from","default","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List payment terms","tags":["Payment terms"],"x-yoprint-docs":{"group":"Team settings","notes":["Skip terms with `trashed: true` when you offer a choice. The `default` term is what new orders get when the customer has none."],"permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_payment_term_store","v1_public_payment_term_default","v2_public_order_create"]}},"post":{"description":"Creates a payment term and returns it.\n\nA payment term says whether an order needs a deposit, how big, and when the deposit and full payment are due. A new sales order or quote takes the customer's default payment term, or else the team's default. YoPrint copies the term onto the order: the deposit requirement and percentage, a full payment due date `full_amount_due` days after the order is created and, when a deposit is required, a deposit due date `deposit_due` days after it. Changing or deleting a term later doesn't change existing orders.\n\nThe first payment term of a team becomes its default. `default: true` doesn't switch the default when the team already has one; call Set the default payment term after creating it.","operationId":"v1_public_payment_term_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"deposit":{"summary":"50% deposit, balance in 30 days","value":{"deposit_due":0,"deposit_due_from":"issue_date","deposit_percent":50000,"enable_deposit":true,"full_amount_due":30,"full_amount_due_from":"issue_date","name":"50/50"}},"net30":{"summary":"Net 30, no deposit","value":{"enable_deposit":false,"full_amount_due":30,"full_amount_due_from":"issue_date","name":"Net 30"}}},"schema":{"properties":{"default":{"description":"`true` makes it the default only when the team has no default yet. To switch the default, call Set the default payment term.","type":"boolean"},"deposit_due":{"description":"Days until the deposit is due.","type":"integer"},"deposit_due_from":{"description":"Always `issue_date`.","enum":["issue_date"],"type":"string"},"deposit_percent":{"description":"Send a whole number as a percentage ×1000: `8250` is 8.25% (`20000` is 20%, `33333` is 33.333%).","minimum":0,"type":"integer"},"enable_deposit":{"description":"Require a deposit before production. When true, `deposit_percent`, `deposit_due` and `deposit_due_from` are required.","type":"boolean"},"full_amount_due":{"description":"Days until full payment is due.","type":"integer"},"full_amount_due_from":{"description":"What the days count from.","enum":["issue_date","customer_due_date"],"type":"string"},"name":{"type":"string"}},"required":["name","full_amount_due","full_amount_due_from"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"default":false,"deposit_due":0,"deposit_due_from":"issue_date","deposit_percent":50000,"enable_deposit":true,"full_amount_due":30,"full_amount_due_from":"issue_date","id":"H3J5exdciYshbk","name":"50/50","trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"description":"The new payment term, as built from your request: `enable_deposit`, `deposit_percent`, `deposit_due` and `deposit_due_from` are null when you left them out (YoPrint stores `false`, null, `0` and null). Read it back with Show a payment term for the stored values.","properties":{"default":{"description":"Whether it is the team's default payment term.","example":true,"type":"boolean"},"deposit_due":{"description":"Days until the deposit is due. 0 when never set.","example":30,"type":["integer","null"]},"deposit_due_from":{"enum":["issue_date",null],"example":"issue_date","type":["string","null"]},"deposit_percent":{"description":"The deposit percentage. A percentage ×1000: `8250` is 8.25% (`20000` is 20%). With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":20000,"type":["integer","null"]},"enable_deposit":{"description":"Whether a deposit is required before production.","example":true,"type":["boolean","null"]},"full_amount_due":{"description":"Days until full payment is due.","example":30,"type":"integer"},"full_amount_due_from":{"description":"What the days count from: the issue date, or the customer due date.","enum":["issue_date","customer_due_date"],"example":"issue_date","type":"string"},"id":{"example":"H3J5exdciYshbk","type":"string"},"name":{"example":"20/80 (20% deposit/upfront)","type":"string"},"trashed":{"description":"True for a deleted payment term.","example":false,"type":"boolean"}},"required":["id","name","enable_deposit","deposit_percent","deposit_due","deposit_due_from","full_amount_due","full_amount_due_from","default","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a payment term","tags":["Payment terms"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A required field is missing, a day count is not a number, a `*_from` value is not allowed, or `deposit_percent` is negative. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."},{"fix":"Send the percentage ×1000 as a whole number: `8250` is 8.25%, `33333` is 33.333%.","status":422,"when":"`deposit_percent` is not a whole number, or is too large (`error.code` `amount_out_of_range`)."}],"group":"Team settings","notes":["The answer echoes what you sent. Fields you left out are null in it, even though YoPrint stores defaults for them; send every field, or read the term back."],"permission":"Needs the Manage Settings permission.","related":["v1_public_payment_term_default"],"rules":["`name`, `full_amount_due` and `full_amount_due_from` are required.","With `enable_deposit: true`, `deposit_percent`, `deposit_due` and `deposit_due_from` are required.","`deposit_percent` is a whole number of 0 or more (a percentage ×1000: `8250` is 8.25%). YoPrint doesn't cap it at 100%.","`deposit_due_from` is `issue_date`; `full_amount_due_from` is `issue_date` or `customer_due_date`."]}}},"/v1/api/store/{team_slug}/setting/payment_term/{hash_id}":{"delete":{"description":"Deletes a payment term. It stays in the list with `trashed: true` and can be restored. Orders that used it keep their deposit and due dates.","operationId":"v1_public_payment_term_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment term's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"H3J5exdciYshbk","in":"path","name":"hash_id","required":true,"schema":{"example":"H3J5exdciYshbk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a payment term","tags":["Payment terms"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No payment term with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Make another one the default first, then delete this one.","status":500,"when":"The payment term is the team default. YoPrint refuses with HTTP 500 and `{\"status\": 500, \"success\": false, \"error\": {\"code\": \"delete_fail\", \"message\": null}}`; nothing is deleted. Don't retry it."}],"group":"Team settings","notes":["YoPrint doesn't check whether customers use it as their default payment term."],"permission":"Needs the Manage Settings permission.","related":["v1_public_payment_term_restore","v1_public_payment_term_default"],"rules":["The default payment term cannot be deleted."]}},"get":{"description":"Returns one payment term, deleted or not.","operationId":"v1_public_payment_term_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment term's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"H3J5exdciYshbk","in":"path","name":"hash_id","required":true,"schema":{"example":"H3J5exdciYshbk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"default":true,"deposit_due":30,"deposit_due_from":"issue_date","deposit_percent":20000,"enable_deposit":true,"full_amount_due":30,"full_amount_due_from":"issue_date","id":"H3J5exdciYshbk","name":"20/80 (20% deposit/upfront)","trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"default":{"description":"Whether it is the team's default payment term.","example":true,"type":"boolean"},"deposit_due":{"description":"Days until the deposit is due. 0 when never set.","example":30,"type":"integer"},"deposit_due_from":{"enum":["issue_date",null],"example":"issue_date","type":["string","null"]},"deposit_percent":{"description":"The deposit percentage. A percentage ×1000: `8250` is 8.25% (`20000` is 20%). With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":20000,"type":["integer","null"]},"enable_deposit":{"description":"Whether a deposit is required before production.","example":true,"type":"boolean"},"full_amount_due":{"description":"Days until full payment is due.","example":30,"type":"integer"},"full_amount_due_from":{"description":"What the days count from: the issue date, or the customer due date.","enum":["issue_date","customer_due_date"],"example":"issue_date","type":"string"},"id":{"example":"H3J5exdciYshbk","type":"string"},"name":{"example":"20/80 (20% deposit/upfront)","type":"string"},"trashed":{"description":"True for a deleted payment term.","example":false,"type":"boolean"}},"required":["id","name","enable_deposit","deposit_percent","deposit_due","deposit_due_from","full_amount_due","full_amount_due_from","default","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show a payment term","tags":["Payment terms"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_payment_term_update_patch"]}},"patch":{"description":"Use PUT to change a payment term. PATCH saves the same fields but skips validation, so a bad value can be stored or fail with a server error.","operationId":"v1_public_payment_term_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment term's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"H3J5exdciYshbk","in":"path","name":"hash_id","required":true,"schema":{"example":"H3J5exdciYshbk","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"days":{"summary":"Give 45 days","value":{"full_amount_due":45}}},"schema":{"properties":{"default":{"description":"`true` makes it the team's default payment term.","type":"boolean"},"deposit_due":{"description":"Days until the deposit is due.","type":"integer"},"deposit_due_from":{"description":"Always `issue_date`.","enum":["issue_date"],"type":"string"},"deposit_percent":{"description":"Send a whole number as a percentage ×1000: `8250` is 8.25% (`20000` is 20%, `33333` is 33.333%).","minimum":0,"type":"integer"},"enable_deposit":{"description":"Require a deposit before production. When true, `deposit_percent`, `deposit_due` and `deposit_due_from` are required.","type":"boolean"},"full_amount_due":{"description":"Days until full payment is due.","type":"integer"},"full_amount_due_from":{"description":"What the days count from.","enum":["issue_date","customer_due_date"],"type":"string"},"name":{"type":"string"}},"required":[],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"default":true,"deposit_due":30,"deposit_due_from":"issue_date","deposit_percent":20000,"enable_deposit":true,"full_amount_due":45,"full_amount_due_from":"issue_date","id":"H3J5exdciYshbk","name":"20/80 (20% deposit/upfront)","trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"default":{"description":"Whether it is the team's default payment term.","example":true,"type":"boolean"},"deposit_due":{"description":"Days until the deposit is due. 0 when never set.","example":30,"type":"integer"},"deposit_due_from":{"enum":["issue_date",null],"example":"issue_date","type":["string","null"]},"deposit_percent":{"description":"The deposit percentage. A percentage ×1000: `8250` is 8.25% (`20000` is 20%). With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":20000,"type":["integer","null"]},"enable_deposit":{"description":"Whether a deposit is required before production.","example":true,"type":"boolean"},"full_amount_due":{"description":"Days until full payment is due.","example":30,"type":"integer"},"full_amount_due_from":{"description":"What the days count from: the issue date, or the customer due date.","enum":["issue_date","customer_due_date"],"example":"issue_date","type":"string"},"id":{"example":"H3J5exdciYshbk","type":"string"},"name":{"example":"20/80 (20% deposit/upfront)","type":"string"},"trashed":{"description":"True for a deleted payment term.","example":false,"type":"boolean"}},"required":["id","name","enable_deposit","deposit_percent","deposit_due","deposit_due_from","full_amount_due","full_amount_due_from","default","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a payment term without checks","tags":["Payment terms"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No payment term with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Send the percentage ×1000 as a whole number: `8250` is 8.25%, `33333` is 33.333%.","status":422,"when":"`deposit_percent` is not a whole number, or is too large (`error.code` `amount_out_of_range`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_payment_term_show"],"rules":["With `enable_deposit: true`, `deposit_percent`, `deposit_due` and `deposit_due_from` are required.","`deposit_percent` is a whole number of 0 or more (a percentage ×1000: `8250` is 8.25%). YoPrint doesn't cap it at 100%.","`deposit_due_from` is `issue_date`; `full_amount_due_from` is `issue_date` or `customer_due_date`."],"side_effects":["With `default: true`, it becomes the default for new orders of customers without their own payment term."]}},"put":{"description":"Changes a payment term and returns it. Send only the fields to change. `default: true` makes it the team default.\n\nOrders that already use the term keep the values they copied.","operationId":"v1_public_payment_term_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment term's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"H3J5exdciYshbk","in":"path","name":"hash_id","required":true,"schema":{"example":"H3J5exdciYshbk","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"days":{"summary":"Give 45 days","value":{"full_amount_due":45}}},"schema":{"properties":{"default":{"description":"`true` makes it the team's default payment term.","type":"boolean"},"deposit_due":{"description":"Days until the deposit is due.","type":"integer"},"deposit_due_from":{"description":"Always `issue_date`.","enum":["issue_date"],"type":"string"},"deposit_percent":{"description":"Send a whole number as a percentage ×1000: `8250` is 8.25% (`20000` is 20%, `33333` is 33.333%).","minimum":0,"type":"integer"},"enable_deposit":{"description":"Require a deposit before production. When true, `deposit_percent`, `deposit_due` and `deposit_due_from` are required.","type":"boolean"},"full_amount_due":{"description":"Days until full payment is due.","type":"integer"},"full_amount_due_from":{"description":"What the days count from.","enum":["issue_date","customer_due_date"],"type":"string"},"name":{"type":"string"}},"required":[],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"default":true,"deposit_due":30,"deposit_due_from":"issue_date","deposit_percent":20000,"enable_deposit":true,"full_amount_due":45,"full_amount_due_from":"issue_date","id":"H3J5exdciYshbk","name":"20/80 (20% deposit/upfront)","trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"default":{"description":"Whether it is the team's default payment term.","example":true,"type":"boolean"},"deposit_due":{"description":"Days until the deposit is due. 0 when never set.","example":30,"type":"integer"},"deposit_due_from":{"enum":["issue_date",null],"example":"issue_date","type":["string","null"]},"deposit_percent":{"description":"The deposit percentage. A percentage ×1000: `8250` is 8.25% (`20000` is 20%). With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":20000,"type":["integer","null"]},"enable_deposit":{"description":"Whether a deposit is required before production.","example":true,"type":"boolean"},"full_amount_due":{"description":"Days until full payment is due.","example":30,"type":"integer"},"full_amount_due_from":{"description":"What the days count from: the issue date, or the customer due date.","enum":["issue_date","customer_due_date"],"example":"issue_date","type":"string"},"id":{"example":"H3J5exdciYshbk","type":"string"},"name":{"example":"20/80 (20% deposit/upfront)","type":"string"},"trashed":{"description":"True for a deleted payment term.","example":false,"type":"boolean"}},"required":["id","name","enable_deposit","deposit_percent","deposit_due","deposit_due_from","full_amount_due","full_amount_due_from","default","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a payment term","tags":["Payment terms"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No payment term with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A value has the wrong type, or `deposit_percent` is negative. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."},{"fix":"Send the percentage ×1000 as a whole number: `8250` is 8.25%, `33333` is 33.333%.","status":422,"when":"`deposit_percent` is not a whole number, or is too large (`error.code` `amount_out_of_range`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_payment_term_show"],"rules":["With `enable_deposit: true`, `deposit_percent`, `deposit_due` and `deposit_due_from` are required.","`deposit_percent` is a whole number of 0 or more (a percentage ×1000: `8250` is 8.25%). YoPrint doesn't cap it at 100%.","`deposit_due_from` is `issue_date`; `full_amount_due_from` is `issue_date` or `customer_due_date`."],"side_effects":["With `default: true`, it becomes the default for new orders of customers without their own payment term."]}}},"/v1/api/store/{team_slug}/setting/payment_term/{id}/default":{"patch":{"description":"Makes this payment term the team default and returns it. The previous default stops being the default. New sales orders and quotes for customers without their own payment term use it.","operationId":"v1_public_payment_term_default","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment term's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"H3J5exdciYshbk","in":"path","name":"id","required":true,"schema":{"example":"H3J5exdciYshbk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"default":true,"deposit_due":30,"deposit_due_from":"issue_date","deposit_percent":20000,"enable_deposit":true,"full_amount_due":30,"full_amount_due_from":"issue_date","id":"H3J5exdciYshbk","name":"20/80 (20% deposit/upfront)","trashed":false},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"default":{"description":"Whether it is the team's default payment term.","example":true,"type":"boolean"},"deposit_due":{"description":"Days until the deposit is due. 0 when never set.","example":30,"type":"integer"},"deposit_due_from":{"enum":["issue_date",null],"example":"issue_date","type":["string","null"]},"deposit_percent":{"description":"The deposit percentage. A percentage ×1000: `8250` is 8.25% (`20000` is 20%). With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":20000,"type":["integer","null"]},"enable_deposit":{"description":"Whether a deposit is required before production.","example":true,"type":"boolean"},"full_amount_due":{"description":"Days until full payment is due.","example":30,"type":"integer"},"full_amount_due_from":{"description":"What the days count from: the issue date, or the customer due date.","enum":["issue_date","customer_due_date"],"example":"issue_date","type":"string"},"id":{"example":"H3J5exdciYshbk","type":"string"},"name":{"example":"20/80 (20% deposit/upfront)","type":"string"},"trashed":{"description":"True for a deleted payment term.","example":false,"type":"boolean"}},"required":["id","name","enable_deposit","deposit_percent","deposit_due","deposit_due_from","full_amount_due","full_amount_due_from","default","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set the default payment term","tags":["Payment terms"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No payment term with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_payment_term_index"],"rules":["YoPrint doesn't check whether the term is deleted. Restore a deleted term before you make it the default."],"side_effects":["Tells the team's open web app sessions that the default changed."]}}},"/v1/api/store/{team_slug}/setting/payment_term/{id}/restore":{"patch":{"description":"Brings back a deleted payment term.","operationId":"v1_public_payment_term_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment term's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"H3J5exdciYshbk","in":"path","name":"id","required":true,"schema":{"example":"H3J5exdciYshbk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a payment term","tags":["Payment terms"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No payment term with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_payment_term_destroy"]}}},"/v1/api/store/{team_slug}/setting/photo":{"delete":{"description":"Removes the team logo from YoPrint and the customer portal. The company details then read `logo_url: null`. Calling it when there is no logo also succeeds. The response has no data.","operationId":"v1_public_setting_photo_delete","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove the team logo","tags":["Company settings"],"x-yoprint-docs":{"errors":[{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_setting_photo_update","v1_public_setting_detail_show"]}},"post":{"description":"Uploads a new team logo as `multipart/form-data`, in the field `media`. It replaces the logo shown in the company details (`logo_url`) and in the customer portal; PDFs show it in the header when `pdf_header_use_logo` is on.\n\nThe file is checked first, so a refused upload leaves the current logo in place. Once the new logo is saved, the old one is removed.\n\nThe response has no data. Read the company details for the new `logo_url`.","operationId":"v1_public_setting_photo_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"encoding":{"media":{"contentType":"image/png, image/jpeg"}},"schema":{"properties":{"media":{"description":"A JPEG or PNG image, at most 4096 KiB (4 MB). YoPrint reads the type from the file's content, not its name.","format":"binary","type":"string"}},"required":["media"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Upload the team logo","tags":["Company settings"],"x-yoprint-docs":{"errors":[{"fix":"Send one JPEG or PNG file in the `media` field.","status":422,"when":"`media` is missing, is not a JPEG or PNG image, or is larger than 4096 KiB (`validation_failed`; `error.fields.media` says which). The current logo stays."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_setting_photo_delete","v1_public_setting_detail_show"]}}},"/v1/api/store/{team_slug}/setting/pipeline":{"get":{"description":"Returns all the team's task presets in one list, including deleted ones (`trashed: true`), each with its statuses.\n\nTask presets (called pipelines in the API) are named sets of statuses that a task moves through, for example Pending, Started, Completed. The tasks on a job each follow a preset, and services can be linked to presets. Every answer includes the preset's `statuses`. Change them with the status operations: add, rename, reorder or remove them with Save a set of status changes.","operationId":"v1_public_pipeline_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color":"#1976d2","enable":true,"id":"SyqthLPEGyJQGY","label":"Screen printing","statuses":[{"color":"#1976d2","customer_label":"Pending","id":"ta5ib44WIIqi1X","label":"Pending","pipeline_id":"SyqthLPEGyJQGY","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#4caf50","customer_label":"In Progress","id":"v4teCIco0ZHebU","label":"Started","pipeline_id":"SyqthLPEGyJQGY","position":1,"role":"pipeline","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"V4RV92MCWxFIjQ","label":"Completed","pipeline_id":"SyqthLPEGyJQGY","position":2,"role":"pipeline","trashed":false,"type":"end"}],"trashed":false,"version":1}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"color":{"description":"A hex color.","example":"#1976d2","type":"string"},"enable":{"example":true,"type":"boolean"},"id":{"example":"SyqthLPEGyJQGY","type":"string"},"label":{"example":"Screen printing","type":"string"},"statuses":{"description":"The preset's statuses, removed ones included (`trashed: true`). They are not sorted: order them by `position`.","example":[{"color":"#1976d2","customer_label":"Pending","id":"ta5ib44WIIqi1X","label":"Pending","pipeline_id":"SyqthLPEGyJQGY","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#4caf50","customer_label":"In Progress","id":"v4teCIco0ZHebU","label":"Started","pipeline_id":"SyqthLPEGyJQGY","position":1,"role":"pipeline","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"V4RV92MCWxFIjQ","label":"Completed","pipeline_id":"SyqthLPEGyJQGY","position":2,"role":"pipeline","trashed":false,"type":"end"}],"items":{"properties":{"color":{"example":"#1976d2","type":"string"},"customer_label":{"description":"The name customers see. When none was set: `Pending`, `In Progress` or `Completed`, by `type`.","example":"Pending","type":"string"},"id":{"description":"The status id, as task status changes take it.","example":"ta5ib44WIIqi1X","type":"string"},"label":{"description":"The status name people see.","example":"Pending","type":"string"},"pipeline_id":{"description":"The task preset's id.","example":"SyqthLPEGyJQGY","type":"string"},"position":{"description":"The order of the status in the preset, from 0.","example":0,"type":"integer"},"role":{"description":"Always `pipeline` for task statuses.","example":"pipeline","type":"string"},"trashed":{"description":"True for a removed status. Removed statuses stay in the list.","example":false,"type":"boolean"},"type":{"description":"`start`: where a new task begins. `in_progress`: working. `end`: the task is done.","enum":["start","in_progress","end"],"example":"start","type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed","pipeline_id"],"type":"object"},"type":"array"},"trashed":{"description":"True for a deleted task preset.","example":false,"type":"boolean"},"version":{"example":1,"type":"integer"}},"required":["id","label","color","version","enable","trashed","statuses"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List task presets","tags":["Task presets"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_status_list_pipeline","v1_public_pipeline_store"]}},"post":{"description":"Creates a task preset with three statuses and returns it, statuses included: Pending (the start status), Started (in progress) and Completed (the end status). Change them with the status operations.\n\nA new preset is off (`enable: false`) unless you send `enable: true`.\n\nTask presets (called pipelines in the API) are named sets of statuses that a task moves through, for example Pending, Started, Completed. The tasks on a job each follow a preset, and services can be linked to presets. Every answer includes the preset's `statuses`. Change them with the status operations: add, rename, reorder or remove them with Save a set of status changes.","operationId":"v1_public_pipeline_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"color":"#1976d2","enable":true,"label":"Screen printing"},"schema":{"properties":{"color":{"description":"A hex color: `#` and 3 or 6 hex digits, such as `#1976d2`. Defaults to `#FFFFFF`.","type":"string"},"enable":{"description":"Defaults to false: send `true` to turn it on.","type":"boolean"},"label":{"description":"Unique among the team's task presets that aren't deleted.","type":"string"}},"required":["label"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"color":"#1976d2","enable":true,"id":"SyqthLPEGyJQGY","label":"Screen printing","statuses":[{"color":"#1976d2","customer_label":"Pending","id":"ta5ib44WIIqi1X","label":"Pending","pipeline_id":"SyqthLPEGyJQGY","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#4caf50","customer_label":"In Progress","id":"v4teCIco0ZHebU","label":"Started","pipeline_id":"SyqthLPEGyJQGY","position":1,"role":"pipeline","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"V4RV92MCWxFIjQ","label":"Completed","pipeline_id":"SyqthLPEGyJQGY","position":2,"role":"pipeline","trashed":false,"type":"end"}],"trashed":false,"version":1},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"color":{"description":"A hex color.","example":"#1976d2","type":"string"},"enable":{"example":true,"type":"boolean"},"id":{"example":"SyqthLPEGyJQGY","type":"string"},"label":{"example":"Screen printing","type":"string"},"statuses":{"description":"The preset's statuses, removed ones included (`trashed: true`). They are not sorted: order them by `position`.","example":[{"color":"#1976d2","customer_label":"Pending","id":"ta5ib44WIIqi1X","label":"Pending","pipeline_id":"SyqthLPEGyJQGY","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#4caf50","customer_label":"In Progress","id":"v4teCIco0ZHebU","label":"Started","pipeline_id":"SyqthLPEGyJQGY","position":1,"role":"pipeline","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"V4RV92MCWxFIjQ","label":"Completed","pipeline_id":"SyqthLPEGyJQGY","position":2,"role":"pipeline","trashed":false,"type":"end"}],"items":{"properties":{"color":{"example":"#1976d2","type":"string"},"customer_label":{"description":"The name customers see. When none was set: `Pending`, `In Progress` or `Completed`, by `type`.","example":"Pending","type":"string"},"id":{"description":"The status id, as task status changes take it.","example":"ta5ib44WIIqi1X","type":"string"},"label":{"description":"The status name people see.","example":"Pending","type":"string"},"pipeline_id":{"description":"The task preset's id.","example":"SyqthLPEGyJQGY","type":"string"},"position":{"description":"The order of the status in the preset, from 0.","example":0,"type":"integer"},"role":{"description":"Always `pipeline` for task statuses.","example":"pipeline","type":"string"},"trashed":{"description":"True for a removed status. Removed statuses stay in the list.","example":false,"type":"boolean"},"type":{"description":"`start`: where a new task begins. `in_progress`: working. `end`: the task is done.","enum":["start","in_progress","end"],"example":"start","type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed","pipeline_id"],"type":"object"},"type":"array"},"trashed":{"description":"True for a deleted task preset.","example":false,"type":"boolean"},"version":{"example":1,"type":"integer"}},"required":["id","label","color","version","enable","trashed","statuses"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a task preset","tags":["Task presets"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`label` is missing or already used, or `color` is not a hex color. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_status_list_pipeline","v1_public_status_sync"],"rules":["`label` is required and must not match another task preset that isn't deleted.","`color`, when sent, is a hex color."],"side_effects":["Creates the statuses Pending, Started and Completed for the preset."]}}},"/v1/api/store/{team_slug}/setting/pipeline/{hash_id}":{"delete":{"description":"Deletes a task preset. It stays in the list with `trashed: true` and can be restored. YoPrint doesn't check whether tasks or services use it.","operationId":"v1_public_pipeline_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The task preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"SyqthLPEGyJQGY","in":"path","name":"hash_id","required":true,"schema":{"example":"SyqthLPEGyJQGY","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a task preset","tags":["Task presets"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No task preset with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","notes":["Its label becomes free for a new task preset."],"permission":"Needs the Manage Settings permission.","related":["v1_public_pipeline_restore"]}},"get":{"description":"Returns one task preset, deleted or not, with its statuses.","operationId":"v1_public_pipeline_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The task preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"SyqthLPEGyJQGY","in":"path","name":"hash_id","required":true,"schema":{"example":"SyqthLPEGyJQGY","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"color":"#1976d2","enable":true,"id":"SyqthLPEGyJQGY","label":"Screen printing","statuses":[{"color":"#1976d2","customer_label":"Pending","id":"ta5ib44WIIqi1X","label":"Pending","pipeline_id":"SyqthLPEGyJQGY","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#4caf50","customer_label":"In Progress","id":"v4teCIco0ZHebU","label":"Started","pipeline_id":"SyqthLPEGyJQGY","position":1,"role":"pipeline","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"V4RV92MCWxFIjQ","label":"Completed","pipeline_id":"SyqthLPEGyJQGY","position":2,"role":"pipeline","trashed":false,"type":"end"}],"trashed":false,"version":1},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"color":{"description":"A hex color.","example":"#1976d2","type":"string"},"enable":{"example":true,"type":"boolean"},"id":{"example":"SyqthLPEGyJQGY","type":"string"},"label":{"example":"Screen printing","type":"string"},"statuses":{"description":"The preset's statuses, removed ones included (`trashed: true`). They are not sorted: order them by `position`.","example":[{"color":"#1976d2","customer_label":"Pending","id":"ta5ib44WIIqi1X","label":"Pending","pipeline_id":"SyqthLPEGyJQGY","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#4caf50","customer_label":"In Progress","id":"v4teCIco0ZHebU","label":"Started","pipeline_id":"SyqthLPEGyJQGY","position":1,"role":"pipeline","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"V4RV92MCWxFIjQ","label":"Completed","pipeline_id":"SyqthLPEGyJQGY","position":2,"role":"pipeline","trashed":false,"type":"end"}],"items":{"properties":{"color":{"example":"#1976d2","type":"string"},"customer_label":{"description":"The name customers see. When none was set: `Pending`, `In Progress` or `Completed`, by `type`.","example":"Pending","type":"string"},"id":{"description":"The status id, as task status changes take it.","example":"ta5ib44WIIqi1X","type":"string"},"label":{"description":"The status name people see.","example":"Pending","type":"string"},"pipeline_id":{"description":"The task preset's id.","example":"SyqthLPEGyJQGY","type":"string"},"position":{"description":"The order of the status in the preset, from 0.","example":0,"type":"integer"},"role":{"description":"Always `pipeline` for task statuses.","example":"pipeline","type":"string"},"trashed":{"description":"True for a removed status. Removed statuses stay in the list.","example":false,"type":"boolean"},"type":{"description":"`start`: where a new task begins. `in_progress`: working. `end`: the task is done.","enum":["start","in_progress","end"],"example":"start","type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed","pipeline_id"],"type":"object"},"type":"array"},"trashed":{"description":"True for a deleted task preset.","example":false,"type":"boolean"},"version":{"example":1,"type":"integer"}},"required":["id","label","color","version","enable","trashed","statuses"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show a task preset","tags":["Task presets"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_status_list_pipeline"]}},"patch":{"description":"Use PUT to change a task preset. PATCH saves the same fields but skips validation, including the unique label and hex color checks.","operationId":"v1_public_pipeline_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The task preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"SyqthLPEGyJQGY","in":"path","name":"hash_id","required":true,"schema":{"example":"SyqthLPEGyJQGY","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"label":"Screen printing (2 colors)"},"schema":{"properties":{"color":{"description":"A hex color: `#` and 3 or 6 hex digits, such as `#1976d2`.","type":"string"},"enable":{"description":"Turns it on or off.","type":"boolean"},"label":{"description":"Unique among the team's task presets that aren't deleted.","type":"string"}},"required":[],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"color":"#1976d2","enable":true,"id":"SyqthLPEGyJQGY","label":"Screen printing (2 colors)","statuses":[{"color":"#1976d2","customer_label":"Pending","id":"ta5ib44WIIqi1X","label":"Pending","pipeline_id":"SyqthLPEGyJQGY","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#4caf50","customer_label":"In Progress","id":"v4teCIco0ZHebU","label":"Started","pipeline_id":"SyqthLPEGyJQGY","position":1,"role":"pipeline","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"V4RV92MCWxFIjQ","label":"Completed","pipeline_id":"SyqthLPEGyJQGY","position":2,"role":"pipeline","trashed":false,"type":"end"}],"trashed":false,"version":1},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"color":{"description":"A hex color.","example":"#1976d2","type":"string"},"enable":{"example":true,"type":"boolean"},"id":{"example":"SyqthLPEGyJQGY","type":"string"},"label":{"example":"Screen printing","type":"string"},"statuses":{"description":"The preset's statuses, removed ones included (`trashed: true`). They are not sorted: order them by `position`.","example":[{"color":"#1976d2","customer_label":"Pending","id":"ta5ib44WIIqi1X","label":"Pending","pipeline_id":"SyqthLPEGyJQGY","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#4caf50","customer_label":"In Progress","id":"v4teCIco0ZHebU","label":"Started","pipeline_id":"SyqthLPEGyJQGY","position":1,"role":"pipeline","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"V4RV92MCWxFIjQ","label":"Completed","pipeline_id":"SyqthLPEGyJQGY","position":2,"role":"pipeline","trashed":false,"type":"end"}],"items":{"properties":{"color":{"example":"#1976d2","type":"string"},"customer_label":{"description":"The name customers see. When none was set: `Pending`, `In Progress` or `Completed`, by `type`.","example":"Pending","type":"string"},"id":{"description":"The status id, as task status changes take it.","example":"ta5ib44WIIqi1X","type":"string"},"label":{"description":"The status name people see.","example":"Pending","type":"string"},"pipeline_id":{"description":"The task preset's id.","example":"SyqthLPEGyJQGY","type":"string"},"position":{"description":"The order of the status in the preset, from 0.","example":0,"type":"integer"},"role":{"description":"Always `pipeline` for task statuses.","example":"pipeline","type":"string"},"trashed":{"description":"True for a removed status. Removed statuses stay in the list.","example":false,"type":"boolean"},"type":{"description":"`start`: where a new task begins. `in_progress`: working. `end`: the task is done.","enum":["start","in_progress","end"],"example":"start","type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed","pipeline_id"],"type":"object"},"type":"array"},"trashed":{"description":"True for a deleted task preset.","example":false,"type":"boolean"},"version":{"example":1,"type":"integer"}},"required":["id","label","color","version","enable","trashed","statuses"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a task preset without checks","tags":["Task presets"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No task preset with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_pipeline_show"],"rules":["`label`, when sent, must not match another task preset that isn't deleted.","`color`, when sent, is a hex color."]}},"put":{"description":"Changes a task preset's label, color or on/off state, and returns it with its statuses. Statuses are changed with the status operations.","operationId":"v1_public_pipeline_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The task preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"SyqthLPEGyJQGY","in":"path","name":"hash_id","required":true,"schema":{"example":"SyqthLPEGyJQGY","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"label":"Screen printing (2 colors)"},"schema":{"properties":{"color":{"description":"A hex color: `#` and 3 or 6 hex digits, such as `#1976d2`.","type":"string"},"enable":{"description":"Turns it on or off.","type":"boolean"},"label":{"description":"Unique among the team's task presets that aren't deleted.","type":"string"}},"required":[],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"color":"#1976d2","enable":true,"id":"SyqthLPEGyJQGY","label":"Screen printing (2 colors)","statuses":[{"color":"#1976d2","customer_label":"Pending","id":"ta5ib44WIIqi1X","label":"Pending","pipeline_id":"SyqthLPEGyJQGY","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#4caf50","customer_label":"In Progress","id":"v4teCIco0ZHebU","label":"Started","pipeline_id":"SyqthLPEGyJQGY","position":1,"role":"pipeline","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"V4RV92MCWxFIjQ","label":"Completed","pipeline_id":"SyqthLPEGyJQGY","position":2,"role":"pipeline","trashed":false,"type":"end"}],"trashed":false,"version":1},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"color":{"description":"A hex color.","example":"#1976d2","type":"string"},"enable":{"example":true,"type":"boolean"},"id":{"example":"SyqthLPEGyJQGY","type":"string"},"label":{"example":"Screen printing","type":"string"},"statuses":{"description":"The preset's statuses, removed ones included (`trashed: true`). They are not sorted: order them by `position`.","example":[{"color":"#1976d2","customer_label":"Pending","id":"ta5ib44WIIqi1X","label":"Pending","pipeline_id":"SyqthLPEGyJQGY","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#4caf50","customer_label":"In Progress","id":"v4teCIco0ZHebU","label":"Started","pipeline_id":"SyqthLPEGyJQGY","position":1,"role":"pipeline","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"V4RV92MCWxFIjQ","label":"Completed","pipeline_id":"SyqthLPEGyJQGY","position":2,"role":"pipeline","trashed":false,"type":"end"}],"items":{"properties":{"color":{"example":"#1976d2","type":"string"},"customer_label":{"description":"The name customers see. When none was set: `Pending`, `In Progress` or `Completed`, by `type`.","example":"Pending","type":"string"},"id":{"description":"The status id, as task status changes take it.","example":"ta5ib44WIIqi1X","type":"string"},"label":{"description":"The status name people see.","example":"Pending","type":"string"},"pipeline_id":{"description":"The task preset's id.","example":"SyqthLPEGyJQGY","type":"string"},"position":{"description":"The order of the status in the preset, from 0.","example":0,"type":"integer"},"role":{"description":"Always `pipeline` for task statuses.","example":"pipeline","type":"string"},"trashed":{"description":"True for a removed status. Removed statuses stay in the list.","example":false,"type":"boolean"},"type":{"description":"`start`: where a new task begins. `in_progress`: working. `end`: the task is done.","enum":["start","in_progress","end"],"example":"start","type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed","pipeline_id"],"type":"object"},"type":"array"},"trashed":{"description":"True for a deleted task preset.","example":false,"type":"boolean"},"version":{"example":1,"type":"integer"}},"required":["id","label","color","version","enable","trashed","statuses"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a task preset","tags":["Task presets"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No task preset with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`label` is already used, or `color` is not a hex color. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_pipeline_show"],"rules":["`label`, when sent, must not match another task preset that isn't deleted.","`color`, when sent, is a hex color."]}}},"/v1/api/store/{team_slug}/setting/pipeline/{id}/restore":{"patch":{"description":"Brings back a deleted task preset. Restoring one that isn't deleted does nothing. YoPrint doesn't check whether another preset took its label in the meantime.","operationId":"v1_public_pipeline_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The task preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"SyqthLPEGyJQGY","in":"path","name":"id","required":true,"schema":{"example":"SyqthLPEGyJQGY","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a task preset","tags":["Task presets"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No task preset with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_pipeline_destroy"]}}},"/v1/api/store/{team_slug}/setting/running_number":{"get":{"description":"Returns the number the next sales order, purchase order and invoice will get.\n\nNew sales orders are numbered `SO` plus the number, padded with zeros to at least 4 digits (`SO0042`, `SO1043`); from 5 digits up, one extra zero is added (`SO010000`). Purchase orders use `PO` the same way. Invoices use the plain number.","operationId":"v1_public_setting_running_number_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"order_invoice":877,"purchase_order":218,"sales_order":1043},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"order_invoice":{"description":"The number the next invoice gets.","example":877,"type":"integer"},"purchase_order":{"description":"The number the next purchase order gets.","example":218,"type":"integer"},"sales_order":{"description":"The number the next sales order gets.","example":1043,"type":"integer"}},"required":["sales_order","purchase_order","order_invoice"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show the next document numbers","tags":["Running numbers"],"x-yoprint-docs":{"group":"Team settings","notes":["The numbers are a preview: another user creating a document first takes the number."],"permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_setting_running_number_update"]}},"put":{"description":"Sets the number the next sales order, purchase order or invoice gets, and returns all three next numbers. Send only the counters you want to change.\n\nOnly documents created afterwards use the new numbers; existing documents keep theirs. New sales orders are numbered `SO` plus the number, padded with zeros to at least 4 digits (`SO0042`, `SO1043`); from 5 digits up, one extra zero is added (`SO010000`). Purchase orders use `PO` the same way. Invoices use the plain number.","operationId":"v1_public_setting_running_number_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"sales_order":2000},"schema":{"properties":{"order_invoice":{"description":"The next invoice number.","minimum":1,"type":"integer"},"purchase_order":{"description":"The next purchase order number.","minimum":1,"type":"integer"},"sales_order":{"description":"The next sales order number.","minimum":1,"type":"integer"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"order_invoice":877,"purchase_order":218,"sales_order":2000},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"order_invoice":{"description":"The number the next invoice gets.","example":877,"type":"integer"},"purchase_order":{"description":"The number the next purchase order gets.","example":218,"type":"integer"},"sales_order":{"description":"The number the next sales order gets.","example":1043,"type":"integer"}},"required":["sales_order","purchase_order","order_invoice"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set the next document numbers","tags":["Running numbers"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A value is not a number or is below 1. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_setting_running_number_show"],"rules":["Each value must be a number of at least 1. Send whole numbers: a fraction is rounded, so the next number may not be the one you asked for.","YoPrint doesn't check the number against existing documents. Setting it below a number already used makes new documents repeat existing numbers."],"side_effects":["Tells the team's open web app sessions about the new numbers."]}}},"/v1/api/store/{team_slug}/setting/shipment_box":{"get":{"description":"Returns all the team's shipping boxes in one list.\n\nShipping boxes are saved box sizes. The web app offers them when you buy a shipping label with GoShippo, to fill in a parcel's size. Nothing links to a box by id, so changing or deleting a box doesn't change existing shipments or packages.","operationId":"v1_public_shipment_box_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"height":12000,"id":"KkXRzp66r5WrEH","is_default":true,"is_insured":false,"length":16000,"length_unit":"IN","name":"Medium box","width":12000}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"height":{"description":"The height, in thousandths of the unit (the size ×1000): `12000` is 12.","example":12000,"type":"integer"},"id":{"example":"KkXRzp66r5WrEH","type":"string"},"is_default":{"description":"Whether it is the team's default box.","example":true,"type":"boolean"},"is_insured":{"description":"The box's Insured option.","example":false,"type":"boolean"},"length":{"example":16000,"type":"integer"},"length_unit":{"enum":["CM","IN"],"example":"IN","type":"string"},"name":{"example":"Medium box","type":"string"},"width":{"example":12000,"type":"integer"}},"required":["id","name","height","width","length","length_unit","is_default","is_insured"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List shipping boxes","tags":["Shipping boxes"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_shipment_box_store"]}},"post":{"description":"Creates a shipping box and returns it. The team's first box becomes the default; `is_default: true` makes a later one the default.\n\nShipping boxes are saved box sizes. The web app offers them when you buy a shipping label with GoShippo, to fill in a parcel's size. Nothing links to a box by id, so changing or deleting a box doesn't change existing shipments or packages.","operationId":"v1_public_shipment_box_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"height":12000,"length":16000,"length_unit":"IN","name":"Medium box","width":12000},"schema":{"properties":{"height":{"description":"The height, in thousandths of the unit (the size ×1000): `12500` is 12.5.","type":"integer"},"is_default":{"description":"`true` makes it the team's default box. `false` does nothing.","type":"boolean"},"is_insured":{"type":"boolean"},"length":{"description":"The length, in thousandths of the unit (the size ×1000): `12500` is 12.5.","type":"integer"},"length_unit":{"enum":["CM","IN"],"type":"string"},"name":{"type":"string"},"width":{"description":"The width, in thousandths of the unit (the size ×1000): `12500` is 12.5.","type":"integer"}},"required":["name","height","width","length","length_unit"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"height":12000,"id":"KkXRzp66r5WrEH","is_default":true,"is_insured":false,"length":16000,"length_unit":"IN","name":"Medium box","width":12000},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"height":{"description":"The height, in thousandths of the unit (the size ×1000): `12000` is 12.","example":12000,"type":"integer"},"id":{"example":"KkXRzp66r5WrEH","type":"string"},"is_default":{"description":"Whether it is the team's default box.","example":true,"type":"boolean"},"is_insured":{"description":"The box's Insured option.","example":false,"type":"boolean"},"length":{"example":16000,"type":"integer"},"length_unit":{"enum":["CM","IN"],"example":"IN","type":"string"},"name":{"example":"Medium box","type":"string"},"width":{"example":12000,"type":"integer"}},"required":["id","name","height","width","length","length_unit","is_default","is_insured"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a shipping box","tags":["Shipping boxes"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A required field is missing, a size is not a whole number, or `length_unit` is not `CM` or `IN`. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_shipment_box_index"],"rules":["`name`, `height`, `width`, `length` and `length_unit` are required.","Sizes are whole numbers in thousandths of the unit.","`length_unit` is `CM` or `IN`."]}}},"/v1/api/store/{team_slug}/setting/shipment_box/{hash_id}":{"delete":{"description":"Deletes a shipping box for good. There is no restore.","operationId":"v1_public_shipment_box_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipping box's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"KkXRzp66r5WrEH","in":"path","name":"hash_id","required":true,"schema":{"example":"KkXRzp66r5WrEH","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a shipping box","tags":["Shipping boxes"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No shipping box with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Make another one the default first, then delete this one.","status":500,"when":"The shipping box is the team default. YoPrint refuses with HTTP 500 and `{\"status\": 500, \"success\": false, \"error\": {\"code\": \"delete_fail\", \"message\": null}}`; nothing is deleted. Don't retry it."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","rules":["The default box cannot be deleted."]}},"get":{"description":"Returns one shipping box.","operationId":"v1_public_shipment_box_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipping box's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"KkXRzp66r5WrEH","in":"path","name":"hash_id","required":true,"schema":{"example":"KkXRzp66r5WrEH","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"height":12000,"id":"KkXRzp66r5WrEH","is_default":true,"is_insured":false,"length":16000,"length_unit":"IN","name":"Medium box","width":12000},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"height":{"description":"The height, in thousandths of the unit (the size ×1000): `12000` is 12.","example":12000,"type":"integer"},"id":{"example":"KkXRzp66r5WrEH","type":"string"},"is_default":{"description":"Whether it is the team's default box.","example":true,"type":"boolean"},"is_insured":{"description":"The box's Insured option.","example":false,"type":"boolean"},"length":{"example":16000,"type":"integer"},"length_unit":{"enum":["CM","IN"],"example":"IN","type":"string"},"name":{"example":"Medium box","type":"string"},"width":{"example":12000,"type":"integer"}},"required":["id","name","height","width","length","length_unit","is_default","is_insured"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show a shipping box","tags":["Shipping boxes"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_shipment_box_update_patch"]}},"patch":{"description":"Use PUT to change a shipping box. PATCH ignores every field except `is_default`: `{\"is_default\": true}` makes the box the team default, and nothing else changes.","operationId":"v1_public_shipment_box_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipping box's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"KkXRzp66r5WrEH","in":"path","name":"hash_id","required":true,"schema":{"example":"KkXRzp66r5WrEH","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"is_default":true},"schema":{"properties":{"is_default":{"description":"`true` makes it the default.","type":"boolean"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"height":12000,"id":"KkXRzp66r5WrEH","is_default":true,"is_insured":false,"length":16000,"length_unit":"IN","name":"Medium box","width":12000},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"height":{"description":"The height, in thousandths of the unit (the size ×1000): `12000` is 12.","example":12000,"type":"integer"},"id":{"example":"KkXRzp66r5WrEH","type":"string"},"is_default":{"description":"Whether it is the team's default box.","example":true,"type":"boolean"},"is_insured":{"description":"The box's Insured option.","example":false,"type":"boolean"},"length":{"example":16000,"type":"integer"},"length_unit":{"enum":["CM","IN"],"example":"IN","type":"string"},"name":{"example":"Medium box","type":"string"},"width":{"example":12000,"type":"integer"}},"required":["id","name","height","width","length","length_unit","is_default","is_insured"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Make a shipping box the default","tags":["Shipping boxes"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No shipping box with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_shipment_box_update_patch"]}},"put":{"description":"Changes a shipping box and returns it. Send only the fields to change. `is_default: true` makes it the team default.","operationId":"v1_public_shipment_box_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipping box's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"KkXRzp66r5WrEH","in":"path","name":"hash_id","required":true,"schema":{"example":"KkXRzp66r5WrEH","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"is_default":true},"schema":{"properties":{"height":{"description":"The height, in thousandths of the unit (the size ×1000): `12500` is 12.5.","type":"integer"},"is_default":{"description":"`true` makes it the team's default box. `false` does nothing.","type":"boolean"},"is_insured":{"type":"boolean"},"length":{"description":"The length, in thousandths of the unit (the size ×1000): `12500` is 12.5.","type":"integer"},"length_unit":{"enum":["CM","IN"],"type":"string"},"name":{"type":"string"},"width":{"description":"The width, in thousandths of the unit (the size ×1000): `12500` is 12.5.","type":"integer"}},"required":[],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"height":12000,"id":"KkXRzp66r5WrEH","is_default":true,"is_insured":false,"length":16000,"length_unit":"IN","name":"Medium box","width":12000},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"height":{"description":"The height, in thousandths of the unit (the size ×1000): `12000` is 12.","example":12000,"type":"integer"},"id":{"example":"KkXRzp66r5WrEH","type":"string"},"is_default":{"description":"Whether it is the team's default box.","example":true,"type":"boolean"},"is_insured":{"description":"The box's Insured option.","example":false,"type":"boolean"},"length":{"example":16000,"type":"integer"},"length_unit":{"enum":["CM","IN"],"example":"IN","type":"string"},"name":{"example":"Medium box","type":"string"},"width":{"example":12000,"type":"integer"}},"required":["id","name","height","width","length","length_unit","is_default","is_insured"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a shipping box","tags":["Shipping boxes"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No shipping box with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A size is not a whole number, or `length_unit` is not `CM` or `IN`. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_shipment_box_show"]}}},"/v1/api/store/{team_slug}/setting/shipping_type":{"get":{"description":"Returns all the team's shipping methods in one list, including deleted ones (`trashed: true`).\n\nShipping methods say how a shipment goes out: by courier, your own delivery, customer pick-up, or a service of a connected carrier integration such as UPS or FedEx. Each shipment names its method with `shipping_type_id`. YoPrint makes the GoShippo and Shopify fulfillment methods itself.","operationId":"v1_public_shipping_type_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"default":true,"external_integration_id":null,"id":"1aNKrP6pU0uytN","min_price":0,"name":"Pick Up","price_percent":0,"price_type":"markup","service_code":null,"trashed":false,"type":"pick_up"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"default":{"description":"Whether it is the team's default shipping method.","example":true,"type":"boolean"},"external_integration_id":{"description":"The carrier integration, for `integration` methods.","example":null,"type":["string","null"]},"id":{"example":"1aNKrP6pU0uytN","type":"string"},"min_price":{"description":"The Minimum Price. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). Stored only, like `price_type`.","example":0,"type":"integer"},"name":{"example":"Pick Up","type":"string"},"price_percent":{"description":"The Markup Percentage or Margin Percentage as a percentage ×1000: `8250` is 8.25%, `10000` is 10%. Stored only, like `price_type`.","example":0,"type":"integer"},"price_type":{"description":"Pricing calculation type: `markup` (markup percentage on carrier cost) or `margin` (profit margin percentage). Stored and displayed in the web app; the API does not apply this calculation to shipment prices.","enum":["markup","margin"],"example":"markup","type":"string"},"service_code":{"description":"The carrier's service code, for `integration` methods.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted shipping method.","example":false,"type":"boolean"},"type":{"description":"`courier`, `self_delivery`, `pick_up`: your own methods. `integration`: a service of a connected carrier integration. `integration_shippo` and `shopify_fulfillment` are made by YoPrint.","enum":["courier","self_delivery","pick_up","integration","integration_shippo","shopify_fulfillment"],"example":"pick_up","type":"string"}},"required":["id","name","type","external_integration_id","service_code","price_type","price_percent","min_price","default","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List shipping methods","tags":["Shipping methods"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_shipping_type_store"]}},"post":{"description":"Creates a shipping method and returns it. An `integration` method uses one service of a connected carrier integration; the others are your own.\n\nThe team's first shipping method becomes its default. `default` in the body doesn't change the default when the team already has one; update the method with `default: true` afterwards.\n\nShipping methods say how a shipment goes out: by courier, your own delivery, customer pick-up, or a service of a connected carrier integration such as UPS or FedEx. Each shipment names its method with `shipping_type_id`. YoPrint makes the GoShippo and Shopify fulfillment methods itself.","operationId":"v1_public_shipping_type_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"integration":{"summary":"A carrier service with a 10% markup","value":{"external_integration_id":"bHTF18MXCEJwKc","min_price":5000,"name":"UPS Ground","price_percent":10000,"price_type":"markup","service_code":"ground","type":"integration"},"x-yoprint-variant":"Carrier integration service"},"own":{"summary":"Local delivery","value":{"name":"Local delivery","type":"self_delivery"},"x-yoprint-variant":"Your own method"}},"schema":{"oneOf":[{"description":"Courier, your own delivery, or pick-up.","properties":{"default":{"description":"Has no effect when the team already has a default.","type":"boolean"},"min_price":{"description":"The Minimum Price. Send a whole number of thousandths: `12500` is 12.50. Defaults to 0.","type":"integer"},"name":{"type":"string"},"price_percent":{"description":"The Markup Percentage or Margin Percentage. Send a whole number as a percentage ×1000: `8250` is 8.25%, `10000` is 10%. Defaults to 0.","type":"integer"},"price_type":{"description":"Pricing calculation type: `markup` (markup percentage on carrier cost) or `margin` (profit margin percentage). Defaults to `markup`. Stored with the method; the API does not apply this calculation to shipment prices.","enum":["markup","margin"],"type":"string"},"type":{"enum":["courier","self_delivery","pick_up"],"type":"string"}},"required":["name","type"],"title":"Your own method","type":"object"},{"description":"One service of a connected shipping integration.","properties":{"default":{"description":"Has no effect when the team already has a default.","type":"boolean"},"external_integration_id":{"description":"The id of a connected shipping integration (Settings, Apps).","type":"string"},"min_price":{"description":"The Minimum Price. Send a whole number of thousandths: `12500` is 12.50. Defaults to 0.","type":"integer"},"name":{"type":"string"},"price_percent":{"description":"The Markup Percentage or Margin Percentage. Send a whole number as a percentage ×1000: `8250` is 8.25%, `10000` is 10%. Defaults to 0.","type":"integer"},"price_type":{"description":"Pricing calculation type: `markup` (markup percentage on carrier cost) or `margin` (profit margin percentage). Defaults to `markup`. Stored with the method; the API does not apply this calculation to shipment prices.","enum":["markup","margin"],"type":"string"},"service_code":{"description":"A service code the integration offers.","type":"string"},"type":{"const":"integration","type":"string"}},"required":["name","type","external_integration_id","service_code","price_percent","min_price"],"title":"Carrier integration service","type":"object"}],"title":"What kind of method?"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"default":false,"external_integration_id":null,"id":"u16QRJNTkBfHZF","min_price":0,"name":"Local delivery","price_percent":0,"price_type":"markup","service_code":null,"trashed":false,"type":"self_delivery"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"default":{"description":"Whether it is the team's default shipping method.","example":true,"type":"boolean"},"external_integration_id":{"description":"The carrier integration, for `integration` methods.","example":null,"type":["string","null"]},"id":{"example":"1aNKrP6pU0uytN","type":"string"},"min_price":{"description":"The Minimum Price. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). Stored only, like `price_type`.","example":0,"type":"integer"},"name":{"example":"Pick Up","type":"string"},"price_percent":{"description":"The Markup Percentage or Margin Percentage as a percentage ×1000: `8250` is 8.25%, `10000` is 10%. Stored only, like `price_type`.","example":0,"type":"integer"},"price_type":{"description":"Pricing calculation type: `markup` (markup percentage on carrier cost) or `margin` (profit margin percentage). Stored and displayed in the web app; the API does not apply this calculation to shipment prices.","enum":["markup","margin"],"example":"markup","type":"string"},"service_code":{"description":"The carrier's service code, for `integration` methods.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted shipping method.","example":false,"type":"boolean"},"type":{"description":"`courier`, `self_delivery`, `pick_up`: your own methods. `integration`: a service of a connected carrier integration. `integration_shippo` and `shopify_fulfillment` are made by YoPrint.","enum":["courier","self_delivery","pick_up","integration","integration_shippo","shopify_fulfillment"],"example":"pick_up","type":"string"}},"required":["id","name","type","external_integration_id","service_code","price_type","price_percent","min_price","default","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a shipping method","tags":["Shipping methods"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A required field is missing, `type` is not allowed, `external_integration_id` is not a hash id, or a number is not a whole number. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."},{"fix":"Use an id from List integrations.","status":404,"when":"`external_integration_id` names no integration of this team, for example a deleted one (`error.code` null, \"No query results…\")."},{"fix":"Check that the id is a connected shipping integration and that it offers the service code, then try again.","status":500,"when":"The integration is not a shipping integration, or doesn't offer `service_code`. YoPrint answers with a generic server error (`{\"message\": \"Server Error\"}`) that doesn't say which; nothing is created."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_shipping_type_update_patch","v1_public_external_integration_index"],"rules":["`type` is `courier`, `self_delivery`, `pick_up` or `integration`. GoShippo and Shopify fulfillment methods cannot be created.","An `integration` method needs `external_integration_id` (a shipping integration), a `service_code` that integration offers, `price_percent` and `min_price`.","Percentages are whole numbers (a percentage ×1000: `8250` is 8.25%). Prices are whole numbers in thousandths (`12500` is 12.50).","The type cannot be changed later."]}}},"/v1/api/store/{team_slug}/setting/shipping_type/{hash_id}":{"delete":{"description":"Deletes a shipping method. It stays in the list with `trashed: true` and can be restored. Shipments that used it keep it.","operationId":"v1_public_shipping_type_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipping method's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"1aNKrP6pU0uytN","in":"path","name":"hash_id","required":true,"schema":{"example":"1aNKrP6pU0uytN","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a shipping method","tags":["Shipping methods"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No shipping method with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Make another method the default first. YoPrint's own methods stay.","status":500,"when":"The method is the default, or a GoShippo or Shopify fulfillment method (`error.code` is `delete_fail`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_shipping_type_restore"],"rules":["The default method, and the GoShippo and Shopify fulfillment methods, cannot be deleted."]}},"get":{"description":"Returns one shipping method, deleted or not.","operationId":"v1_public_shipping_type_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipping method's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"1aNKrP6pU0uytN","in":"path","name":"hash_id","required":true,"schema":{"example":"1aNKrP6pU0uytN","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"default":true,"external_integration_id":null,"id":"1aNKrP6pU0uytN","min_price":0,"name":"Pick Up","price_percent":0,"price_type":"markup","service_code":null,"trashed":false,"type":"pick_up"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"default":{"description":"Whether it is the team's default shipping method.","example":true,"type":"boolean"},"external_integration_id":{"description":"The carrier integration, for `integration` methods.","example":null,"type":["string","null"]},"id":{"example":"1aNKrP6pU0uytN","type":"string"},"min_price":{"description":"The Minimum Price. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). Stored only, like `price_type`.","example":0,"type":"integer"},"name":{"example":"Pick Up","type":"string"},"price_percent":{"description":"The Markup Percentage or Margin Percentage as a percentage ×1000: `8250` is 8.25%, `10000` is 10%. Stored only, like `price_type`.","example":0,"type":"integer"},"price_type":{"description":"Pricing calculation type: `markup` (markup percentage on carrier cost) or `margin` (profit margin percentage). Stored and displayed in the web app; the API does not apply this calculation to shipment prices.","enum":["markup","margin"],"example":"markup","type":"string"},"service_code":{"description":"The carrier's service code, for `integration` methods.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted shipping method.","example":false,"type":"boolean"},"type":{"description":"`courier`, `self_delivery`, `pick_up`: your own methods. `integration`: a service of a connected carrier integration. `integration_shippo` and `shopify_fulfillment` are made by YoPrint.","enum":["courier","self_delivery","pick_up","integration","integration_shippo","shopify_fulfillment"],"example":"pick_up","type":"string"}},"required":["id","name","type","external_integration_id","service_code","price_type","price_percent","min_price","default","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show a shipping method","tags":["Shipping methods"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_shipping_type_update_patch"]}},"patch":{"description":"Use PUT to change a shipping method. PATCH ignores every field except `default`: `{\"default\": true}` makes the method the team default, and nothing else changes. On an `integration` method, PATCH fails.","operationId":"v1_public_shipping_type_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipping method's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"1aNKrP6pU0uytN","in":"path","name":"hash_id","required":true,"schema":{"example":"1aNKrP6pU0uytN","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"default":true},"schema":{"properties":{"default":{"description":"`true` makes it the default.","type":"boolean"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"default":true,"external_integration_id":null,"id":"1aNKrP6pU0uytN","min_price":0,"name":"Pick Up","price_percent":0,"price_type":"markup","service_code":null,"trashed":false,"type":"pick_up"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"default":{"description":"Whether it is the team's default shipping method.","example":true,"type":"boolean"},"external_integration_id":{"description":"The carrier integration, for `integration` methods.","example":null,"type":["string","null"]},"id":{"example":"1aNKrP6pU0uytN","type":"string"},"min_price":{"description":"The Minimum Price. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). Stored only, like `price_type`.","example":0,"type":"integer"},"name":{"example":"Pick Up","type":"string"},"price_percent":{"description":"The Markup Percentage or Margin Percentage as a percentage ×1000: `8250` is 8.25%, `10000` is 10%. Stored only, like `price_type`.","example":0,"type":"integer"},"price_type":{"description":"Pricing calculation type: `markup` (markup percentage on carrier cost) or `margin` (profit margin percentage). Stored and displayed in the web app; the API does not apply this calculation to shipment prices.","enum":["markup","margin"],"example":"markup","type":"string"},"service_code":{"description":"The carrier's service code, for `integration` methods.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted shipping method.","example":false,"type":"boolean"},"type":{"description":"`courier`, `self_delivery`, `pick_up`: your own methods. `integration`: a service of a connected carrier integration. `integration_shippo` and `shopify_fulfillment` are made by YoPrint.","enum":["courier","self_delivery","pick_up","integration","integration_shippo","shopify_fulfillment"],"example":"pick_up","type":"string"}},"required":["id","name","type","external_integration_id","service_code","price_type","price_percent","min_price","default","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Make a shipping method the default","tags":["Shipping methods"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No shipping method with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Pick another method.","status":422,"when":"`default: true` on the Shopify fulfillment method."},{"fix":"Use PUT with `service_code`.","status":500,"when":"The method is an `integration` method."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_shipping_type_update_patch"]}},"put":{"description":"Changes a shipping method and returns it. Send only the fields to change; for an `integration` method, always send `service_code`. `default: true` makes it the team default. The type and integration can't be changed.","operationId":"v1_public_shipping_type_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipping method's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"1aNKrP6pU0uytN","in":"path","name":"hash_id","required":true,"schema":{"example":"1aNKrP6pU0uytN","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"Make it the default","value":{"default":true}},"rename":{"summary":"Rename","value":{"name":"Customer pick-up"}}},"schema":{"properties":{"default":{"description":"`true` makes it the team's default shipping method. `false` does nothing.","type":"boolean"},"min_price":{"description":"The Minimum Price. Send a whole number of thousandths: `12500` is 12.50. Defaults to 0.","type":"integer"},"name":{"type":"string"},"price_percent":{"description":"The Markup Percentage or Margin Percentage. Send a whole number as a percentage ×1000: `8250` is 8.25%, `10000` is 10%. Defaults to 0.","type":"integer"},"price_type":{"description":"Pricing calculation type: `markup` (markup percentage on carrier cost) or `margin` (profit margin percentage). Defaults to `markup`. Stored with the method; the API does not apply this calculation to shipment prices.","enum":["markup","margin"],"type":"string"},"service_code":{"description":"Required for `integration` methods, even when it doesn't change. Must be a service the integration offers.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"default":true,"external_integration_id":null,"id":"1aNKrP6pU0uytN","min_price":0,"name":"Customer pick-up","price_percent":0,"price_type":"markup","service_code":null,"trashed":false,"type":"pick_up"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"default":{"description":"Whether it is the team's default shipping method.","example":true,"type":"boolean"},"external_integration_id":{"description":"The carrier integration, for `integration` methods.","example":null,"type":["string","null"]},"id":{"example":"1aNKrP6pU0uytN","type":"string"},"min_price":{"description":"The Minimum Price. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). Stored only, like `price_type`.","example":0,"type":"integer"},"name":{"example":"Pick Up","type":"string"},"price_percent":{"description":"The Markup Percentage or Margin Percentage as a percentage ×1000: `8250` is 8.25%, `10000` is 10%. Stored only, like `price_type`.","example":0,"type":"integer"},"price_type":{"description":"Pricing calculation type: `markup` (markup percentage on carrier cost) or `margin` (profit margin percentage). Stored and displayed in the web app; the API does not apply this calculation to shipment prices.","enum":["markup","margin"],"example":"markup","type":"string"},"service_code":{"description":"The carrier's service code, for `integration` methods.","example":null,"type":["string","null"]},"trashed":{"description":"True for a deleted shipping method.","example":false,"type":"boolean"},"type":{"description":"`courier`, `self_delivery`, `pick_up`: your own methods. `integration`: a service of a connected carrier integration. `integration_shippo` and `shopify_fulfillment` are made by YoPrint.","enum":["courier","self_delivery","pick_up","integration","integration_shippo","shopify_fulfillment"],"example":"pick_up","type":"string"}},"required":["id","name","type","external_integration_id","service_code","price_type","price_percent","min_price","default","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a shipping method","tags":["Shipping methods"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No shipping method with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A field has the wrong type or value. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."},{"fix":"Pick another method as the default.","status":422,"when":"`default: true` on the Shopify fulfillment method (`shopify_system_shipping_type_default_locked`)."},{"fix":"Send a `service_code` the integration offers.","status":500,"when":"On an `integration` method: `service_code` is missing (a generic `{\"message\": \"Server Error\"}`), or the integration doesn't offer it (`error.code` `invalid_service_code`). Nothing is saved."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_shipping_type_show"],"rules":["For an `integration` method, `service_code` is required on every update and must be a service the integration offers.","The Shopify fulfillment method cannot be the default."]}}},"/v1/api/store/{team_slug}/setting/shipping_type/{id}/restore":{"patch":{"description":"Brings back a deleted shipping method.","operationId":"v1_public_shipping_type_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipping method's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"1aNKrP6pU0uytN","in":"path","name":"id","required":true,"schema":{"example":"1aNKrP6pU0uytN","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a shipping method","tags":["Shipping methods"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No shipping method with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_shipping_type_destroy"]}}},"/v1/api/store/{team_slug}/setting/status":{"get":{"description":"Returns every status the team has, for every list, including deleted ones (`trashed: true`).\n\nUse it for a settings screen or a full sync. To fill a status picker, use the list for one kind of record instead (for example `GET /v1/api/store/{team_slug}/setting/status/sales_order`): those leave deleted statuses out.\n\nThe list is not sorted. Group by `role` (and `pipeline_id` for task statuses), then sort by `position`.","operationId":"v1_public_status_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color":"#1e88e5","customer_label":"In Progress","id":"0CoeFF1BmpcxxE","label":"Printing","position":2,"role":"order","trashed":false,"type":"in_progress"},{"color":"#ff9800","customer_label":"In Progress","id":"0FBSNFKFGHapYd","label":"On hold","position":3,"role":"job","trashed":true,"type":"in_progress"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List every status, including deleted ones","tags":["Statuses"],"x-yoprint-docs":{"group":"Team settings","permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_status_list_sales_order","v1_public_status_store","v1_public_status_restore"]}},"post":{"description":"Adds an in-between status (`type: in_progress`) to one list: sales orders, quotes, jobs, purchase orders, shipments, message threads, or the tasks of a task preset.\n\nEvery list already has one starting and one ending status, which you can rename but not add. To move the start or end marker to another status, use \"Save a set of status changes\" (`POST /v1/api/store/{team_slug}/setting/status/sync`).\n\nReturns the new status.","operationId":"v1_public_status_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"sales_order":{"summary":"A sales order status","value":{"color":"#1e88e5","label":"Printing","position":2,"role":"order","type":"in_progress"}},"task":{"summary":"A task status in a task preset","value":{"color":"#43a047","label":"Screens burned","pipeline_id":"eIOQnV5PP0pp7c","position":1,"role":"pipeline","type":"in_progress"}}},"schema":{"additionalProperties":false,"properties":{"color":{"description":"A hex color with the `#`, 3 or 6 digits: `#1e88e5`.","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$","type":"string"},"customer_label":{"description":"Optional. What customers see in the customer portal.","type":"string"},"label":{"description":"The name your team sees.","type":"string"},"pipeline_id":{"description":"Required when `role` is `pipeline`: the ID of the task preset this status belongs to. Ignored for other roles.","type":"string"},"position":{"description":"Sort order within the list. Defaults to 0.","maximum":2147483647,"minimum":-2147483648,"type":"integer"},"role":{"description":"Which status list to add it to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset (requires `pipeline_id`)","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"type":{"const":"in_progress","description":"Must be `in_progress`. Other types cannot be created with this operation (to create or change `start` or `end` statuses, use Save a set of status changes).","type":"string"}},"required":["label","color","type","role"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"color":"#1e88e5","customer_label":"In Progress","id":"0CoeFF1BmpcxxE","label":"Printing","position":2,"role":"order","trashed":false,"type":"in_progress"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a status","tags":["Statuses"],"x-yoprint-docs":{"errors":[{"fix":"Send `label`, `color` like `#1e88e5`, `type: in_progress` and a `role` from the list.","status":422,"when":"A required field is missing, `color` is not a hex color, or `type` or `role` is not an allowed value (`validation_failed`, with `error.fields`)."},{"fix":"Send `type: in_progress`. Nothing was saved.","status":500,"when":"`type` is `pre_production`. The body is `{\"message\": \"Server Error\"}`, without the error envelope."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_status_update_patch","v1_public_status_sync","v1_public_status_list_sales_order"],"rules":["Only `type: in_progress` saves. `pre_production` passes validation but fails with 500; `start` and `end` are refused with 422.","`pipeline_id` is required when `role` is `pipeline`, and ignored for every other role.","Labels don't have to be unique."],"side_effects":["Team members who have YoPrint open see the new status at once."]}}},"/v1/api/store/{team_slug}/setting/status/customer_message":{"get":{"description":"Returns the team's message thread (role `customer_message`) statuses. Deleted statuses are left out. These exist once the \"customer message statuses\" add-on has been turned on (`PUT /v1/api/store/{team_slug}/setting/feature_addon/cust_msg_status/enable`).\n\nThe list is not sorted: sort by `position` (lowest first) to show it in the order the team set. Use the `id` of a status wherever a request asks for a status id.","operationId":"v1_public_status_list_customer_message","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color":"#f5f5f5","customer_label":"Pending","id":"ID5Uq31nRDPaUa","label":"Awaiting Customer Reply","position":0,"role":"customer_message","trashed":false,"type":"start"},{"color":"#c6ff00","customer_label":"In Progress","id":"MjaAFMWeKzfwDl","label":"Need to Respond","position":1,"role":"customer_message","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"k6ui4z13Dps9KT","label":"Completed","position":6,"role":"customer_message","trashed":false,"type":"end"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List message thread statuses","tags":["Statuses"],"x-yoprint-docs":{"group":"Team settings","notes":["Read the list once and reuse the ids; statuses change rarely."],"permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_status_index","v1_public_status_store"]}}},"/v1/api/store/{team_slug}/setting/status/job":{"get":{"description":"Returns the team's job (role `job`) statuses. Deleted statuses are left out.\n\nThe list is not sorted: sort by `position` (lowest first) to show it in the order the team set. Use the `id` of a status wherever a request asks for a status id.","operationId":"v1_public_status_list_job","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color":"#f5f5f5","customer_label":"Pending","id":"sL0BrabjZwug91","label":"New","position":0,"role":"job","trashed":false,"type":"start"},{"color":"#1e88e5","customer_label":"In Progress","id":"cBs0FZpx8a7dyA","label":"Printing","position":2,"role":"job","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"GoEoxgoShq1mEu","label":"Completed","position":6,"role":"job","trashed":false,"type":"end"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List job statuses","tags":["Statuses"],"x-yoprint-docs":{"group":"Team settings","notes":["Read the list once and reuse the ids; statuses change rarely."],"permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_status_index","v1_public_status_store"]}}},"/v1/api/store/{team_slug}/setting/status/pipeline/{hash_id}":{"get":{"description":"Returns the statuses of one task preset (role `pipeline`): the steps a task moves through. The path takes the task preset's id, from `GET /v1/api/store/{team_slug}/setting/pipeline`. Deleted statuses are left out.\n\nThe list is not sorted: sort by `position` (lowest first). A valid id that names no task preset answers an empty list, not 404.","operationId":"v1_public_status_list_pipeline","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The task preset, from `GET /v1/api/store/{team_slug}/setting/pipeline`. Its hash id from an earlier answer; there is no unique key for it.","example":"eIOQnV5PP0pp7c","in":"path","name":"hash_id","required":true,"schema":{"example":"eIOQnV5PP0pp7c","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color":"#f5f5f5","customer_label":"Pending","id":"fA3KDzwnMRc5Cd","label":"To do","pipeline_id":"eIOQnV5PP0pp7c","position":0,"role":"pipeline","trashed":false,"type":"start"},{"color":"#424242","customer_label":"Completed","id":"MIJM9QpP6O0whd","label":"Done","pipeline_id":"eIOQnV5PP0pp7c","position":1,"role":"pipeline","trashed":false,"type":"end"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the task statuses of a task preset","tags":["Statuses"],"x-yoprint-docs":{"group":"Team settings","notes":["Read the list once and reuse the ids; statuses change rarely."],"permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_status_index","v1_public_status_store"]}}},"/v1/api/store/{team_slug}/setting/status/purchase_order":{"get":{"description":"Returns the team's purchase order (role `purchase_order`) statuses. Deleted statuses are left out.\n\nThe list is not sorted: sort by `position` (lowest first) to show it in the order the team set. Use the `id` of a status wherever a request asks for a status id.","operationId":"v1_public_status_list_purchase_order","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color":"#f5f5f5","customer_label":"Pending","id":"3y3BaxoCuUPLFG","label":"New","position":0,"role":"purchase_order","trashed":false,"type":"start"},{"color":"#1e88e5","customer_label":"In Progress","id":"KfY91KjTCizddl","label":"Printing","position":2,"role":"purchase_order","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"gbkoQGmDAHPI2u","label":"Completed","position":6,"role":"purchase_order","trashed":false,"type":"end"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List purchase order statuses","tags":["Statuses"],"x-yoprint-docs":{"group":"Team settings","notes":["Read the list once and reuse the ids; statuses change rarely."],"permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_status_index","v1_public_status_store"]}}},"/v1/api/store/{team_slug}/setting/status/purchase_order_without_end":{"get":{"description":"Returns the team's purchase order (role `purchase_order`) statuses. Deleted statuses are left out. The ending (`end`) status is left out too.\n\nThe list is not sorted: sort by `position` (lowest first) to show it in the order the team set. Use the `id` of a status wherever a request asks for a status id.","operationId":"v1_public_status_list_purchase_order_without_end","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color":"#f5f5f5","customer_label":"Pending","id":"3y3BaxoCuUPLFG","label":"New","position":0,"role":"purchase_order","trashed":false,"type":"start"},{"color":"#1e88e5","customer_label":"In Progress","id":"KfY91KjTCizddl","label":"Printing","position":2,"role":"purchase_order","trashed":false,"type":"in_progress"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List purchase order statuses, without the ending one","tags":["Statuses"],"x-yoprint-docs":{"group":"Team settings","notes":["Read the list once and reuse the ids; statuses change rarely."],"permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_status_index","v1_public_status_store"]}}},"/v1/api/store/{team_slug}/setting/status/quote":{"get":{"description":"Returns the team's quote (role `quote`) statuses. Deleted statuses are left out.\n\nThe list is not sorted: sort by `position` (lowest first) to show it in the order the team set. Use the `id` of a status wherever a request asks for a status id.","operationId":"v1_public_status_list_quote","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color":"#f5f5f5","customer_label":"Pending","id":"k0O0mVOyJg0BPD","label":"New","position":0,"role":"quote","trashed":false,"type":"start"},{"color":"#1e88e5","customer_label":"In Progress","id":"sZabHnxhUN3ouI","label":"Printing","position":2,"role":"quote","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"kxS1tOOSlCugWu","label":"Completed","position":6,"role":"quote","trashed":false,"type":"end"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List quote statuses","tags":["Statuses"],"x-yoprint-docs":{"group":"Team settings","notes":["Read the list once and reuse the ids; statuses change rarely."],"permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_status_index","v1_public_status_store"]}}},"/v1/api/store/{team_slug}/setting/status/sales_order":{"get":{"description":"Returns the team's sales order (role `order`) statuses. Deleted statuses are left out. The path says `sales_order`, but the rows' `role` is `order`.\n\nThe list is not sorted: sort by `position` (lowest first) to show it in the order the team set. Use the `id` of a status wherever a request asks for a status id.","operationId":"v1_public_status_list_sales_order","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color":"#f5f5f5","customer_label":"Pending","id":"q0hnLYYLRQE3tw","label":"New","position":0,"role":"order","trashed":false,"type":"start"},{"color":"#1e88e5","customer_label":"In Progress","id":"0CoeFF1BmpcxxE","label":"Printing","position":2,"role":"order","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"FDIbFjrYvFgaCW","label":"Completed","position":6,"role":"order","trashed":false,"type":"end"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List sales order statuses","tags":["Statuses"],"x-yoprint-docs":{"group":"Team settings","notes":["Read the list once and reuse the ids; statuses change rarely."],"permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_status_index","v1_public_status_store"]}}},"/v1/api/store/{team_slug}/setting/status/shipment":{"get":{"description":"Returns the team's shipment (role `shipment`) statuses. Deleted statuses are left out.\n\nThe list is not sorted: sort by `position` (lowest first) to show it in the order the team set. Use the `id` of a status wherever a request asks for a status id.","operationId":"v1_public_status_list_shipment","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color":"#f5f5f5","customer_label":"Pending","id":"GQrF01EL8SVHJv","label":"New","position":0,"role":"shipment","trashed":false,"type":"start"},{"color":"#1e88e5","customer_label":"In Progress","id":"AdTyucFdeza4SI","label":"Printing","position":2,"role":"shipment","trashed":false,"type":"in_progress"},{"color":"#424242","customer_label":"Completed","id":"tlYiHMZ8c6yQok","label":"Completed","position":6,"role":"shipment","trashed":false,"type":"end"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List shipment statuses","tags":["Statuses"],"x-yoprint-docs":{"group":"Team settings","notes":["Read the list once and reuse the ids; statuses change rarely."],"permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_status_index","v1_public_status_store"]}}},"/v1/api/store/{team_slug}/setting/status/{id}/restore":{"patch":{"description":"Brings back a deleted status, with its label, color, type and position. Find deleted statuses in the full list (`trashed: true`). Restoring a status that is not deleted changes nothing. Returns the status.","operationId":"v1_public_status_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The deleted status, from the full status list. Its hash id from an earlier answer; there is no unique key for it.","example":"0FBSNFKFGHapYd","in":"path","name":"id","required":true,"schema":{"example":"0FBSNFKFGHapYd","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"color":"#ff9800","customer_label":"In Progress","id":"0FBSNFKFGHapYd","label":"On hold","position":3,"role":"job","trashed":false,"type":"in_progress"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a deleted status","tags":["Statuses"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Use an id from the full list.","status":404,"when":"No status of your team, deleted or not, has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["A restored `end` status sits next to any ending status you marked meanwhile; check the list afterwards."],"permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_status_destroy","v1_public_status_index"],"side_effects":["Team members who have YoPrint open see the status come back at once."]}}},"/v1/api/store/{team_slug}/setting/status/{status_reference}":{"delete":{"description":"Deletes an in-between (`in_progress`) or ending (`end`) status. Starting (`start`) and `pre_production` statuses can't be deleted: the call answers 500 and changes nothing.\n\nThe delete is soft. Records already in this status keep it and still show its label; it just leaves the lists you pick from. Nothing checks whether the status is in use first. Bring it back with `PATCH /v1/api/store/{team_slug}/setting/status/{id}/restore`.","operationId":"v1_public_status_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The status. Its hash id from an earlier answer; there is no unique key for it.","example":"0CoeFF1BmpcxxE","in":"path","name":"status_reference","required":true,"schema":{"example":"0CoeFF1BmpcxxE","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a status","tags":["Statuses"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the status lists.","status":404,"when":"No status of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Rename it instead, or move the start marker first with \"Save a set of status changes\". Nothing changed.","status":500,"when":"The status is a `start` or `pre_production` status. The body is the error envelope with `error.code` and `error.message` null."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_status_restore","v1_public_status_index"],"rules":["Only `in_progress` and `end` statuses can be deleted.","A status in use can be deleted; the records using it keep it.","Deleting the `end` status leaves the list without an ending status until you restore it or mark another one with \"Save a set of status changes\"."],"side_effects":["Team members who have YoPrint open see the status disappear at once."]}},"get":{"description":"Returns one status by its id. A deleted status is not found (404); the full list shows deleted ones.","operationId":"v1_public_status_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The status. Its hash id from an earlier answer; there is no unique key for it.","example":"0CoeFF1BmpcxxE","in":"path","name":"status_reference","required":true,"schema":{"example":"0CoeFF1BmpcxxE","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"color":"#1e88e5","customer_label":"In Progress","id":"0CoeFF1BmpcxxE","label":"Printing","position":2,"role":"order","trashed":false,"type":"in_progress"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a status","tags":["Statuses"],"x-yoprint-docs":{"group":"Team settings","permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_status_update_patch","v1_public_status_index"]}},"patch":{"description":"Use PUT to change a status. PATCH saves the fields without checking them, so a bad value can be stored. See Update a status (PUT) for the fields.","operationId":"v1_public_status_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The status. Its hash id from an earlier answer; there is no unique key for it.","example":"0CoeFF1BmpcxxE","in":"path","name":"status_reference","required":true,"schema":{"example":"0CoeFF1BmpcxxE","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"color":"#3949ab","customer_label":"In production","label":"On press"},"schema":{"additionalProperties":false,"properties":{"color":{"description":"A hex color with the `#`, 3 or 6 digits: `#1e88e5`.","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$","type":"string"},"customer_label":{"description":"What customers see in the customer portal.","type":"string"},"label":{"type":"string"},"pipeline_id":{"description":"For task statuses (`role: pipeline`) only: the task preset's ID. Moves this status to another task preset. Ignored for all other status roles.","type":"string"},"position":{"maximum":2147483647,"minimum":-2147483648,"type":"integer"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"color":"#3949ab","customer_label":"In production","id":"0CoeFF1BmpcxxE","label":"On press","position":2,"role":"order","trashed":false,"type":"in_progress"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a status without checks","tags":["Statuses"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the status lists.","status":404,"when":"No status of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Send a color like `#1e88e5` and an integer position.","status":422,"when":"`color` is not a hex color, or `position` is not a whole number (PUT only; `validation_failed`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_status_show","v1_public_status_sync"],"rules":["`type` and `role` can't change here. `pipeline_id` is ignored unless the status belongs to a task preset."],"side_effects":["Team members who have YoPrint open see the change at once."]}},"post":{"description":"Creates, updates and deletes several statuses in one request, all or nothing. This is how the web app saves the status settings page, and the only way to move a list's start or end marker.\n\nCall it as `POST /v1/api/store/{team_slug}/setting/status/sync`: the last path segment must be the word `sync`. Any other word answers 405.\n\nSend `data`, a list of changes, each with an `action`:\n\n- `create`: a new status. Needs `label`, `color`, `role`, `type` (`in_progress` or `end`) and `position`.\n- `update`: an existing status, by `id`. Send `position` and what changes. Unlike the single update, it can change `type`.\n- `delete`: an `in_progress` status, by `id`.\n\nReturns every status of the team, including deleted ones, like the full list.","operationId":"v1_public_status_sync","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"Always the word `sync`. Any other value answers 405.","example":"sync","in":"path","name":"status_reference","required":true,"schema":{"enum":["sync"],"example":"sync","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"data":[{"action":"create","color":"#43a047","label":"Ready for pickup","position":5,"role":"order","type":"in_progress"},{"action":"update","id":"0CoeFF1BmpcxxE","position":6,"type":"end"},{"action":"delete","id":"bMlYH975FRUWEr"}]},"schema":{"additionalProperties":false,"properties":{"data":{"items":{"additionalProperties":false,"properties":{"action":{"enum":["create","update","delete"],"type":"string"},"color":{"description":"A hex color with the `#`, 3 or 6 digits: `#1e88e5`.","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$","type":"string"},"customer_label":{"type":"string"},"id":{"description":"Required for `update` and `delete`: the status to change.","type":"string"},"label":{"description":"Required for `create`.","type":"string"},"pipeline_id":{"description":"Do not send. This operation does not link statuses to task presets. To create task statuses (`role: pipeline`), use Create a status instead.","type":"string"},"position":{"description":"Required for `create` and `update`.","maximum":2147483647,"minimum":-2147483648,"type":"integer"},"role":{"description":"Required for `create`. Which status list it belongs to (`order`, `quote`, `job`, `purchase_order`, `pipeline`, or `shipment`). `customer_message` statuses cannot be created here, and task statuses (`pipeline`) should be created with Create a status instead.","enum":["order","quote","job","purchase_order","pipeline","shipment"],"type":"string"},"type":{"description":"Required for `create`, which accepts `in_progress` or `end`. On `update`, setting `start` or `end` moves that stage marker to this status; see the rules.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["action"],"type":"object"},"minItems":1,"type":"array"}},"required":["data"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color":"#f5f5f5","customer_label":"Pending","id":"q0hnLYYLRQE3tw","label":"New","position":0,"role":"order","trashed":false,"type":"start"},{"color":"#1e88e5","customer_label":"Completed","id":"0CoeFF1BmpcxxE","label":"Printing","position":6,"role":"order","trashed":false,"type":"end"},{"color":"#424242","customer_label":"In Progress","id":"FDIbFjrYvFgaCW","label":"Completed","position":6,"role":"order","trashed":false,"type":"in_progress"},{"color":"#8e24aa","customer_label":"In Progress","id":"bMlYH975FRUWEr","label":"Quality check","position":3,"role":"order","trashed":true,"type":"in_progress"},{"color":"#43a047","customer_label":"In Progress","id":"Why7b1DdlX6iuu","label":"Ready for pickup","position":5,"role":"order","trashed":false,"type":"in_progress"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Save a set of status changes","tags":["Statuses"],"x-yoprint-docs":{"errors":[{"fix":"Send at least one change, each with its `action` and the fields that action needs.","status":422,"when":"`data` is empty, an item has no `action`, or a `create` item misses a required field (`validation_failed`)."},{"fix":"Use ids from the full list.","status":404,"when":"An `update` or `delete` id is not one of your team's statuses."},{"fix":"Follow the rules above. Nothing was saved.","status":500,"when":"A `delete` targets a status that is not `in_progress`, a `create` has the wrong `type`, or a `start`/`end` status is updated to another type. The body is `{\"message\": \"Server Error\"}`, without the error envelope."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_status_index","v1_public_status_store","v1_public_status_update_patch"],"rules":["All changes run in one transaction: if one fails, none is saved.","Updating a status to `type: start` or `end` turns the list's current start or end status into `in_progress`, so each list keeps one of each.","A `start` or `end` status can't be changed to another type directly. Mark another status as start or end instead.","`delete` works only on `in_progress` statuses; any other type fails the whole request with 500.","`create` accepts only `type` `in_progress` or `end`; `start` and `pre_production` fail the whole request with 500. A created `end` status does not demote the existing one.","Task statuses (`role: pipeline`): this call doesn't decode `pipeline_id`, so a task status created here belongs to no task preset, and an `update` that sends `pipeline_id` detaches it from its preset. Use \"Create a status\" and \"Update a status\" for task statuses."],"side_effects":["Team members who have YoPrint open see each change at once."]}},"put":{"description":"Changes a status's label, color, position or customer portal label. Send only what changes.\n\nThe type and the list it belongs to never change here; any `type` you send is ignored. To make a different status the start or end of a list, use \"Save a set of status changes\".\n\nPUT checks the fields. PATCH saves the same fields without checking them, so prefer PUT.\n\nReturns the updated status. Records already in this status show the new label and color.","operationId":"v1_public_status_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The status. Its hash id from an earlier answer; there is no unique key for it.","example":"0CoeFF1BmpcxxE","in":"path","name":"status_reference","required":true,"schema":{"example":"0CoeFF1BmpcxxE","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"color":"#3949ab","customer_label":"In production","label":"On press"},"schema":{"additionalProperties":false,"properties":{"color":{"description":"A hex color with the `#`, 3 or 6 digits: `#1e88e5`.","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$","type":"string"},"customer_label":{"description":"What customers see in the customer portal.","type":"string"},"label":{"type":"string"},"pipeline_id":{"description":"For task statuses (`role: pipeline`) only: the task preset's ID. Moves this status to another task preset. Ignored for all other status roles.","type":"string"},"position":{"maximum":2147483647,"minimum":-2147483648,"type":"integer"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"color":"#3949ab","customer_label":"In production","id":"0CoeFF1BmpcxxE","label":"On press","position":2,"role":"order","trashed":false,"type":"in_progress"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"color":{"example":"#1e88e5","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","example":"In Progress","type":"string"},"id":{"example":"0CoeFF1BmpcxxE","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only. Absent for every other role.","example":"eIOQnV5PP0pp7c","type":"string"},"position":{"description":"Sort order within the list, lowest first.","example":2,"type":"integer"},"role":{"description":"Which list the status belongs to:\n\n- `order`: sales orders\n- `quote`: quotes\n- `job`: jobs\n- `purchase_order`: purchase orders\n- `shipment`: shipments\n- `customer_message`: message threads\n- `pipeline`: tasks within a task preset","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"type":"string"},"trashed":{"description":"True for a deleted status. Only the full list includes deleted ones.","example":false,"type":"boolean"},"type":{"description":"The stage of the status in the workflow: `start` (first status in the list), `pre_production`, `in_progress`, or `end` (final status).","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a status","tags":["Statuses"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the status lists.","status":404,"when":"No status of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Send a color like `#1e88e5` and an integer position.","status":422,"when":"`color` is not a hex color, or `position` is not a whole number (PUT only; `validation_failed`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_status_show","v1_public_status_sync"],"rules":["`type` and `role` can't change here. `pipeline_id` is ignored unless the status belongs to a task preset."],"side_effects":["Team members who have YoPrint open see the change at once."]}}},"/v1/api/store/{team_slug}/setting/subscription/check_coupon":{"put":{"description":"Checks a coupon code for a plan and, when it is valid, returns its discount and a `coupon_token`. Send that token with the coupon to the plan preview and checkout.\n\nIt applies nothing and charges nothing.","operationId":"v1_public_setting_subscription_check_coupon","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"coupon":"WELCOME10","new_plan":"starter-monthly-v2"},"schema":{"additionalProperties":false,"properties":{"coupon":{"description":"The coupon code.","type":"string"},"new_plan":{"description":"The plan `id` you want, from the plan list.","type":"string"}},"required":["coupon","new_plan"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"amount_off":null,"coupon_token":"YOUR_COUPON_TOKEN","duration":"once","duration_in_months":null,"id":"WELCOME10","name":"Welcome 10%","percent_off":10000,"trial_days":0},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"amount_off":{"description":"A fixed discount, or null for a percentage coupon. Thousandths, an older encoding: `5000` is 5.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","null"]},"coupon_token":{"description":"Send it as `coupon_token` with the same `coupon` to preview and checkout.","type":"string"},"duration":{"type":["string","null"]},"duration_in_months":{"type":["integer","null"]},"id":{"type":"string"},"name":{"type":["string","null"]},"percent_off":{"description":"The percentage discount, or null for a fixed discount. A percentage ×1000: `25500` is 25.5%, `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","type":["integer","null"]},"trial_days":{"type":"integer"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Check a YoPrint coupon","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Check the code.","status":422,"when":"The coupon is unknown or not valid for that plan and your team (`invalid_coupon`), or a field is missing (`validation_failed`)."},{"fix":"Use an `id` from the plan list.","status":500,"when":"`new_plan` is not a plan id. The body is `{\"message\": \"Server Error\"}`, without the error envelope."},{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_plan_preview","v1_public_setting_subscription_plan_checkout"]}}},"/v1/api/store/{team_slug}/setting/subscription/current":{"get":{"description":"Returns the team's current YoPrint subscription: its plan and extras, price, state, dates and the card on file (brand and last four digits only). A team with no subscription (for example during a trial) gets 422 `no_active_plan`. Reading it changes nothing.","operationId":"v1_public_setting_subscription_current_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"active":true,"attempt_count":null,"billing_cycle":"monthly","config_option":[{"type":"warehouse","value":1},{"type":"pricing_group","value":1},{"type":"user_limit","value":5},{"type":"pricing_rule","value":5}],"ends_at":null,"features":{"api_access":true,"customer_portal":true,"job_list":true},"last_invoice_date":"2026-10-01T00:00:00+00:00","last_warning_sent":0,"next_payment_attempt":null,"plan":{"billing_cycle":"monthly","config_option":[{"id":"user_limit","included":3,"label":"Users","max":100,"min":3,"price":{"type":"none"},"type":"number"}],"configurable":true,"display_features":[{"has_tooltip":false,"is_bold":true,"is_new":false,"text":"3 Users Included","tooltip":""}],"free":false,"id":"starter-monthly-v2","is_archived":false,"name":"Starter","price":39000,"trial_plan_id":"starter-trial","type":"paid"},"price":69000,"status":"active","stripe_card_brand":"Visa","stripe_card_last_four":"4242","trial_ends_at":null},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"active":{"description":"Whether YoPrint treats the subscription as active now.","type":"boolean"},"attempt_count":{"description":"Failed payment attempts on the open invoice.","type":["integer","null"]},"billing_cycle":{"enum":["monthly","annually"],"type":"string"},"config_option":{"description":"The limits on this subscription, as `{type, value}` for `warehouse`, `pricing_group`, `user_limit` and `pricing_rule`; `[]` when the plan has no extras.","type":["array","object","null"]},"ends_at":{"description":"Set when a cancellation is scheduled: the plan ends then.","format":"date-time","type":["string","null"]},"features":{"additionalProperties":true,"description":"The plan's features and limits.","type":["object","array"]},"last_invoice_date":{"format":"date-time","type":["string","null"]},"last_warning_sent":{"description":"Whether a payment warning was sent, as the database keeps it: `0` or `1`.","type":["integer","boolean"]},"next_payment_attempt":{"format":"date-time","type":["string","null"]},"plan":{"additionalProperties":true,"properties":{"billing_cycle":{"enum":["monthly","annually"],"type":"string"},"config_option":{"items":{"additionalProperties":true,"description":"One extra you can buy on top of the plan.","properties":{"id":{"description":"The `config[].type` to send to preview and checkout.","enum":["warehouse","pricing_group","user_limit","pricing_rule"],"type":"string"},"included":{"description":"How many the plan includes.","type":"integer"},"label":{"example":"Warehouse","type":"string"},"max":{"type":"integer"},"min":{"description":"The smallest `config[].value`: what the plan includes.","type":"integer"},"price":{"additionalProperties":true,"description":"The price of each extra one; `{\"type\": \"none\"}` when the plan sells none.","type":"object"},"type":{"example":"number","type":"string"}},"type":"object"},"type":["array","null"]},"configurable":{"description":"Whether extras can be added (`config_option`).","type":"boolean"},"display_features":{"description":"What the plan includes, as the pricing page lists it: rows of `{text, tooltip, has_tooltip, is_bold, is_new}`.","type":["array","object"]},"free":{"type":"boolean"},"id":{"description":"Send it as `new_plan` to preview and checkout.","example":"starter-monthly-v2","type":"string"},"is_archived":{"description":"An old plan, still listed when YoPrint gave it to your team privately.","type":"boolean"},"name":{"example":"Starter","type":"string"},"price":{"description":"The plan's price per billing cycle before extras, coupons and tax. Thousandths, an older encoding: `39000` is 39.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":39000,"type":"integer"},"trial_plan_id":{"description":"Send it as `plan_id` to choose this plan for a trial.","type":["string","null"]},"type":{"description":"`paid` for a plan you subscribe to.","example":"paid","type":"string"}},"required":["id","name","type"],"type":"object"},"price":{"description":"What each billing cycle costs, with extras. Thousandths, an older encoding: `69000` is 69.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":69000,"type":"integer"},"status":{"description":"The subscription's state at Stripe, as YoPrint last saw it.","example":"active","type":"string"},"stripe_card_brand":{"example":"Visa","type":["string","null"]},"stripe_card_last_four":{"example":"4242","type":["string","null"]},"trial_ends_at":{"format":"date-time","type":["string","null"]}},"required":["price","billing_cycle","plan","status","active"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get your YoPrint subscription","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Choose a plan with checkout.","status":422,"when":"The team has no subscription: `error.code` `no_active_plan`."},{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_plan_checkout","v1_public_setting_subscription_current_cancel"]}}},"/v1/api/store/{team_slug}/setting/subscription/current/cancel":{"patch":{"description":"**This changes what your shop pays YoPrint.** It acts on your YoPrint subscription, through Stripe, not on your customers' payments.\n\nSchedules the subscription to end at the end of the current billing period. The team keeps its plan until then, and nothing more is charged after it. Undo it before the period ends with \"Resume your YoPrint subscription\".\n\n**Billing operations.** Every change is one billing operation, named by an `operation_id` you choose: 16 to 64 letters, digits, `_` or `-`, new for each change. Keep it. The answer is the operation, as `{\"data\": {...}}` without `success` or `status`, and its HTTP status says where it stands:\n\n- `200`: done (`terminal: true`, `outcome: succeeded`). Reload the subscription.\n- `202`: still settling, or it needs a recovery. Read it again with `GET .../setting/subscription/operation/{operation_id}`, and call `.../recover` when `next_action` is `recover`.\n- `402`: the payment failed (`outcome: payment_failed`). Follow `next_action` (`use_different_card` or `update_card_then_retry`).\n- `422`: either refused before anything happened (the error envelope, with `error.code`), or the operation stopped safely (`outcome: safe_failed`, with `error_code` and `next_action`).\n- `409`: another billing operation is in progress for the team (`billing_operation_conflict`).\n- `503`: Stripe or YoPrint's billing setup can't be reached (`billing_provider_unavailable`).\n\nNever start a second change because an answer was lost or slow: read or recover the same `operation_id` instead, so you can't be charged twice.","operationId":"v1_public_setting_subscription_current_cancel","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"operation_id":"billing-lifecycle-01JZ0000000000"},"schema":{"additionalProperties":false,"properties":{"operation_id":{"pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"}},"required":["operation_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"subscription_cancel","next_action":"refresh_billing","operation_id":"billing-cancel-01JZ0000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The subscription lifecycle operation reached a successful terminal state."},"202":{"content":{"application/json":{"example":{"data":{"error_code":"provider_readback_required","kind":"subscription_cancel","next_action":"recover","operation_id":"billing-cancel-01JZ0000000000000","outcome":null,"retry_class":"reconciliation_required","state":"subscription_lifecycle_update_dispatching","terminal":false}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The subscription lifecycle operation is durable but needs exact-identity recovery."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"error":{"code":"billing_operation_conflict","message":"A different billing operation owns the team lifecycle or frozen state changed."},"status":409,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"A different billing operation owns the team lifecycle or frozen state changed."},"422":{"content":{"application/json":{"example":{"error":{"code":"subscription_not_cancellable","message":"The subscription cannot be cancelled from its current state."},"status":422,"success":false},"schema":{"oneOf":[{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"},{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}]}}},"description":"The subscription state rejected this lifecycle action or a terminal safe failure was recorded."},"503":{"content":{"application/json":{"example":{"error":{"code":"billing_provider_unavailable","message":"Billing provider configuration or readback is temporarily unavailable."},"status":503,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"Billing provider configuration or readback is temporarily unavailable."}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Cancel your YoPrint subscription","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Wait and check the current operation.","status":409,"when":"Another billing operation is in progress."},{"fix":"Reload the subscription.","status":422,"when":"The subscription can't be cancelled from its current state (`subscription_not_cancellable`), or the body has fields other than `operation_id` (`invalid_lifecycle_context`)."},{"fix":"Read the operation again later.","status":503,"when":"Billing is temporarily unavailable (`billing_provider_unavailable`)."},{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_current_resume","v1_public_setting_subscription_operation_show"],"side_effects":["Sets the subscription to cancel at the end of the period at Stripe."]}}},"/v1/api/store/{team_slug}/setting/subscription/current/resume":{"patch":{"description":"**This changes what your shop pays YoPrint.** It acts on your YoPrint subscription, through Stripe, not on your customers' payments.\n\nUndoes a scheduled cancellation, so the subscription renews and is charged as before. It works only while a cancellation is pending.\n\n**Billing operations.** Every change is one billing operation, named by an `operation_id` you choose: 16 to 64 letters, digits, `_` or `-`, new for each change. Keep it. The answer is the operation, as `{\"data\": {...}}` without `success` or `status`, and its HTTP status says where it stands:\n\n- `200`: done (`terminal: true`, `outcome: succeeded`). Reload the subscription.\n- `202`: still settling, or it needs a recovery. Read it again with `GET .../setting/subscription/operation/{operation_id}`, and call `.../recover` when `next_action` is `recover`.\n- `402`: the payment failed (`outcome: payment_failed`). Follow `next_action` (`use_different_card` or `update_card_then_retry`).\n- `422`: either refused before anything happened (the error envelope, with `error.code`), or the operation stopped safely (`outcome: safe_failed`, with `error_code` and `next_action`).\n- `409`: another billing operation is in progress for the team (`billing_operation_conflict`).\n- `503`: Stripe or YoPrint's billing setup can't be reached (`billing_provider_unavailable`).\n\nNever start a second change because an answer was lost or slow: read or recover the same `operation_id` instead, so you can't be charged twice.","operationId":"v1_public_setting_subscription_current_resume","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"operation_id":"billing-lifecycle-01JZ0000000000"},"schema":{"additionalProperties":false,"properties":{"operation_id":{"pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"}},"required":["operation_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"subscription_resume","next_action":"refresh_billing","operation_id":"billing-resume-01JZ0000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The subscription lifecycle operation reached a successful terminal state."},"202":{"content":{"application/json":{"example":{"data":{"error_code":"provider_readback_required","kind":"subscription_resume","next_action":"recover","operation_id":"billing-resume-01JZ0000000000000","outcome":null,"retry_class":"reconciliation_required","state":"subscription_lifecycle_update_dispatching","terminal":false}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The subscription lifecycle operation is durable but needs exact-identity recovery."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"error":{"code":"billing_operation_conflict","message":"A different billing operation owns the team lifecycle or frozen state changed."},"status":409,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"A different billing operation owns the team lifecycle or frozen state changed."},"422":{"content":{"application/json":{"example":{"error":{"code":"subscription_not_pending_cancel","message":"The subscription is not pending cancellation."},"status":422,"success":false},"schema":{"oneOf":[{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"},{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}]}}},"description":"The subscription state rejected this lifecycle action or a terminal safe failure was recorded."},"503":{"content":{"application/json":{"example":{"error":{"code":"billing_provider_unavailable","message":"Billing provider configuration or readback is temporarily unavailable."},"status":503,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"Billing provider configuration or readback is temporarily unavailable."}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Resume your YoPrint subscription","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Wait and check the current operation.","status":409,"when":"Another billing operation is in progress."},{"fix":"Nothing to resume.","status":422,"when":"No cancellation is pending (`subscription_not_pending_cancel`), or the body has fields other than `operation_id` (`invalid_lifecycle_context`)."},{"fix":"Read the operation again later.","status":503,"when":"Billing is temporarily unavailable (`billing_provider_unavailable`)."},{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_current_cancel"],"side_effects":["Removes the scheduled cancellation at Stripe; renewals are charged again."]}}},"/v1/api/store/{team_slug}/setting/subscription/current/retry_payment":{"post":{"description":"**This changes what your shop pays YoPrint.** It acts on your YoPrint subscription, through Stripe, not on your customers' payments.\n\nCharges the card on file for the failed renewal invoice shown by the retry preview. Send the preview's `preview_id` and a new `operation_id`; nothing else is accepted.\n\n**Billing operations.** Every change is one billing operation, named by an `operation_id` you choose: 16 to 64 letters, digits, `_` or `-`, new for each change. Keep it. The answer is the operation, as `{\"data\": {...}}` without `success` or `status`, and its HTTP status says where it stands:\n\n- `200`: done (`terminal: true`, `outcome: succeeded`). Reload the subscription.\n- `202`: still settling, or it needs a recovery. Read it again with `GET .../setting/subscription/operation/{operation_id}`, and call `.../recover` when `next_action` is `recover`.\n- `402`: the payment failed (`outcome: payment_failed`). Follow `next_action` (`use_different_card` or `update_card_then_retry`).\n- `422`: either refused before anything happened (the error envelope, with `error.code`), or the operation stopped safely (`outcome: safe_failed`, with `error_code` and `next_action`).\n- `409`: another billing operation is in progress for the team (`billing_operation_conflict`).\n- `503`: Stripe or YoPrint's billing setup can't be reached (`billing_provider_unavailable`).\n\nNever start a second change because an answer was lost or slow: read or recover the same `operation_id` instead, so you can't be charged twice.","operationId":"v1_public_setting_subscription_current_retry_payment","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"operation_id":"billing-payment-retry-01JZ0000000","preview_id":"v1.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"},"schema":{"additionalProperties":false,"properties":{"operation_id":{"pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"preview_id":{"maxLength":2048,"pattern":"^v1\\.[A-Za-z0-9_-]+\\.[a-f0-9]{64}$","type":"string"}},"required":["operation_id","preview_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The billing operation reached a successful terminal state."},"202":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The billing operation is durable but needs status or recovery follow-up."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"402":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The provider declined payment and the terminal operation records the outcome."},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"error":{"code":"billing_operation_conflict","message":"A different billing operation owns the team lifecycle or frozen state changed."},"status":409,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"A different billing operation owns the team lifecycle or frozen state changed."},"422":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"oneOf":[{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"},{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}]}}},"description":"Validation failed or a terminal safe failure was recorded."},"503":{"content":{"application/json":{"example":{"error":{"code":"billing_provider_unavailable","message":"Billing provider configuration or readback is temporarily unavailable."},"status":503,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"Billing provider configuration or readback is temporarily unavailable."}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Retry a failed YoPrint payment","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Follow `next_action`: replace the card, then retry.","status":402,"when":"The card was declined again (`outcome: payment_failed`)."},{"fix":"Wait, then read the preview again.","status":409,"when":"Another billing operation is in progress (`billing_operation_conflict`)."},{"fix":"Send only `operation_id` and `preview_id` from a fresh preview.","status":422,"when":"Refused before any charge: other fields (`invalid_payment_retry_context`), a missing or malformed `preview_id` (`validation_failed`, `payment_retry_preview_required`), or a retry limit (`payment_retry_limit_reached`, `payment_retry_rate_limited`)."},{"fix":"Read the preview again and retry with its new `preview_id` and a new `operation_id`.","status":422,"when":"The invoice, card or Stripe state changed since the preview: the operation stops safely (`outcome: safe_failed`, `error_code` such as `payment_retry_preview_changed`, `next_action: start_new_operation`). If the charge had already been sent, it answers 202 with `next_action: recover` instead."},{"fix":"Read the operation again later.","status":503,"when":"Billing is temporarily unavailable (`billing_provider_unavailable`)."},{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_current_retry_payment_preview","v1_public_setting_subscription_operation_show"],"side_effects":["Charges your card through Stripe for the open invoice."]}}},"/v1/api/store/{team_slug}/setting/subscription/current/retry_payment_preview":{"get":{"description":"Reads the open renewal invoice that failed to charge: `amount_remaining` (in cents, as Stripe counts it: `7000` is 70.00, Stripe's own unit, unlike the thousandths or decimal pairs used elsewhere in YoPrint), `currency`, the card it would charge (`card_brand`, `card_last_four`), whether you can retry now (`can_retry_now`, `retry_after`), `manual_retry_attempts_remaining`, `next_payment_attempt`, and a `preview_id`. It changes nothing.\n\nShow these to the person, then retry with the `preview_id`. If the invoice, card or Stripe state changes in between, the retry is refused with 409, so nobody is charged an amount they didn't see.","operationId":"v1_public_setting_subscription_current_retry_payment_preview","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"amount_remaining":7000,"can_retry_now":true,"card_brand":"Visa","card_last_four":"4242","currency":"usd","next_payment_attempt":"2026-08-10T14:00:00+00:00","preview_id":"v1.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","retry_after":"2026-03-21T10:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"amount_remaining":{"example":7000,"minimum":1,"type":"integer"},"can_retry_now":{"example":true,"type":"boolean"},"card_brand":{"example":"Visa","type":"string"},"card_last_four":{"example":"4242","pattern":"^[0-9]{4}$","type":"string"},"currency":{"example":"usd","pattern":"^[a-z]{3}$","type":"string"},"next_payment_attempt":{"example":"2026-08-10T14:00:00+00:00","format":"date-time","type":["string","null"]},"preview_id":{"example":"v1.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","maxLength":2048,"pattern":"^v1\\.[A-Za-z0-9_-]+\\.[a-f0-9]{64}$","type":"string"},"retry_after":{"example":null,"format":"date-time","type":["string","null"]}},"required":["amount_remaining","can_retry_now","card_brand","card_last_four","currency","next_payment_attempt","preview_id","retry_after"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"error":{"code":"payment_retry_provider_drift","message":"The canonical renewal invoice, card, or provider state changed."},"status":409,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"The canonical renewal invoice, card, or provider state changed."},"422":{"content":{"application/json":{"example":{"error":{"code":"payment_retry_not_required","message":"No exact open renewal invoice is eligible for manual retry."},"status":422,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"No exact open renewal invoice is eligible for manual retry."},"503":{"content":{"application/json":{"example":{"error":{"code":"billing_provider_unavailable","message":"Billing provider configuration or readback is temporarily unavailable."},"status":503,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"Billing provider configuration or readback is temporarily unavailable."}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Check a failed YoPrint payment before retrying","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Nothing to pay.","status":422,"when":"No failed renewal invoice can be retried (`payment_retry_not_required`), or the team has no subscription (`no_active_plan`)."},{"fix":"Read the preview again.","status":409,"when":"The invoice, card or Stripe state changed while it was read (for example `payment_retry_provider_drift`)."},{"fix":"Try again later.","status":503,"when":"Billing is temporarily unavailable (`billing_provider_unavailable`)."},{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_current_retry_payment"]}}},"/v1/api/store/{team_slug}/setting/subscription/current/update_card":{"put":{"description":"**This changes what your shop pays YoPrint.** It acts on your YoPrint subscription, through Stripe, not on your customers' payments.\n\nReplaces the card YoPrint charges for your subscription. Send a Stripe card token (`stripe_token`, `tok_...`, made with Stripe.js) and a new `operation_id`. To change the plan and the card together, use checkout with `payment_method: replacement` instead: one request, not two.\n\n**Billing operations.** Every change is one billing operation, named by an `operation_id` you choose: 16 to 64 letters, digits, `_` or `-`, new for each change. Keep it. The answer is the operation, as `{\"data\": {...}}` without `success` or `status`, and its HTTP status says where it stands:\n\n- `200`: done (`terminal: true`, `outcome: succeeded`). Reload the subscription.\n- `202`: still settling, or it needs a recovery. Read it again with `GET .../setting/subscription/operation/{operation_id}`, and call `.../recover` when `next_action` is `recover`.\n- `402`: the payment failed (`outcome: payment_failed`). Follow `next_action` (`use_different_card` or `update_card_then_retry`).\n- `422`: either refused before anything happened (the error envelope, with `error.code`), or the operation stopped safely (`outcome: safe_failed`, with `error_code` and `next_action`).\n- `409`: another billing operation is in progress for the team (`billing_operation_conflict`).\n- `503`: Stripe or YoPrint's billing setup can't be reached (`billing_provider_unavailable`).\n\nNever start a second change because an answer was lost or slow: read or recover the same `operation_id` instead, so you can't be charged twice.","operationId":"v1_public_setting_subscription_current_update_card","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"operation_id":"billing-card-01JZ000000000000000","stripe_token":"tok_test_example"},"schema":{"additionalProperties":false,"properties":{"operation_id":{"pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"stripe_token":{"pattern":"^tok_[A-Za-z0-9_]{3,187}$","type":"string"}},"required":["operation_id","stripe_token"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The billing operation reached a successful terminal state."},"202":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The billing operation is durable but needs status or recovery follow-up."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"402":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The provider declined payment and the terminal operation records the outcome."},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"error":{"code":"billing_operation_conflict","message":"A different billing operation owns the team lifecycle or frozen state changed."},"status":409,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"A different billing operation owns the team lifecycle or frozen state changed."},"422":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"oneOf":[{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"},{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}]}}},"description":"Validation failed or a terminal safe failure was recorded."},"503":{"content":{"application/json":{"example":{"error":{"code":"billing_provider_unavailable","message":"Billing provider configuration or readback is temporarily unavailable."},"status":503,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"Billing provider configuration or readback is temporarily unavailable."}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Replace the card for your YoPrint subscription","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Use another card.","status":422,"when":"Stripe declined or rejected the card: `error.code` is Stripe's decline code (for example `card_declined`) or `payment_method_rejected`. A card change never answers 402."},{"fix":"Wait and check the current operation.","status":409,"when":"Another billing operation is in progress (`billing_operation_conflict`)."},{"fix":"Send only `operation_id` and `stripe_token`.","status":422,"when":"The body has other fields (`invalid_card_update_context`), or the token is missing or malformed (`validation_failed`)."},{"fix":"Read the operation again later.","status":503,"when":"Billing is temporarily unavailable (`billing_provider_unavailable`)."},{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_operation_show","v1_public_setting_subscription_plan_checkout"],"side_effects":["Saves the new card at Stripe as the subscription's payment method."]}}},"/v1/api/store/{team_slug}/setting/subscription/invoice":{"get":{"description":"Returns the invoices YoPrint has billed your team for its subscription, newest first, a page at a time (the team's page size, 50 by default). These are YoPrint's invoices to you, not invoices to your customers.","operationId":"v1_public_setting_subscription_invoice_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"created_at":"2026-10-01T00:00:05+00:00","currency":"usd","id":"6A5fjbVPF0RlMd","pdf_url":"https://example.com/yoprint-invoice.pdf","provider_created_at":"2026-10-01T00:00:00+00:00","tax":0,"total":69000}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"created_at":{"format":"date-time","type":["string","null"]},"currency":{"example":"usd","type":["string","null"]},"id":{"type":"string"},"pdf_url":{"description":"A short-lived link to the PDF. It carries a download token: treat it as private.","format":"uri","type":"string"},"provider_created_at":{"description":"When Stripe created it.","format":"date-time","type":["string","null"]},"tax":{"description":"Tax. Thousandths, an older encoding: `5000` is 5.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number"]},"total":{"description":"The invoice total. Thousandths, an older encoding: `69000` is 69.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number"]}},"required":["id","tax","total","currency","pdf_url"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List your YoPrint invoices","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_current_show"]}}},"/v1/api/store/{team_slug}/setting/subscription/operation/current":{"get":{"description":"Returns the team's billing operation that hasn't finished, as `operation`, or `operation: null` when there is none. Check it before starting a change, and after an answer was lost. It changes nothing.","operationId":"v1_public_setting_subscription_operation_current","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"operation":{"error_code":"provider_readback_required","kind":"checkout_swap","next_action":"recover","operation_id":"billing-checkout-01JZ000000000000","outcome":null,"retry_class":"reconciliation_required","state":"subscription_update_dispatching","terminal":false}},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"operation":{"oneOf":[{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},{"type":"null"}]}},"required":["operation"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get the unfinished YoPrint billing operation","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_operation_show","v1_public_setting_subscription_operation_recover"]}}},"/v1/api/store/{team_slug}/setting/subscription/operation/{operation_id}":{"get":{"description":"Returns one billing operation by the `operation_id` you chose: its `kind`, `state`, whether it is `terminal`, its `outcome` and the `next_action` to take. It changes nothing.\n\n`next_action`: `refresh_billing` (done, reload), `wait` (still running, read again), `recover` (call recover), `use_different_card`, `update_card_then_retry`, or `start_new_operation`.","operationId":"v1_public_setting_subscription_operation_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The `operation_id` you chose when you started the change: 16 to 64 letters, digits, `_` or `-`. Not a hash id.","example":"billing-checkout-01JZ000000000000","in":"path","name":"operation_id","required":true,"schema":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_swap","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a YoPrint billing operation","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Use the `operation_id` you sent.","status":404,"when":"No operation of your team has this id (`billing_operation_not_found`). `error.code` is null; `error.message` names the record type."},{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_operation_recover","v1_public_setting_subscription_operation_current"]}}},"/v1/api/store/{team_slug}/setting/subscription/operation/{operation_id}/recover":{"post":{"description":"Finishes a billing operation whose `next_action` is `recover`: YoPrint reads Stripe and settles the operation to match. It never repeats a step Stripe already accepted, so it can't charge twice. Safe to call again. Returns the operation.","operationId":"v1_public_setting_subscription_operation_recover","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The `operation_id` you chose when you started the change: 16 to 64 letters, digits, `_` or `-`. Not a hash id.","example":"billing-checkout-01JZ000000000000","in":"path","name":"operation_id","required":true,"schema":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The billing operation reached a successful terminal state."},"202":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The billing operation is durable but needs status or recovery follow-up."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"402":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The provider declined payment and the terminal operation records the outcome."},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"error":{"code":"billing_operation_conflict","message":"A different billing operation owns the team lifecycle or frozen state changed."},"status":409,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"A different billing operation owns the team lifecycle or frozen state changed."},"422":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"oneOf":[{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"},{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}]}}},"description":"Validation failed or a terminal safe failure was recorded."},"503":{"content":{"application/json":{"example":{"error":{"code":"billing_provider_unavailable","message":"Billing provider configuration or readback is temporarily unavailable."},"status":503,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"Billing provider configuration or readback is temporarily unavailable."}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Recover a YoPrint billing operation","tags":["YoPrint subscription"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Use the `operation_id` you sent.","status":404,"when":"No operation of your team has this id (`billing_operation_not_found`). `error.code` is null; `error.message` names the record type."},{"fix":"Wait and read the operation again.","status":409,"when":"Another billing operation is in progress (`billing_operation_conflict`)."},{"fix":"Try again later; recover is safe to repeat.","status":503,"when":"Billing is temporarily unavailable (`billing_provider_unavailable`), or the result couldn't be confirmed (`billing_recovery_result_unknown`)."},{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_operation_show"],"side_effects":["Reads from Stripe and may complete the change the operation started."]}}},"/v1/api/store/{team_slug}/setting/subscription/plan":{"get":{"description":"Returns the YoPrint plans your team can subscribe to, including any private plan YoPrint gave your team: each with its `id`, `name`, `billing_cycle`, `price`, features, the extras you can configure (`config_option`), and the `trial_plan_id` to use during a trial.\n\nReading it changes nothing.","operationId":"v1_public_setting_subscription_plan_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"billing_cycle":"monthly","config_option":[{"id":"user_limit","included":3,"label":"Users","max":100,"min":3,"price":{"type":"none"},"type":"number"}],"configurable":true,"display_features":[{"has_tooltip":false,"is_bold":true,"is_new":false,"text":"3 Users Included","tooltip":""}],"free":false,"id":"starter-monthly-v2","is_archived":false,"name":"Starter","price":39000,"trial_plan_id":"starter-trial","type":"paid"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"billing_cycle":{"enum":["monthly","annually"],"type":"string"},"config_option":{"items":{"additionalProperties":true,"description":"One extra you can buy on top of the plan.","properties":{"id":{"description":"The `config[].type` to send to preview and checkout.","enum":["warehouse","pricing_group","user_limit","pricing_rule"],"type":"string"},"included":{"description":"How many the plan includes.","type":"integer"},"label":{"example":"Warehouse","type":"string"},"max":{"type":"integer"},"min":{"description":"The smallest `config[].value`: what the plan includes.","type":"integer"},"price":{"additionalProperties":true,"description":"The price of each extra one; `{\"type\": \"none\"}` when the plan sells none.","type":"object"},"type":{"example":"number","type":"string"}},"type":"object"},"type":["array","null"]},"configurable":{"description":"Whether extras can be added (`config_option`).","type":"boolean"},"display_features":{"description":"What the plan includes, as the pricing page lists it: rows of `{text, tooltip, has_tooltip, is_bold, is_new}`.","type":["array","object"]},"free":{"type":"boolean"},"id":{"description":"Send it as `new_plan` to preview and checkout.","example":"starter-monthly-v2","type":"string"},"is_archived":{"description":"An old plan, still listed when YoPrint gave it to your team privately.","type":"boolean"},"name":{"example":"Starter","type":"string"},"price":{"description":"The plan's price per billing cycle before extras, coupons and tax. Thousandths, an older encoding: `39000` is 39.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":39000,"type":"integer"},"trial_plan_id":{"description":"Send it as `plan_id` to choose this plan for a trial.","type":["string","null"]},"type":{"description":"`paid` for a plan you subscribe to.","example":"paid","type":"string"}},"required":["id","name","type"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List YoPrint plans you can choose","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_plan_preview","v1_public_setting_subscription_plan_checkout","v1_public_setting_subscription_plan_select_trial"]}}},"/v1/api/store/{team_slug}/setting/subscription/plan/checkout":{"post":{"description":"**This changes what your shop pays YoPrint.** It acts on your YoPrint subscription, through Stripe, not on your customers' payments.\n\nSubscribes the team to a plan, or changes its plan or paid extras. Stripe charges the card for what the change costs; preview it first. Send `payment_method: current` to use the card on file, or `replacement` with a Stripe card token (`stripe_token`, `tok_...`, made with Stripe.js in the browser). Card numbers never go to YoPrint.\n\n**Billing operations.** Every change is one billing operation, named by an `operation_id` you choose: 16 to 64 letters, digits, `_` or `-`, new for each change. Keep it. The answer is the operation, as `{\"data\": {...}}` without `success` or `status`, and its HTTP status says where it stands:\n\n- `200`: done (`terminal: true`, `outcome: succeeded`). Reload the subscription.\n- `202`: still settling, or it needs a recovery. Read it again with `GET .../setting/subscription/operation/{operation_id}`, and call `.../recover` when `next_action` is `recover`.\n- `402`: the payment failed (`outcome: payment_failed`). Follow `next_action` (`use_different_card` or `update_card_then_retry`).\n- `422`: either refused before anything happened (the error envelope, with `error.code`), or the operation stopped safely (`outcome: safe_failed`, with `error_code` and `next_action`).\n- `409`: another billing operation is in progress for the team (`billing_operation_conflict`).\n- `503`: Stripe or YoPrint's billing setup can't be reached (`billing_provider_unavailable`).\n\nNever start a second change because an answer was lost or slow: read or recover the same `operation_id` instead, so you can't be charged twice.","operationId":"v1_public_setting_subscription_plan_checkout","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"config":[],"new_plan":"starter-monthly-v2","operation_id":"billing-checkout-01JZ000000000000","payment_method":"replacement","stripe_token":"tok_test_example"},"schema":{"additionalProperties":false,"properties":{"config":{"items":{"additionalProperties":false,"properties":{"type":{"enum":["warehouse","pricing_group","user_limit","pricing_rule"],"type":"string"},"value":{"maximum":1000000,"minimum":0,"type":"integer"}},"required":["type","value"],"type":"object"},"maxItems":4,"type":"array"},"coupon":{"maxLength":191,"type":"string"},"coupon_token":{"maxLength":4096,"type":"string"},"new_plan":{"maxLength":191,"type":"string"},"operation_id":{"pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"payment_method":{"enum":["current","replacement"],"type":"string"},"referral_id":{"maxLength":191,"type":"string"},"stripe_token":{"pattern":"^tok_[A-Za-z0-9_]{3,187}$","type":"string"}},"required":["operation_id","payment_method","new_plan"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The billing operation reached a successful terminal state."},"202":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The billing operation is durable but needs status or recovery follow-up."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"402":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"}}},"description":"The provider declined payment and the terminal operation records the outcome."},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"error":{"code":"billing_operation_conflict","message":"A different billing operation owns the team lifecycle or frozen state changed."},"status":409,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"A different billing operation owns the team lifecycle or frozen state changed."},"422":{"content":{"application/json":{"example":{"data":{"error_code":null,"kind":"checkout_create","next_action":"refresh_billing","operation_id":"billing-checkout-01JZ000000000000","outcome":"succeeded","retry_class":null,"state":"settled","terminal":true}},"schema":{"oneOf":[{"additionalProperties":false,"properties":{"data":{"additionalProperties":false,"properties":{"error_code":{"example":null,"pattern":"^[a-z0-9_:-]{1,64}$","type":["string","null"]},"kind":{"enum":["card_prepare","checkout_create","checkout_swap","payment_retry","subscription_cancel","subscription_resume"],"type":"string"},"next_action":{"enum":["recover","refresh_billing","start_new_operation","update_card_then_retry","use_different_card","wait"],"type":"string"},"operation_id":{"example":"billing-checkout-01JZ000000000000","pattern":"^[A-Za-z0-9_-]{16,64}$","type":"string"},"outcome":{"enum":["succeeded","payment_failed","safe_failed",null],"type":["string","null"]},"retry_class":{"enum":["safe","compensated","provider_retry","reconciliation_required",null],"type":["string","null"]},"state":{"example":"settled","type":"string"},"terminal":{"example":true,"type":"boolean"}},"required":["operation_id","kind","state","terminal","outcome","retry_class","error_code","next_action"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["data"],"type":"object"},{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}]}}},"description":"Validation failed or a terminal safe failure was recorded."},"503":{"content":{"application/json":{"example":{"error":{"code":"billing_provider_unavailable","message":"Billing provider configuration or readback is temporarily unavailable."},"status":503,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"Billing provider configuration or readback is temporarily unavailable."}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Subscribe to or change your YoPrint plan","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Follow `next_action`: `use_different_card` for a new subscription, `update_card_then_retry` for a plan change.","status":402,"when":"The first invoice wasn't paid (`outcome: payment_failed`)."},{"fix":"Wait, check the current operation, then try again with a new `operation_id`.","status":409,"when":"Another billing operation is in progress, or billing changed meanwhile (`billing_operation_conflict`)."},{"fix":"Read `error.code`.","status":422,"when":"An extra field or a token with `current` (`invalid_payment_method`), a bad `config` (`invalid_plan_config`), a missing field (`validation_failed`), the plan not available to you, or Stripe declined or rejected the card (`error.code` is Stripe's decline code, or `payment_method_rejected`)."},{"fix":"Read the operation again later; don't start a new one.","status":503,"when":"Billing is temporarily unavailable (`billing_provider_unavailable`)."},{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_plan_preview","v1_public_setting_subscription_operation_show","v1_public_setting_subscription_operation_recover"],"rules":["Only the listed fields are accepted; anything else is refused before any charge.","`stripe_token` is required with `replacement` and not allowed with `current`.","Preview the change first to see what will be charged."],"side_effects":["Charges your card through Stripe and changes your YoPrint plan, limits and features."]}}},"/v1/api/store/{team_slug}/setting/subscription/plan/preview":{"put":{"description":"Shows what a plan change would cost before you make it: `amount_due` now and the `ending_balance`, as Stripe calculates them, in thousandths (`69000` is 69.00; see [Money and quantities](/concepts/money-and-quantities/)). It changes nothing.\n\nIt works only for a team that already has a subscription; otherwise you get 422 `preview_not_available`. Send only `new_plan`, `config`, `coupon` and `coupon_token`; any other field is refused.","operationId":"v1_public_setting_subscription_plan_preview","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"config":[],"new_plan":"starter-monthly-v2"},"schema":{"additionalProperties":false,"properties":{"config":{"items":{"additionalProperties":false,"properties":{"type":{"enum":["warehouse","pricing_group","user_limit","pricing_rule"],"type":"string"},"value":{"maximum":1000000,"minimum":0,"type":"integer"}},"required":["type","value"],"type":"object"},"maxItems":4,"type":"array"},"coupon":{"maxLength":191,"type":"string"},"coupon_token":{"maxLength":4096,"type":"string"},"new_plan":{"maxLength":191,"type":"string"}},"required":["new_plan"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"amount_due":69000,"ending_balance":0},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"amount_due":{"example":69000,"minimum":0,"type":"integer"},"ending_balance":{"example":0,"type":["integer","null"]}},"required":["amount_due","ending_balance"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"content":{"application/json":{"example":{"error":{"code":"invalid_plan","message":"The requested plan preview is invalid or unavailable for this team."},"status":422,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"The requested plan preview is invalid or unavailable for this team."},"503":{"content":{"application/json":{"example":{"error":{"code":"billing_provider_unavailable","message":"Billing provider configuration or readback is temporarily unavailable."},"status":503,"success":false},"schema":{"additionalProperties":true,"properties":{"error":{"additionalProperties":true,"properties":{"code":{"example":"invalid_plan","type":"string"},"fields":{"additionalProperties":true,"type":["object","null"]},"message":{"example":"Selected plan is not valid.","type":"string"}},"required":["code","message"],"type":"object"},"status":{"example":422,"type":"integer"},"success":{"example":false,"type":"boolean"}},"required":["success","status","error"],"type":"object"}}},"description":"Billing provider configuration or readback is temporarily unavailable."}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Preview a YoPrint plan change","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Read `error.code`.","status":422,"when":"An extra field (`invalid_plan_preview_context`), a bad `config` (`invalid_plan_config`), an unknown or unavailable plan (`invalid_plan`), a bad coupon (`invalid_coupon`), no subscription to change (`preview_not_available`), or a missing field (`validation_failed`)."},{"fix":"Try again later.","status":503,"when":"Billing is temporarily unavailable (`billing_provider_unavailable`)."},{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_plan_checkout","v1_public_setting_subscription_check_coupon"],"rules":["`config` lists the paid extras, each `{type, value}` with `type` `warehouse`, `pricing_group`, `user_limit` or `pricing_rule`, once each, within the plan's limits.","A `coupon` needs the `coupon_token` from \"Check a YoPrint coupon\"."]}}},"/v1/api/store/{team_slug}/setting/subscription/plan/select_trial":{"post":{"description":"Sets which plan's features the team gets during its free trial. Send a `trial_plan_id` from the plan list. It charges nothing.\n\nIt works only while the team can still trial: its trial hasn't ended and it has no subscription. Returns your company details.","operationId":"v1_public_setting_subscription_plan_select_trial","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"plan_id":"starter-trial"},"schema":{"additionalProperties":false,"properties":{"plan_id":{"description":"A `trial_plan_id` from the plan list.","maxLength":191,"type":"string"}},"required":["plan_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"channel_id":1001,"custom_domain":"shop.example.com","customer_portal_bg":null,"dimension":"in","email":"alex@example.com","favicon_url":null,"ga_id":"YxPx1001","id":"OutVLW14xRJYLp","logo_url":"https://example.com/logo.png","name":"Northwind Apparel","onboard_status":null,"payment_gateway":[],"phone":"+1 201 555 0123","phone_country":"US","plan":{"active":true,"detail":{"archive":false,"expire_at":"2026-11-17T00:00:00+00:00","id":"starter-trial","name":"Starter Trial","need_to_select_plan":false,"status":"active"},"features":{"user_limit":3},"type":"trial"},"plan_region":"US","printavo_importer_available":false,"printavo_importer_enabled":false,"seeded":true,"slug":"your-team","tax_number":null,"timezone":"America/New_York","trial_expires_at":"2026-01-15T00:00:00+00:00","website":"https://example.com","weight":"lbs"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"channel_id":{"description":"The team's number, used by YoPrint's live-update channel.","type":"integer"},"custom_domain":{"description":"The host your customer portal is served on, or null.","type":["string","null"]},"customer_portal_bg":{"description":"The customer portal background image, or null.","type":["string","null"]},"dimension":{"description":"Length unit: `m`, `cm`, `mm` or `in`.","type":["string","null"]},"email":{"type":["string","null"]},"favicon_url":{"description":"The customer portal favicon (the icon in the browser tab), or null when none is uploaded.","type":["string","null"]},"ga_id":{"description":"An analytics id: `YxPx` and the team's number (`channel_id`).","example":"YxPx1001","type":"string"},"id":{"example":"OutVLW14xRJYLp","type":"string"},"logo_url":{"type":["string","null"]},"name":{"example":"Northwind Apparel","type":"string"},"onboard_status":{"type":["string","null"]},"payment_gateway":{"description":"The payment gateways your customers can pay through, with only their public identifiers (for example a Stripe publishable key). Empty when the plan has no payment integration.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"plan":{"additionalProperties":false,"description":"The team's YoPrint plan.","properties":{"active":{"description":"Whether the plan is active now.","type":"boolean"},"detail":{"additionalProperties":true,"description":"With a subscription: `name`, `status`, `active` and `need_to_select_plan`. On a trial or free plan: `id`, `name`, `archive`, `need_to_select_plan`, and on a trial `expire_at` and `status` (`active` or `expired`).","properties":{"active":{"type":"boolean"},"archive":{"type":"boolean"},"expire_at":{"format":"date-time","type":["string","null"]},"id":{"type":"string"},"name":{"description":"With a subscription, always `default`; otherwise the trial or free plan's name.","type":["string","null"]},"need_to_select_plan":{"description":"True when the team must choose a plan before it can go on.","type":"boolean"},"status":{"type":["string","null"]}},"type":"object"},"features":{"additionalProperties":true,"description":"What the plan allows: features, limits and integrations, keyed by name.","type":"object"},"type":{"description":"`paid` with a subscription; otherwise `trial` or `free`.","enum":["paid","trial","free"],"type":"string"}},"required":["type","active","detail","features"],"type":"object"},"plan_region":{"type":["string","null"]},"printavo_importer_available":{"type":"boolean"},"printavo_importer_enabled":{"type":"boolean"},"seeded":{"type":"boolean"},"slug":{"description":"The `{team_slug}` in every path.","example":"your-team","type":"string"},"tax_number":{"type":["string","null"]},"timezone":{"example":"America/New_York","type":"string"},"trial_expires_at":{"format":"date-time","type":"string"},"website":{"type":["string","null"]},"weight":{"description":"Weight unit: `kg`, `g`, `lbs` or `oz`.","type":["string","null"]}},"required":["id","name","slug","timezone","custom_domain","payment_gateway","plan"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Choose the plan for your free trial","tags":["YoPrint subscription"],"x-yoprint-docs":{"errors":[{"fix":"Use a `trial_plan_id` from the plan list, or subscribe with checkout.","status":422,"when":"The plan is not a trial plan you can choose, or the team can no longer trial: `error.code` `invalid_plan`. A missing `plan_id` is `validation_failed`."},{"fix":"Use the owner's key, or that of a member with Manage Billing.","status":403,"when":"You are not the owner and your role lacks Manage Billing. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","notes":["Part of your YoPrint subscription: what your shop pays YoPrint, not your customers' payments.","AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"The team owner, or a member with the Manage Billing permission. Manage Settings alone is not enough.","related":["v1_public_setting_subscription_plan_index"],"side_effects":["Changes which features the team has during the trial."]}}},"/v1/api/store/{team_slug}/setting/tax_type":{"get":{"description":"Returns all the team's tax presets in one list, including deleted ones (`trashed: true`) and YoPrint's `system` presets, such as Auto Tax.\n\nTax presets are the taxes you apply to invoices. When YoPrint creates an invoice for you, it applies the default preset; on invoices you build yourself, you choose the tax. An invoice stores the rate it used, so changing or deleting a preset doesn't change existing invoices.\n\nUse the `default` preset when you need the team's usual tax. Skip presets with `trashed: true`.","operationId":"v1_public_custom_tax_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"apply_before_disc":false,"can_override_rates":false,"can_override_rules":false,"default":true,"enable":true,"error":"","hidden":false,"id":"kazdbC5ICA0kV0","line_taxes":[],"name":"State sales tax","override_rates":[],"override_rules":[],"secondary_type":null,"shipping_taxable":true,"supported_place":[],"total":6000,"trashed":false,"type":"simple"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"apply_before_disc":{"description":"Whether tax is calculated before the discount (Calculate Taxes Before Discount). Normally false: tax comes after the discount.","example":false,"type":"boolean"},"can_override_rates":{"example":false,"type":"boolean"},"can_override_rules":{"example":false,"type":"boolean"},"default":{"description":"Whether it is the team's default tax preset. At most one preset is the default.","example":true,"type":"boolean"},"enable":{"example":true,"type":"boolean"},"error":{"example":"","type":"string"},"hidden":{"example":false,"type":"boolean"},"id":{"example":"kazdbC5ICA0kV0","type":"string"},"line_taxes":{"description":"The parts of a `line_tax` preset, as they were sent. Empty for the others.","example":[],"items":{"properties":{"name":{"description":"The part's name, such as `State` or `County`.","example":"State","type":"string"},"total":{"description":"The part's rate. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":6000,"minimum":0,"type":"integer"}},"required":["name","total"],"type":"object"},"type":"array"},"name":{"example":"State sales tax","type":"string"},"override_rates":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"override_rules":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"secondary_type":{"description":"For `system` presets, which one: `auto` is Auto Tax, YoPrint's automatic US sales tax; `other` is a 0% preset some teams have, whose `name` always reads Tax Exempt. Null for your own presets.","example":null,"type":["string","null"]},"shipping_taxable":{"description":"Whether shipping is taxed (Tax Shipping).","example":true,"type":"boolean"},"supported_place":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"total":{"description":"The rate. For `line_tax`, the sum of the parts. Auto Tax shows 0: its rate is looked up per invoice. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":6000,"minimum":0,"type":"integer"},"trashed":{"description":"True for a deleted preset. Restore it with Restore a tax preset.","example":false,"type":"boolean"},"type":{"description":"`simple` (Single Line Tax): one rate. `line_tax` (Multi Line Tax): parts that add up. `system`: made by YoPrint, such as Auto Tax.","enum":["simple","line_tax","system"],"example":"simple","type":"string"}},"required":["id","type","secondary_type","name","total","shipping_taxable","apply_before_disc","enable","default","line_taxes","trashed"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List tax presets","tags":["Tax presets"],"x-yoprint-docs":{"group":"Team settings","notes":["Rates are a percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","Auto Tax (`type` `system`, `secondary_type` `auto`) is available to US-plan teams with the feature. Its rate is looked up for each invoice from the address, so `total` is 0."],"permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_custom_tax_store","v2_public_invoice_tax_selection_update"]}},"post":{"description":"Creates a tax preset and returns it. A `simple` preset (Single Line Tax) has one rate. A `line_tax` preset (Multi Line Tax) has up to 8 named parts, such as state, county and city, and its rate is their sum.\n\nThe new preset becomes the team default when you send `default: true`, or when the team has no default yet.\n\nTax presets are the taxes you apply to invoices. When YoPrint creates an invoice for you, it applies the default preset; on invoices you build yourself, you choose the tax. An invoice stores the rate it used, so changing or deleting a preset doesn't change existing invoices.","operationId":"v1_public_custom_tax_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"line_tax":{"summary":"State plus county","value":{"default":true,"line_taxes":[{"name":"State","total":6000},{"name":"County","total":2250}],"name":"State and county","type":"line_tax"},"x-yoprint-variant":"Multi Line Tax"},"simple":{"summary":"A 6% state tax","value":{"name":"State sales tax","shipping_taxable":false,"total":6000,"type":"simple"},"x-yoprint-variant":"Single Line Tax"}},"schema":{"discriminator":{"mapping":{"line_tax":"#/components/schemas/MultiLineTax","simple":"#/components/schemas/SingleLineTax"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/SingleLineTax"},{"$ref":"#/components/schemas/MultiLineTax"}],"title":"What kind of tax?"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"apply_before_disc":false,"can_override_rates":false,"can_override_rules":false,"default":false,"enable":true,"error":"","hidden":false,"id":"Pn8oyZYD9l6qP7","line_taxes":[],"name":"State sales tax","override_rates":[],"override_rules":[],"secondary_type":null,"shipping_taxable":false,"supported_place":[],"total":6000,"trashed":false,"type":"simple"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"apply_before_disc":{"description":"Whether tax is calculated before the discount (Calculate Taxes Before Discount). Normally false: tax comes after the discount.","example":false,"type":"boolean"},"can_override_rates":{"example":false,"type":"boolean"},"can_override_rules":{"example":false,"type":"boolean"},"default":{"description":"Whether it is the team's default tax preset. At most one preset is the default.","example":true,"type":"boolean"},"enable":{"example":true,"type":"boolean"},"error":{"example":"","type":"string"},"hidden":{"example":false,"type":"boolean"},"id":{"example":"kazdbC5ICA0kV0","type":"string"},"line_taxes":{"description":"The parts of a `line_tax` preset, as they were sent. Empty for the others.","example":[],"items":{"properties":{"name":{"description":"The part's name, such as `State` or `County`.","example":"State","type":"string"},"total":{"description":"The part's rate. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":6000,"minimum":0,"type":"integer"}},"required":["name","total"],"type":"object"},"type":"array"},"name":{"example":"State sales tax","type":"string"},"override_rates":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"override_rules":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"secondary_type":{"description":"For `system` presets, which one: `auto` is Auto Tax, YoPrint's automatic US sales tax; `other` is a 0% preset some teams have, whose `name` always reads Tax Exempt. Null for your own presets.","example":null,"type":["string","null"]},"shipping_taxable":{"description":"Whether shipping is taxed (Tax Shipping).","example":true,"type":"boolean"},"supported_place":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"total":{"description":"The rate. For `line_tax`, the sum of the parts. Auto Tax shows 0: its rate is looked up per invoice. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":6000,"minimum":0,"type":"integer"},"trashed":{"description":"True for a deleted preset. Restore it with Restore a tax preset.","example":false,"type":"boolean"},"type":{"description":"`simple` (Single Line Tax): one rate. `line_tax` (Multi Line Tax): parts that add up. `system`: made by YoPrint, such as Auto Tax.","enum":["simple","line_tax","system"],"example":"simple","type":"string"}},"required":["id","type","secondary_type","name","total","shipping_taxable","apply_before_disc","enable","default","line_taxes","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a tax preset","tags":["Tax presets"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`type` is missing or not `simple` or `line_tax`, a rate is not a whole number of 0 or more, or `line_taxes` has no parts or more than 8. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."},{"fix":"Check the individual rates: they are a percentage ×1000 (`8250` is 8.25%).","status":422,"when":"The parts of a `line_tax` preset add up to more than YoPrint can store (`error.code` `amount_out_of_range`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_custom_tax_index","v1_public_custom_tax_update_patch"],"rules":["`type` is `simple` or `line_tax`. `system` presets are made by YoPrint and cannot be created.","Rates are whole numbers, 0 or more, as a percentage ×1000: `8250` is 8.25%.","A `line_tax` preset needs 1 to 8 parts, each with a `name` and a `total`. A `total` sent with a `line_tax` preset is ignored.","The type cannot be changed later."],"side_effects":["With `default: true`, or when the team had no default, it becomes the default, and new invoices YoPrint creates use it."]}}},"/v1/api/store/{team_slug}/setting/tax_type/{hash_id}":{"delete":{"description":"Deletes a tax preset. It stays in the list with `trashed: true` and can be restored. Invoices that used it keep their tax.","operationId":"v1_public_custom_tax_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The tax preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"kazdbC5ICA0kV0","in":"path","name":"hash_id","required":true,"schema":{"example":"kazdbC5ICA0kV0","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a tax preset","tags":["Tax presets"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No tax preset with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Make another preset the default first. System presets stay.","status":500,"when":"The preset is the default, or a `system` preset (`error.code` is `delete_fail`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_tax_type_restore"],"rules":["The default preset and YoPrint's `system` presets cannot be deleted."]}},"get":{"description":"Returns one tax preset, deleted or not.","operationId":"v1_public_custom_tax_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The tax preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"kazdbC5ICA0kV0","in":"path","name":"hash_id","required":true,"schema":{"example":"kazdbC5ICA0kV0","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"apply_before_disc":false,"can_override_rates":false,"can_override_rules":false,"default":true,"enable":true,"error":"","hidden":false,"id":"kazdbC5ICA0kV0","line_taxes":[],"name":"State sales tax","override_rates":[],"override_rules":[],"secondary_type":null,"shipping_taxable":true,"supported_place":[],"total":6000,"trashed":false,"type":"simple"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"apply_before_disc":{"description":"Whether tax is calculated before the discount (Calculate Taxes Before Discount). Normally false: tax comes after the discount.","example":false,"type":"boolean"},"can_override_rates":{"example":false,"type":"boolean"},"can_override_rules":{"example":false,"type":"boolean"},"default":{"description":"Whether it is the team's default tax preset. At most one preset is the default.","example":true,"type":"boolean"},"enable":{"example":true,"type":"boolean"},"error":{"example":"","type":"string"},"hidden":{"example":false,"type":"boolean"},"id":{"example":"kazdbC5ICA0kV0","type":"string"},"line_taxes":{"description":"The parts of a `line_tax` preset, as they were sent. Empty for the others.","example":[],"items":{"properties":{"name":{"description":"The part's name, such as `State` or `County`.","example":"State","type":"string"},"total":{"description":"The part's rate. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":6000,"minimum":0,"type":"integer"}},"required":["name","total"],"type":"object"},"type":"array"},"name":{"example":"State sales tax","type":"string"},"override_rates":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"override_rules":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"secondary_type":{"description":"For `system` presets, which one: `auto` is Auto Tax, YoPrint's automatic US sales tax; `other` is a 0% preset some teams have, whose `name` always reads Tax Exempt. Null for your own presets.","example":null,"type":["string","null"]},"shipping_taxable":{"description":"Whether shipping is taxed (Tax Shipping).","example":true,"type":"boolean"},"supported_place":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"total":{"description":"The rate. For `line_tax`, the sum of the parts. Auto Tax shows 0: its rate is looked up per invoice. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":6000,"minimum":0,"type":"integer"},"trashed":{"description":"True for a deleted preset. Restore it with Restore a tax preset.","example":false,"type":"boolean"},"type":{"description":"`simple` (Single Line Tax): one rate. `line_tax` (Multi Line Tax): parts that add up. `system`: made by YoPrint, such as Auto Tax.","enum":["simple","line_tax","system"],"example":"simple","type":"string"}},"required":["id","type","secondary_type","name","total","shipping_taxable","apply_before_disc","enable","default","line_taxes","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show a tax preset","tags":["Tax presets"],"x-yoprint-docs":{"group":"Team settings","permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_custom_tax_update_patch"]}},"patch":{"description":"The same as PUT: changes a tax preset, with the same validation, and returns it.\n\nChanges a tax preset and returns it. Send only the fields to change.\n\n- `simple`: `name`, `total`, `shipping_taxable`, `apply_before_disc`, `enable`, `default`.\n- `line_tax`: the same, with `line_taxes` instead of `total`.\n- `system` presets: only `name` and `default`; for Auto Tax, only `default`. The Tax Exempt preset (`secondary_type` `other`) saves a new `name` but keeps showing Tax Exempt.\n\n`default: true` makes it the team default. The type can't be changed. Existing invoices keep the rate they used.","operationId":"v1_public_custom_tax_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The tax preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"kazdbC5ICA0kV0","in":"path","name":"hash_id","required":true,"schema":{"example":"kazdbC5ICA0kV0","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"Make it the default","value":{"default":true}},"rate":{"summary":"Change a Single Line Tax rate","value":{"total":6250}}},"schema":{"description":"Send only what changes. Which fields apply depends on the preset's type.","properties":{"apply_before_disc":{"default":false,"description":"Calculate tax before the discount. Defaults to false.","type":"boolean"},"default":{"description":"`true` makes it the team's default tax preset. `false` does nothing.","type":"boolean"},"enable":{"default":true,"description":"Defaults to true.","type":"boolean"},"line_taxes":{"description":"`line_tax` presets only. Replaces all the parts.","items":{"properties":{"name":{"description":"The part's name, such as `State` or `County`.","example":"State","type":"string"},"total":{"description":"The part's rate. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":6000,"minimum":0,"type":"integer"}},"required":["name","total"],"type":"object"},"maxItems":8,"minItems":1,"type":"array"},"name":{"description":"Any preset except Auto Tax.","type":"string"},"shipping_taxable":{"default":true,"description":"Tax shipping too. Defaults to true.","type":"boolean"},"total":{"description":"`simple` presets only. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","minimum":0,"type":"integer"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"apply_before_disc":false,"can_override_rates":false,"can_override_rules":false,"default":true,"enable":true,"error":"","hidden":false,"id":"kazdbC5ICA0kV0","line_taxes":[],"name":"State sales tax","override_rates":[],"override_rules":[],"secondary_type":null,"shipping_taxable":true,"supported_place":[],"total":6250,"trashed":false,"type":"simple"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"apply_before_disc":{"description":"Whether tax is calculated before the discount (Calculate Taxes Before Discount). Normally false: tax comes after the discount.","example":false,"type":"boolean"},"can_override_rates":{"example":false,"type":"boolean"},"can_override_rules":{"example":false,"type":"boolean"},"default":{"description":"Whether it is the team's default tax preset. At most one preset is the default.","example":true,"type":"boolean"},"enable":{"example":true,"type":"boolean"},"error":{"example":"","type":"string"},"hidden":{"example":false,"type":"boolean"},"id":{"example":"kazdbC5ICA0kV0","type":"string"},"line_taxes":{"description":"The parts of a `line_tax` preset, as they were sent. Empty for the others.","example":[],"items":{"properties":{"name":{"description":"The part's name, such as `State` or `County`.","example":"State","type":"string"},"total":{"description":"The part's rate. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":6000,"minimum":0,"type":"integer"}},"required":["name","total"],"type":"object"},"type":"array"},"name":{"example":"State sales tax","type":"string"},"override_rates":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"override_rules":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"secondary_type":{"description":"For `system` presets, which one: `auto` is Auto Tax, YoPrint's automatic US sales tax; `other` is a 0% preset some teams have, whose `name` always reads Tax Exempt. Null for your own presets.","example":null,"type":["string","null"]},"shipping_taxable":{"description":"Whether shipping is taxed (Tax Shipping).","example":true,"type":"boolean"},"supported_place":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"total":{"description":"The rate. For `line_tax`, the sum of the parts. Auto Tax shows 0: its rate is looked up per invoice. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":6000,"minimum":0,"type":"integer"},"trashed":{"description":"True for a deleted preset. Restore it with Restore a tax preset.","example":false,"type":"boolean"},"type":{"description":"`simple` (Single Line Tax): one rate. `line_tax` (Multi Line Tax): parts that add up. `system`: made by YoPrint, such as Auto Tax.","enum":["simple","line_tax","system"],"example":"simple","type":"string"}},"required":["id","type","secondary_type","name","total","shipping_taxable","apply_before_disc","enable","default","line_taxes","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a tax preset (same as PUT)","tags":["Tax presets"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No tax preset with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A field is the wrong type, a rate is not a whole number of 0 or more, or `line_taxes` has no parts or more than 8. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."},{"fix":"Edit only presets the list returns, with rates as a percentage ×1000 (`8250` is 8.25%).","status":422,"when":"The preset is a retired legacy row (`error.code` `validation_error`, \"We only support simple and line tax type update.\"), or the parts add up to more than YoPrint can store (`amount_out_of_range`)."}],"group":"Team settings","patch":"same_as_put","permission":"Needs the Manage Settings permission.","related":["v1_public_custom_tax_show"],"rules":["Fields that don't apply to the preset's type are ignored.","`line_taxes`, when sent, needs 1 to 8 parts and replaces them all; the rate becomes their sum."],"side_effects":["With `default: true`, new invoices YoPrint creates use this preset."]}},"put":{"description":"Changes a tax preset and returns it. Send only the fields to change.\n\n- `simple`: `name`, `total`, `shipping_taxable`, `apply_before_disc`, `enable`, `default`.\n- `line_tax`: the same, with `line_taxes` instead of `total`.\n- `system` presets: only `name` and `default`; for Auto Tax, only `default`. The Tax Exempt preset (`secondary_type` `other`) saves a new `name` but keeps showing Tax Exempt.\n\n`default: true` makes it the team default. The type can't be changed. Existing invoices keep the rate they used.","operationId":"v1_public_custom_tax_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The tax preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"kazdbC5ICA0kV0","in":"path","name":"hash_id","required":true,"schema":{"example":"kazdbC5ICA0kV0","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"Make it the default","value":{"default":true}},"rate":{"summary":"Change a Single Line Tax rate","value":{"total":6250}}},"schema":{"description":"Send only what changes. Which fields apply depends on the preset's type.","properties":{"apply_before_disc":{"default":false,"description":"Calculate tax before the discount. Defaults to false.","type":"boolean"},"default":{"description":"`true` makes it the team's default tax preset. `false` does nothing.","type":"boolean"},"enable":{"default":true,"description":"Defaults to true.","type":"boolean"},"line_taxes":{"description":"`line_tax` presets only. Replaces all the parts.","items":{"properties":{"name":{"description":"The part's name, such as `State` or `County`.","example":"State","type":"string"},"total":{"description":"The part's rate. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":6000,"minimum":0,"type":"integer"}},"required":["name","total"],"type":"object"},"maxItems":8,"minItems":1,"type":"array"},"name":{"description":"Any preset except Auto Tax.","type":"string"},"shipping_taxable":{"default":true,"description":"Tax shipping too. Defaults to true.","type":"boolean"},"total":{"description":"`simple` presets only. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","minimum":0,"type":"integer"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"apply_before_disc":false,"can_override_rates":false,"can_override_rules":false,"default":true,"enable":true,"error":"","hidden":false,"id":"kazdbC5ICA0kV0","line_taxes":[],"name":"State sales tax","override_rates":[],"override_rules":[],"secondary_type":null,"shipping_taxable":true,"supported_place":[],"total":6250,"trashed":false,"type":"simple"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"apply_before_disc":{"description":"Whether tax is calculated before the discount (Calculate Taxes Before Discount). Normally false: tax comes after the discount.","example":false,"type":"boolean"},"can_override_rates":{"example":false,"type":"boolean"},"can_override_rules":{"example":false,"type":"boolean"},"default":{"description":"Whether it is the team's default tax preset. At most one preset is the default.","example":true,"type":"boolean"},"enable":{"example":true,"type":"boolean"},"error":{"example":"","type":"string"},"hidden":{"example":false,"type":"boolean"},"id":{"example":"kazdbC5ICA0kV0","type":"string"},"line_taxes":{"description":"The parts of a `line_tax` preset, as they were sent. Empty for the others.","example":[],"items":{"properties":{"name":{"description":"The part's name, such as `State` or `County`.","example":"State","type":"string"},"total":{"description":"The part's rate. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":6000,"minimum":0,"type":"integer"}},"required":["name","total"],"type":"object"},"type":"array"},"name":{"example":"State sales tax","type":"string"},"override_rates":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"override_rules":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"secondary_type":{"description":"For `system` presets, which one: `auto` is Auto Tax, YoPrint's automatic US sales tax; `other` is a 0% preset some teams have, whose `name` always reads Tax Exempt. Null for your own presets.","example":null,"type":["string","null"]},"shipping_taxable":{"description":"Whether shipping is taxed (Tax Shipping).","example":true,"type":"boolean"},"supported_place":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"total":{"description":"The rate. For `line_tax`, the sum of the parts. Auto Tax shows 0: its rate is looked up per invoice. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","example":6000,"minimum":0,"type":"integer"},"trashed":{"description":"True for a deleted preset. Restore it with Restore a tax preset.","example":false,"type":"boolean"},"type":{"description":"`simple` (Single Line Tax): one rate. `line_tax` (Multi Line Tax): parts that add up. `system`: made by YoPrint, such as Auto Tax.","enum":["simple","line_tax","system"],"example":"simple","type":"string"}},"required":["id","type","secondary_type","name","total","shipping_taxable","apply_before_disc","enable","default","line_taxes","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a tax preset","tags":["Tax presets"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No tax preset with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A field is the wrong type, a rate is not a whole number of 0 or more, or `line_taxes` has no parts or more than 8. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."},{"fix":"Edit only presets the list returns, with rates as a percentage ×1000 (`8250` is 8.25%).","status":422,"when":"The preset is a retired legacy row (`error.code` `validation_error`, \"We only support simple and line tax type update.\"), or the parts add up to more than YoPrint can store (`amount_out_of_range`)."}],"group":"Team settings","patch":"same_as_put","permission":"Needs the Manage Settings permission.","related":["v1_public_custom_tax_show"],"rules":["Fields that don't apply to the preset's type are ignored.","`line_taxes`, when sent, needs 1 to 8 parts and replaces them all; the rate becomes their sum."],"side_effects":["With `default: true`, new invoices YoPrint creates use this preset."]}}},"/v1/api/store/{team_slug}/setting/tax_type/{id}/restore":{"patch":{"description":"Brings back a deleted tax preset. Restoring one that isn't deleted does nothing.","operationId":"v1_public_tax_type_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The tax preset's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"kazdbC5ICA0kV0","in":"path","name":"id","required":true,"schema":{"example":"kazdbC5ICA0kV0","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a tax preset","tags":["Tax presets"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No tax preset with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"System presets cannot be restored through the API.","status":500,"when":"It is a `system` preset (`error.code` is `restore_fail`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_custom_tax_destroy"]}}},"/v1/api/store/{team_slug}/setting/user":{"get":{"description":"Returns everyone on the team: name, email, permission group (`roles`), whether they are the owner, and when they last signed in.\n\nUse the `id` wherever a request asks for a user, for example to assign people to a job, task or sales order. People who were invited but haven't joined yet are in the invitations list instead.","operationId":"v1_public_user_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"avatar_url":null,"email":"alex@example.com","id":"E6LjYJJimQNFVF","is_owner":false,"last_login_at":"2026-10-30T14:05:00+00:00","name":"Alex Rivera","roles":[{"id":"drvVENtzY33bqP","name":"Production"}],"timezone":"America/New_York"},{"avatar_url":null,"email":"sam@example.com","id":"NiOR24yWE4ybXe","is_owner":true,"last_login_at":"2026-10-30T14:05:00+00:00","name":"Sam Lee","roles":[{"id":"XPTV59kiGksGRr","name":"Admin"}],"timezone":"America/New_York"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"is_owner":{"description":"True for the team owner. There is exactly one.","type":"boolean"},"last_login_at":{"description":"Null when they never signed in.","format":"date-time","type":["string","null"]},"name":{"example":"Alex Rivera","type":"string"},"roles":{"description":"Their permission group on this team.","items":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"example":"Production","type":"string"}},"required":["id","name"],"type":"object"},"type":"array"},"timezone":{"example":"America/New_York","type":["string","null"]}},"required":["id","name","email","avatar_url","timezone","is_owner","last_login_at","roles"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List team members","tags":["Team members"],"x-yoprint-docs":{"group":"Team settings","permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_invite_index","v1_public_user_show","v1_public_group_index"]}}},"/v1/api/store/{team_slug}/setting/user/{hash_id}":{"delete":{"description":"Takes a person off the team. Their access to this team ends at once, including through their API keys and AI apps. Their YoPrint account stays, and so does everything they created or did on the team.\n\nThe team owner can't be removed: transfer ownership first.","operationId":"v1_public_user_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The team member, from the member list. Its hash id from an earlier answer; there is no unique key for it.","example":"E6LjYJJimQNFVF","in":"path","name":"hash_id","required":true,"schema":{"example":"E6LjYJJimQNFVF","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove a member from the team","tags":["Team members"],"x-yoprint-docs":{"errors":[{"fix":"Transfer ownership to someone else first.","status":403,"when":"The person is the team owner: `error.code` `owner_cannot_be_removed`, \"The team owner cannot be removed. Transfer ownership first.\" Nothing changes."},{"fix":"Use an id from the members list.","status":404,"when":"The person is not on this team."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v1_public_user_index","v1_public_user_make_owner"],"rules":["The owner can't be removed (403 `owner_cannot_be_removed`).","Nothing stops you from removing yourself; you lose access to the team at once. AI apps can't remove their own person."],"side_effects":["Their permission group on this team is cleared.","Team members who have YoPrint open see them disappear at once."]}},"get":{"description":"Returns one member of the team. Someone who is not on this team is not found (404).","operationId":"v1_public_user_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The team member, from the member list. Its hash id from an earlier answer; there is no unique key for it.","example":"E6LjYJJimQNFVF","in":"path","name":"hash_id","required":true,"schema":{"example":"E6LjYJJimQNFVF","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"avatar_url":null,"email":"alex@example.com","id":"E6LjYJJimQNFVF","is_owner":false,"last_login_at":"2026-10-30T14:05:00+00:00","name":"Alex Rivera","roles":[{"id":"drvVENtzY33bqP","name":"Production"}],"timezone":"America/New_York"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"E6LjYJJimQNFVF","type":"string"},"is_owner":{"description":"True for the team owner. There is exactly one.","type":"boolean"},"last_login_at":{"description":"Null when they never signed in.","format":"date-time","type":["string","null"]},"name":{"example":"Alex Rivera","type":"string"},"roles":{"description":"Their permission group on this team.","items":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"example":"Production","type":"string"}},"required":["id","name"],"type":"object"},"type":"array"},"timezone":{"example":"America/New_York","type":["string","null"]}},"required":["id","name","email","avatar_url","timezone","is_owner","last_login_at","roles"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a team member","tags":["Team members"],"x-yoprint-docs":{"group":"Team settings","permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v1_public_user_index","v1_public_user_destroy"]}}},"/v1/api/store/{team_slug}/setting/user/{hash_id}/make_owner":{"post":{"description":"Makes another member the team owner. Only the current owner can do this, using their own API key.\n\nThe new owner gets every permission and control of YoPrint billing. The previous owner stays on the team with their permission group, and loses the owner's extra rights. Only the new owner can transfer ownership back.\n\nThere is no confirmation step: the change applies at once.","operationId":"v1_public_user_make_owner","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The member who becomes the owner. Its hash id from an earlier answer; there is no unique key for it.","example":"E6LjYJJimQNFVF","in":"path","name":"hash_id","required":true,"schema":{"example":"E6LjYJJimQNFVF","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Transfer team ownership","tags":["Team members"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Call it with the owner's API key, for a member from the members list.","status":500,"when":"You are not the owner, or the person is not a member of the team. Nothing changes. The body is the error envelope with `error.code` and `error.message` null."}],"group":"Team settings","notes":["AI apps (MCP connections) can't call this operation: they get 403 `agent_operation_not_available`. Use a personal API key."],"permission":"Only the team owner. The route also needs Manage Settings, which the owner always has.","related":["v1_public_user_index","v1_public_user_destroy"],"rules":["The caller must be the current owner, and the new owner must already be a member of the team."],"side_effects":["Who can manage YoPrint billing changes: the owner always can."]}}},"/v1/api/store/{team_slug}/setting/webhook_subscription":{"get":{"description":"Returns the team's webhook subscriptions, one page at a time. The team owner and members with Manage Settings also get each one's signing `secret`.\n\nThe list includes subscriptions made in the web app (Settings, Webhooks) and by YoPrint's Zapier app (`source` `zapier`). It doesn't include the status filters (`config`) a subscription was created with.","operationId":"v1_public_webhook_subscription_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The page to return. A page holds the team's page size (50 unless the team changed it). `per_page` is not read.","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"created_at":"2026-11-03T15:00:00+00:00","disable_reason":null,"enabled_events":["order.created","payment_received.any_amount"],"id":"V4keXwwxMQyXw7","name":"Order sync","secret":"whsec_YOUR_WEBHOOK_SECRET","source":"yoprint","status":"active","updated_at":"2026-11-03T15:00:00+00:00","url":"https://example.com/yoprint/webhooks"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"disable_reason":{"description":"`auto_disable_too_many_errors` when YoPrint turned the subscription off because its deliveries kept failing. Otherwise null. Setting `status` back to `active` does not clear it.","example":null,"type":["string","null"]},"enabled_events":{"description":"Subscribed event names, or `all` for every event.","example":["order.created","payment_received.any_amount"],"items":{"type":"string"},"type":"array"},"id":{"description":"The subscription id.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"example":"Order sync","type":"string"},"secret":{"description":"The secret used to sign event payloads: `whsec_` followed by 32 letters and digits. Use it to verify incoming messages. YoPrint creates it when the subscription is created and never changes it. Keep it private. Only the team owner and members whose permission group has Manage Settings can see it; for every other member it is null. It is also null for AI apps reading through YoPrint's MCP server.","example":"whsec_YOUR_WEBHOOK_SECRET","type":["string","null"]},"source":{"description":"The `source` sent when the subscription was created: the web app sends `yoprint`, YoPrint's Zapier app sends `zapier`.","example":"yoprint","type":"string"},"status":{"description":"Only `active` subscriptions receive events.","enum":["active","disabled"],"example":"active","type":"string"},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"url":{"description":"The destination URL where YoPrint delivers events. On this API, this is the full URL. AI apps reading subscriptions through YoPrint's MCP server see only the origin (scheme and host, such as `https://example.com`) to protect webhook secrets.","example":"https://example.com/yoprint/webhooks","type":["string","null"]}},"required":["id","url","name","secret","status","disable_reason","source","enabled_events","created_at","updated_at"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List webhook subscriptions","tags":["Webhook subscriptions"],"x-yoprint-docs":{"group":"Team settings","notes":["Manage subscriptions with `source` `zapier` in Zapier: turning a Zap off deletes its subscription. Deleting one here stops that Zap's events."],"permission":"Any team member can call it. Reading needs no extra permission. Every member sees each subscription's full URL, but only the team owner and members with Manage Settings get its signing `secret`; for other members it is null. (AI apps connected through YoPrint's MCP server get `secret: null` and only the URL's scheme and host to protect webhook secrets.)","related":["v1_public_webhook_subscription_store","v1_public_webhook_subscription_show","v1_public_webhook_subscription_log"]}},"post":{"description":"Subscribes a URL to team events. The subscription starts `active`, and YoPrint generates its signing `secret` and returns it in the response.\n\nEvents fire for changes made in the web app, through the API and by AI apps alike. A change that triggers several events sends each of them.\n\n## What YoPrint sends\n\nAbout 10 seconds after an event, YoPrint sends one `POST` to the `url` of every active subscription whose `enabled_events` holds the event name or `all`.\n\nHeaders:\n\n- `Content-Type: application/json`\n- `User-Agent: YoPrint Webhooks Agent`\n- `X-Signature`: the HMAC-SHA256 of the raw request body, keyed with the subscription's `secret`, as 64 lowercase hex characters.\n\nBody:\n\n```json\n{\n  \"id\": \"VwYKuTP9vd8Dfo\",\n  \"type\": \"order.created\",\n  \"payload\": {\n    \"id\": \"BkzhmfgkK2HFTs\",\n    \"scoped_id\": \"SO1001\",\n    \"...\": \"...\"\n  },\n  \"created_at\": \"2026-11-03T15:00:00+00:00\",\n  \"updated_at\": \"2026-11-03T15:00:00+00:00\"\n}\n```\n\n`id` identifies the event: retries of an event carry the same `id`. `payload` is the record the event is about (see \"Events\" below).\n\n### Verify the signature\n\n1. Read the raw body bytes before any JSON parsing.\n2. Compute HMAC-SHA256 of those bytes with the secret (the whole string, `whsec_` included) and hex-encode it.\n3. Compare the result with `X-Signature` in constant time, for example `hash_equals(hash_hmac('sha256', $rawBody, $secret), $signature)` in PHP or `crypto.timingSafeEqual` in Node.js. Reject the request when they differ.\n\nDon't parse and re-serialize the JSON before checking: YoPrint's JSON escapes `/` as `\\/` and non-ASCII characters as `\\uXXXX`, so the bytes change. The signature has no timestamp, so remember the event ids you have processed and ignore repeats.\n\n### Answer, retries and timeouts\n\n- Answer with status `200` within 3 seconds. Do slow work afterwards.\n- YoPrint checks the TLS certificate of `https` URLs and does not follow redirects: a `3xx` answer is a failure.\n- Before every attempt YoPrint looks up the URL's host again. If it doesn't resolve, or any address it resolves to is not a public internet address (private, loopback, link-local, carrier-grade NAT, multicast or reserved), nothing is sent and the attempt fails with `status_code` `999`. YoPrint connects only to the addresses it checked, never through a proxy.\n- A non-`2xx` status, a timeout or a connection error fails the attempt. YoPrint tries an event up to 3 times: once, again 10 seconds after a failure, and a last time 100 seconds after the second failure. Then it gives up on that event.\n- Any `2xx` stops the retries, but only `200` counts as a success in the delivery log. Other `2xx` codes show as `error`.\n- YoPrint can turn off a subscription whose deliveries keep failing. It then sets `status` to `disabled` and `disable_reason` to `auto_disable_too_many_errors`, and emails the team owner. YoPrint does not promise when it checks, so pause a broken receiver yourself by setting `status` to `disabled`.\n- A team whose plan no longer includes API access gets no deliveries, and no delivery rows are logged. Subscriptions are kept and deliver again after an upgrade. Every API request then answers 403 `api_access_not_in_plan`, listing and deleting included. In YoPrint's settings the team can still list and delete its subscriptions.\n- Each delivery is sent on its own, so events can arrive out of order, for example after a retry.\n- For a subscription with `source` `zapier`, a `410 Gone` answer stops the retries at once.\n\n## Events\n\n### Sales orders and quotes\n\n- `order.created`: a sales order is published (it leaves draft). Nothing is sent for drafts. Payload: the sales order.\n- `quote.created`: a quote is published. Payload: the quote.\n- `order.deleted`, `quote.deleted`: a sales order or quote is deleted. Payload: the order or quote, with `trashed: true`.\n- `order.restored`, `quote.restored`: a deleted sales order or quote is restored. Payload: the order or quote.\n- `quote.converted_to_sales_order`: a quote is converted to a sales order. Payload: the converted document.\n- `order.converted_to_quote`: a sales order is converted to a quote. Payload: the converted document.\n- `order.marked_as_rush`, `order.marked_as_not_rush`: a sales order's rush flag is turned on or off. Payload: the sales order.\n- `sales_order.status_changed`: a sales order moves to a different status. Payload: the sales order, plus `previous_status_id`, `previous_status` and `participant_emails` (the message participants who receive email).\n- `quote.status_changed`: the same, for a quote.\n- `order.status_changed`: either of the two above. It is an older event kept for Zapier and sent alongside them, so a subscriber to `all` gets two events for one status change. Payload: the same.\n\n### Jobs, tasks, shipments and purchase orders\n\n- `job.status_changed`: a job moves to a different status. Payload: the job, plus `previous_status_id`, `previous_status` and `participant_emails`.\n- `job.marked_as_rush`, `job.marked_as_not_rush`: a job update turns its rush flag on or off. Payload: the job.\n- `work_pipeline.status_changed`: a task moves to a different status. Payload: the task, plus `previous_status_id` and `previous_status`.\n- `shipment.status_changed`: a shipment's status is changed. Payload: the shipment, plus `previous_status_id` and `previous_status`.\n- `purchase_order.status_changed`: a purchase order's status is set, even to the status it already has. Payload: the purchase order, plus `previous_status_id`, `previous_status` and `related_order` (its linked sales orders, or null).\n\n### Approvals\n\n- `order_approval.approved`, `order_approval.change_requested`: an order approval is completed, approved or with changes requested. Payload: the approval, with its `order` and `customer`.\n- `job_approval.approved`, `job_approval.change_requested`: a job approval is completed. Payload: the approval, with its `order`, `job` and `customer`.\n\n### Payments and customer credit\n\n- `payment_received.any_amount`: any payment is recorded on a sales order: a manual payment, a gateway or payment-link payment, or a payment from customer credit. Payload: the payment, with its `order`.\n- `payment_received.deposit_amount`: after a payment, the order's total paid equals its deposit amount (`calc_deposit_total`) exactly. Sent as well as `any_amount`. Not sent when a payment goes past the deposit, for example a first payment of the full amount. Payload: the same.\n- `payment_received.full_amount`: after a payment, the total paid equals the invoiced total exactly (the balance due is zero). Sent as well as `any_amount`. Not sent for an overpayment, or while the order has no invoice. Payload: the same.\n- `payment.refund_issued`: a refund is recorded on a sales order. Payload: the refund, with its `order`.\n- `customer_credit.deposited`, `customer_credit.withdrew`: credit is added to or taken from a customer's credit balance. Payload: the transaction, with its `customer`.\n\n### Customers and contacts\n\n- `customer.created`, `customer.updated`, `customer.deleted`: a customer is created, changed or deleted. Payload: the customer, with its `contacts`.\n- `customer_contact.created`, `customer_contact.updated`, `customer_contact.deleted`: a customer contact is created, changed or deleted. Payload: the contact, with its `customer`.\n\n### Messages\n\n- `message.received_customer`: a customer sends a message from the customer portal. Payload: the message.\n- `message.received_purchase_order`: a vendor sends a message from the vendor portal. Payload: the message.\n- `message.customer_bounced`, `message.bounced_purchase_order`: an email about a sales order, or about a purchase order, cannot be delivered. Payload: the message.\n- `message.status_changed`: a customer message's status is set, even to the status it already has. Payload: the message, plus `previous_status_id` and `previous_message_status`.\n\n### Reading payloads\n\nDon't rely on `deposit_amount` or `full_amount` alone to start work: both need an exact match, and both can be sent again after a refund and a new payment. Subscribe to `payment_received.any_amount`, then read the order back (Get a sales order or quote) and compare what was paid with the deposit and the balance.\n\nEvery order and quote payload says which it is with `is_quote` (true or false) and `object_type` (`sales_order` or `quote`). The payloads of `order.created` and of the deleted, restored, converted and rush events also have `type` (`order` or `quote`); the `quote.created` and status-change payloads don't. All of them carry older fields such as `is_draft` and `is_created`; use `mode` instead.\n\nOrder and quote payloads give `calc_total` and the other `calc_*` amounts in thousandths, an older encoding (`calc_total: 125000` is 125.00; see [Money and quantities](/concepts/money-and-quantities/)). The payloads of `order.created` and of the deleted, restored, converted and rush events also give them as formatted strings with the currency symbol (`formatted_calc_total: \"$125.00\"`). The `quote.created` and status-change payloads have only some formatted amounts, such as `formatted_invoiced_total` and `formatted_order_balance_due`.\n\nPayment payloads give `amount` as a formatted string for display (such as `\"$125.00\"`; do not parse it—read the order for exact amounts), and name the payment method in `payment_method_name`. A payment a customer made through the customer portal's checkout also carries `funding_payment_gateway` (the gateway), `funding_transaction_id`, `currency_iso`, `is_external_cash_movement` and `customer_payment_*` fields, and YoPrint sets its `payment_method_name` (such as `Credit Card/Debit Card` or `PayPal`). Status ids in payloads are the same ids the status lists return.\n\nOrder and quote payloads include `customer_portal_order_link` and `customer_portal_payment_link`. These links open the customer's portal without a sign-in, so treat payloads as sensitive: do not log or forward them.\n\nTo see the exact `payload` of an event for your team, call Show a sample event.","operationId":"v1_public_webhook_subscription_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"filtered_job_status":{"summary":"Jobs that reach one status","value":{"config":{"job_status_changed_options":{"status_ids":["PLksRyu0AR7Bv4"]}},"enabled_events":["job.status_changed"],"name":"Ready to ship","source":"yoprint","url":"https://example.com/yoprint/jobs"}},"orders_and_payments":{"summary":"New sales orders and payments","value":{"enabled_events":["order.created","payment_received.any_amount"],"name":"Order sync","source":"yoprint","url":"https://example.com/yoprint/webhooks"}}},"schema":{"properties":{"config":{"description":"Optional status filters for the status-change events. Without a filter, every status change is sent. The other events ignore `config`, and so does the older `order.status_changed`. Status ids come from the status lists (see Statuses).","properties":{"job_status_changed_options":{"description":"Send `job.status_changed` only when the new status is one of these job statuses.","properties":{"status_ids":{"description":"Status ids, exactly as the status lists return them.","items":{"type":"string"},"minItems":1,"type":"array"}},"type":"object"},"message_status_changed_options":{"description":"Send `message.status_changed` only when the new status is one of these customer message statuses.","properties":{"status_ids":{"description":"Status ids, exactly as the status lists return them.","items":{"type":"string"},"minItems":1,"type":"array"}},"type":"object"},"purchase_order_status_changed_options":{"description":"Send `purchase_order.status_changed` only when the new status is one of these purchase order statuses.","properties":{"status_ids":{"description":"Status ids, exactly as the status lists return them.","items":{"type":"string"},"minItems":1,"type":"array"}},"type":"object"},"quote_status_changed_options":{"description":"Send `quote.status_changed` only when the new status is one of these quote statuses.","properties":{"status_ids":{"description":"Status ids, exactly as the status lists return them.","items":{"type":"string"},"minItems":1,"type":"array"}},"type":"object"},"sales_order_status_changed_options":{"description":"Send `sales_order.status_changed` only when the new status is one of these sales order statuses.","properties":{"status_ids":{"description":"Status ids, exactly as the status lists return them.","items":{"type":"string"},"minItems":1,"type":"array"}},"type":"object"},"shipment_status_changed_options":{"description":"Send `shipment.status_changed` only when the new status is one of these shipment statuses.","properties":{"status_ids":{"description":"Status ids, exactly as the status lists return them.","items":{"type":"string"},"minItems":1,"type":"array"}},"type":"object"},"work_pipeline_status_changed_options":{"description":"Send `work_pipeline.status_changed` only when the new status is one of these task statuses.","properties":{"status_ids":{"description":"Status ids, exactly as the status lists return them.","items":{"type":"string"},"minItems":1,"type":"array"}},"type":"object"}},"type":"object"},"enabled_events":{"description":"Event names to subscribe to from the Events table, or `all` for every event (including future events). YoPrint does not validate event names: misspelled names are saved without error, but will never match any event.","example":["order.created","payment_received.any_amount"],"items":{"type":"string"},"minItems":1,"type":"array","uniqueItems":true},"name":{"description":"A name to recognize it by.","example":"Order sync","type":"string"},"source":{"description":"Send `yoprint`. YoPrint's Zapier app sends `zapier`, which changes failure handling; don't use it.","example":"yoprint","type":"string"},"url":{"description":"Where YoPrint sends events. Must be an `https://` URL on the public internet. YoPrint refuses plain `http://` URLs and any host that resolves to a non-public address (private, loopback, link-local, carrier-grade NAT, multicast or reserved). YoPrint looks up the host when you save, but does not send a test request. Use the final destination URL because redirects are not followed.","example":"https://example.com/yoprint/webhooks","type":"string"}},"required":["url","name","enabled_events","source"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-03T15:00:00+00:00","disable_reason":null,"enabled_events":["order.created","payment_received.any_amount"],"id":"V4keXwwxMQyXw7","name":"Order sync","secret":"whsec_YOUR_WEBHOOK_SECRET","source":"yoprint","status":"active","updated_at":"2026-11-03T15:00:00+00:00","url":"https://example.com/yoprint/webhooks"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"disable_reason":{"description":"`auto_disable_too_many_errors` when YoPrint turned the subscription off because its deliveries kept failing. Otherwise null. Setting `status` back to `active` does not clear it.","example":null,"type":["string","null"]},"enabled_events":{"description":"Subscribed event names, or `all` for every event.","example":["order.created","payment_received.any_amount"],"items":{"type":"string"},"type":"array"},"id":{"description":"The subscription id.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"example":"Order sync","type":"string"},"secret":{"description":"The secret used to sign event payloads: `whsec_` followed by 32 letters and digits. Use it to verify incoming messages. YoPrint creates it when the subscription is created and never changes it. Keep it private. Only the team owner and members whose permission group has Manage Settings can see it; for every other member it is null. It is also null for AI apps reading through YoPrint's MCP server.","example":"whsec_YOUR_WEBHOOK_SECRET","type":["string","null"]},"source":{"description":"The `source` sent when the subscription was created: the web app sends `yoprint`, YoPrint's Zapier app sends `zapier`.","example":"yoprint","type":"string"},"status":{"description":"Only `active` subscriptions receive events.","enum":["active","disabled"],"example":"active","type":"string"},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"url":{"description":"The destination URL where YoPrint delivers events. On this API, this is the full URL. AI apps reading subscriptions through YoPrint's MCP server see only the origin (scheme and host, such as `https://example.com`) to protect webhook secrets.","example":"https://example.com/yoprint/webhooks","type":["string","null"]}},"required":["id","url","name","secret","status","disable_reason","source","enabled_events","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a webhook subscription","tags":["Webhook subscriptions"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"A required field is missing, `url` is not a URL, `enabled_events` is empty or repeats a name, or a `status_ids` list is empty. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."},{"fix":"Use an `https://` URL on a public host. For `host_lookup_failed`, check the host name, or try again in a minute if its DNS is new.","status":422,"when":"`url` is refused by the public-address check (`validation_failed`, with `error.fields.url` and `error.field_reasons.url.reason`). `not_public_address`: the URL is not `https://`, has no usable host, or its host reaches an address that is not on the public internet (\"Use an https:// URL that reaches a public internet address.\"). `host_lookup_failed`: the host name could not be looked up (\"The host name in this URL could not be looked up. Check the address, or try again in a minute.\")."}],"group":"Team settings","notes":["Store the `secret` from the response with your other secrets. You can read it again later with Show a webhook subscription, as the team owner or with Manage Settings.","Check what you will receive before going live: Show a sample event returns a real `payload` built from your team's data.","Watch deliveries with List deliveries for a webhook subscription."],"permission":"Needs the Manage Settings permission.","related":["v1_public_webhook_subscription_sample","v1_public_webhook_subscription_log","v1_public_webhook_subscription_update_patch","v1_public_status_list_job","v1_public_status_list_sales_order","v2_public_order_show"],"rules":["`url`, `name`, `enabled_events` (at least one name, no repeats) and `source` are required.","`url` must be an `https://` URL whose host resolves, and resolves only to public internet addresses. YoPrint looks the host up when you save; it sends nothing to it.","A `secret` in the body is ignored. YoPrint makes the secret, and it never changes. To get a new secret, create a new subscription and delete the old one.","`config` can be set only here. Updating a subscription does not change it, and no response shows it.","A team can have any number of subscriptions, and two subscriptions may use the same URL. Each gets its own copy of every event."],"side_effects":["From now on, matching events are sent to `url` as described in \"What YoPrint sends\"."]}}},"/v1/api/store/{team_slug}/setting/webhook_subscription/sample/{event_name}":{"get":{"description":"Builds the event YoPrint would send for `event_name`, from your team's latest matching record, without sending anything. Use it to see the exact `payload` of an event before you subscribe.\n\nThe response is the bare event body (`id`, `type`, `payload`, `created_at`, `updated_at`), without the usual `success`, `status` and `data` envelope, because YoPrint's Zapier app reads it as is. The sample `id` is not a real event id.\n\nWhen the team has no record the event could use (for example, no published sales order), the response is the usual envelope with an empty list: `{\"success\": true, \"status\": 200, \"data\": []}`.","operationId":"v1_public_webhook_subscription_sample","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The event to build a sample of: one of the names in the \"Events\" table on Create a webhook subscription, such as `order.created`. `all` and unknown names answer 400 `event_not_found`.","example":"order.created","in":"path","name":"event_name","required":true,"schema":{"enum":["order.created","quote.created","order.deleted","quote.deleted","order.restored","quote.restored","quote.converted_to_sales_order","order.converted_to_quote","order.marked_as_rush","order.marked_as_not_rush","sales_order.status_changed","quote.status_changed","order.status_changed","job.status_changed","job.marked_as_rush","job.marked_as_not_rush","work_pipeline.status_changed","shipment.status_changed","purchase_order.status_changed","order_approval.approved","order_approval.change_requested","job_approval.approved","job_approval.change_requested","payment_received.any_amount","payment_received.deposit_amount","payment_received.full_amount","payment.refund_issued","customer_credit.deposited","customer_credit.withdrew","customer.created","customer.updated","customer.deleted","customer_contact.created","customer_contact.updated","customer_contact.deleted","message.received_customer","message.received_purchase_order","message.customer_bounced","message.bounced_purchase_order","message.status_changed"],"example":"order.created","type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"none":{"summary":"No matching record","value":{"data":[],"status":200,"success":true}},"sample":{"summary":"A sample event","value":{"created_at":"2026-11-03T15:00:00+00:00","id":"yUYzWQ08P0wLEm","payload":{"calc_total":125000,"formatted_calc_total":"$125.00","id":"BkzhmfgkK2HFTs","name":"Team shirts","scoped_id":"SO1001","status_id":"PLksRyu0AR7Bv4","unique_key":"ord_EXAMPLEuniqueKey"},"type":"order.created","updated_at":"2026-11-03T15:00:00+00:00"}}},"schema":{"oneOf":[{"properties":{"created_at":{"description":"When the event happened.","example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"id":{"description":"The event id. Every attempt to deliver this event, to every subscription, carries the same id.","example":"VwYKuTP9vd8Dfo","type":"string"},"payload":{"additionalProperties":true,"description":"The record the event is about, as it was when the event happened. Its fields depend on the event; see \"Events\" on Create a webhook subscription.","example":{"calc_total":125000,"formatted_calc_total":"$125.00","id":"BkzhmfgkK2HFTs","name":"Team shirts","scoped_id":"SO1001","status_id":"PLksRyu0AR7Bv4","unique_key":"ord_EXAMPLEuniqueKey"},"type":"object"},"type":{"description":"The event name.","example":"order.created","type":"string"},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"required":["id","type","payload","created_at","updated_at"],"title":"Sample event","type":"object"},{"properties":{"data":{"items":{"type":"object"},"maxItems":0,"type":"array"},"status":{"const":200,"type":"integer"},"success":{"const":true,"type":"boolean"}},"required":["success","status","data"],"title":"No matching record","type":"object"}]}}},"description":"The sample event, or an empty envelope when the team has no matching record."},"400":{"content":{"application/json":{"example":{"error":{"code":"event_not_found","message":"The event requested is not in our system"},"status":400,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"The event name is not one YoPrint sends."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show a sample event","tags":["Webhook subscriptions"],"x-yoprint-docs":{"errors":[{"fix":"Use a name from the \"Events\" table on Create a webhook subscription.","status":400,"when":"YoPrint doesn't send an event with that name (`event_not_found`)."},{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."}],"group":"Team settings","notes":["The sample reads real team data, such as the latest published sales order, and may include customer names and emails.","The three `payment_received.*` names all return a sample with `type` `payment_received.any_amount`; their payloads have the same shape."],"permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_webhook_subscription_store"],"rules":["`event_name` is one of the event names YoPrint sends (see Create a webhook subscription). `all` is not accepted."]}}},"/v1/api/store/{team_slug}/setting/webhook_subscription/{hash_id}":{"delete":{"description":"Deletes a subscription for good, with its delivery log.\n\nNo more events are sent to it, and pending retries stop. After the delete, YoPrint sends one `DELETE` request to the subscription's URL (no body, no signature, `User-Agent: YoPrint Webhooks Agent`, 3-second timeout, redirects not followed), if its host still resolves only to public internet addresses. Any answer, or none, is ignored.","operationId":"v1_public_webhook_subscription_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The webhook subscription's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a webhook subscription","tags":["Webhook subscriptions"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No webhook subscription with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","notes":["Deleting cannot be undone. To stop deliveries for a while, set `status` to `disabled` instead.","Your endpoint should not treat an unsigned `DELETE` as an event."],"permission":"Needs the Manage Settings permission.","related":["v1_public_webhook_subscription_update_patch"],"side_effects":["Sends one unsigned `DELETE` request to the subscription's URL, unless its host no longer resolves to public internet addresses only.","Deletes the subscription's delivery log.","Deleting a `zapier` subscription stops that Zap's events. To remove a Zap's subscription cleanly, turn the Zap off in Zapier: Zapier then deletes the subscription itself."]}},"get":{"description":"Returns one webhook subscription with its `status` and `disable_reason`, and its signing `secret` for the team owner and members with Manage Settings.\n\nCheck `status` when deliveries stop: a subscription can be turned off by hand or by YoPrint after repeated failures (`disable_reason` `auto_disable_too_many_errors`).","operationId":"v1_public_webhook_subscription_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The webhook subscription's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-03T15:00:00+00:00","disable_reason":null,"enabled_events":["order.created","payment_received.any_amount"],"id":"V4keXwwxMQyXw7","name":"Order sync","secret":"whsec_YOUR_WEBHOOK_SECRET","source":"yoprint","status":"active","updated_at":"2026-11-03T15:00:00+00:00","url":"https://example.com/yoprint/webhooks"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"disable_reason":{"description":"`auto_disable_too_many_errors` when YoPrint turned the subscription off because its deliveries kept failing. Otherwise null. Setting `status` back to `active` does not clear it.","example":null,"type":["string","null"]},"enabled_events":{"description":"Subscribed event names, or `all` for every event.","example":["order.created","payment_received.any_amount"],"items":{"type":"string"},"type":"array"},"id":{"description":"The subscription id.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"example":"Order sync","type":"string"},"secret":{"description":"The secret used to sign event payloads: `whsec_` followed by 32 letters and digits. Use it to verify incoming messages. YoPrint creates it when the subscription is created and never changes it. Keep it private. Only the team owner and members whose permission group has Manage Settings can see it; for every other member it is null. It is also null for AI apps reading through YoPrint's MCP server.","example":"whsec_YOUR_WEBHOOK_SECRET","type":["string","null"]},"source":{"description":"The `source` sent when the subscription was created: the web app sends `yoprint`, YoPrint's Zapier app sends `zapier`.","example":"yoprint","type":"string"},"status":{"description":"Only `active` subscriptions receive events.","enum":["active","disabled"],"example":"active","type":"string"},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"url":{"description":"The destination URL where YoPrint delivers events. On this API, this is the full URL. AI apps reading subscriptions through YoPrint's MCP server see only the origin (scheme and host, such as `https://example.com`) to protect webhook secrets.","example":"https://example.com/yoprint/webhooks","type":["string","null"]}},"required":["id","url","name","secret","status","disable_reason","source","enabled_events","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show a webhook subscription","tags":["Webhook subscriptions"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No webhook subscription with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","notes":["The status filters (`config`) are not returned."],"permission":"Any team member can call it. Reading needs no extra permission. The signing `secret` is null unless you are the team owner or have Manage Settings.","related":["v1_public_webhook_subscription_update_patch","v1_public_webhook_subscription_log"]}},"patch":{"description":"Use PUT to change a webhook subscription. PATCH changes nothing and returns the subscription as it is, because YoPrint reads the body only for PUT.","operationId":"v1_public_webhook_subscription_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The webhook subscription's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-03T15:00:00+00:00","disable_reason":null,"enabled_events":["order.created","payment_received.any_amount"],"id":"V4keXwwxMQyXw7","name":"Order sync","secret":"whsec_YOUR_WEBHOOK_SECRET","source":"yoprint","status":"active","updated_at":"2026-11-03T15:00:00+00:00","url":"https://example.com/yoprint/webhooks"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"disable_reason":{"description":"`auto_disable_too_many_errors` when YoPrint turned the subscription off because its deliveries kept failing. Otherwise null. Setting `status` back to `active` does not clear it.","example":null,"type":["string","null"]},"enabled_events":{"description":"Subscribed event names, or `all` for every event.","example":["order.created","payment_received.any_amount"],"items":{"type":"string"},"type":"array"},"id":{"description":"The subscription id.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"example":"Order sync","type":"string"},"secret":{"description":"The secret used to sign event payloads: `whsec_` followed by 32 letters and digits. Use it to verify incoming messages. YoPrint creates it when the subscription is created and never changes it. Keep it private. Only the team owner and members whose permission group has Manage Settings can see it; for every other member it is null. It is also null for AI apps reading through YoPrint's MCP server.","example":"whsec_YOUR_WEBHOOK_SECRET","type":["string","null"]},"source":{"description":"The `source` sent when the subscription was created: the web app sends `yoprint`, YoPrint's Zapier app sends `zapier`.","example":"yoprint","type":"string"},"status":{"description":"Only `active` subscriptions receive events.","enum":["active","disabled"],"example":"active","type":"string"},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"url":{"description":"The destination URL where YoPrint delivers events. On this API, this is the full URL. AI apps reading subscriptions through YoPrint's MCP server see only the origin (scheme and host, such as `https://example.com`) to protect webhook secrets.","example":"https://example.com/yoprint/webhooks","type":["string","null"]}},"required":["id","url","name","secret","status","disable_reason","source","enabled_events","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Touch a webhook subscription","tags":["Webhook subscriptions"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No webhook subscription with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","permission":"Needs the Manage Settings permission.","related":["v1_public_webhook_subscription_update_patch"]}},"put":{"description":"Changes a subscription's URL, name, events or status, and returns it.\n\n`url` is required on every update, even when it doesn't change. Fields you leave out keep their values. Set `status` to `disabled` to pause deliveries and back to `active` to resume them; events that happen while it is disabled are not sent later.","operationId":"v1_public_webhook_subscription_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The webhook subscription's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"change_events":{"summary":"Change the events","value":{"enabled_events":["order.created","sales_order.status_changed"],"url":"https://example.com/yoprint/webhooks"}},"resume":{"summary":"Turn deliveries back on","value":{"status":"active","url":"https://example.com/yoprint/webhooks"}}},"schema":{"properties":{"config":{"description":"Accepted and validated, but not saved: status filters can only be set when the subscription is created.","type":"object"},"enabled_events":{"description":"Replaces the whole list. YoPrint doesn't check the names.","items":{"type":"string"},"minItems":1,"type":"array","uniqueItems":true},"name":{"description":"A name to recognize it by.","example":"Order sync","type":"string"},"status":{"description":"`disabled` stops deliveries; `active` resumes them.","enum":["active","disabled"],"type":"string"},"url":{"description":"Where YoPrint sends events. Must be an `https://` URL on the public internet. YoPrint refuses plain `http://` URLs and any host that resolves to a non-public address (private, loopback, link-local, carrier-grade NAT, multicast or reserved). YoPrint looks up the host when you save, but does not send a test request. Use the final destination URL because redirects are not followed.","example":"https://example.com/yoprint/webhooks","type":"string"}},"required":["url"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-03T15:00:00+00:00","disable_reason":null,"enabled_events":["order.created","sales_order.status_changed"],"id":"V4keXwwxMQyXw7","name":"Order sync","secret":"whsec_YOUR_WEBHOOK_SECRET","source":"yoprint","status":"active","updated_at":"2026-11-03T15:00:00+00:00","url":"https://example.com/yoprint/webhooks"},"status":200,"success":true},"schema":{"properties":{"data":{"properties":{"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"disable_reason":{"description":"`auto_disable_too_many_errors` when YoPrint turned the subscription off because its deliveries kept failing. Otherwise null. Setting `status` back to `active` does not clear it.","example":null,"type":["string","null"]},"enabled_events":{"description":"Subscribed event names, or `all` for every event.","example":["order.created","payment_received.any_amount"],"items":{"type":"string"},"type":"array"},"id":{"description":"The subscription id.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"example":"Order sync","type":"string"},"secret":{"description":"The secret used to sign event payloads: `whsec_` followed by 32 letters and digits. Use it to verify incoming messages. YoPrint creates it when the subscription is created and never changes it. Keep it private. Only the team owner and members whose permission group has Manage Settings can see it; for every other member it is null. It is also null for AI apps reading through YoPrint's MCP server.","example":"whsec_YOUR_WEBHOOK_SECRET","type":["string","null"]},"source":{"description":"The `source` sent when the subscription was created: the web app sends `yoprint`, YoPrint's Zapier app sends `zapier`.","example":"yoprint","type":"string"},"status":{"description":"Only `active` subscriptions receive events.","enum":["active","disabled"],"example":"active","type":"string"},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"url":{"description":"The destination URL where YoPrint delivers events. On this API, this is the full URL. AI apps reading subscriptions through YoPrint's MCP server see only the origin (scheme and host, such as `https://example.com`) to protect webhook secrets.","example":"https://example.com/yoprint/webhooks","type":["string","null"]}},"required":["id","url","name","secret","status","disable_reason","source","enabled_events","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a webhook subscription","tags":["Webhook subscriptions"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Ask the team owner to give your permission group Manage Settings.","status":403,"when":"Your permission group lacks Manage Settings. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, without `success` or `error`."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No webhook subscription with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."},{"fix":"Fix the fields listed in `error.fields` and send the request again.","status":422,"when":"`url` is missing or not a URL, `status` is not `active` or `disabled`, `enabled_events` is empty or repeats a name, or a `status_ids` list is empty. `error.code` is `validation_failed`, and `error.fields` names each field with its messages."},{"fix":"Use an `https://` URL on a public host. For `host_lookup_failed`, check the host name, or try again in a minute if its DNS is new.","status":422,"when":"`url` is refused by the public-address check (`validation_failed`, with `error.fields.url` and `error.field_reasons.url.reason`). `not_public_address`: the URL is not `https://`, has no usable host, or its host reaches an address that is not on the public internet (\"Use an https:// URL that reaches a public internet address.\"). `host_lookup_failed`: the host name could not be looked up (\"The host name in this URL could not be looked up. Check the address, or try again in a minute.\")."}],"group":"Team settings","notes":["Turning a subscription back on leaves `disable_reason` as it was.","To change the status filters, create a new subscription with the new `config` and delete the old one."],"permission":"Needs the Manage Settings permission.","related":["v1_public_webhook_subscription_show","v1_public_webhook_subscription_destroy"],"rules":["`url` is required.","A new `url` is checked as on create: `https://`, on a host that resolves only to public internet addresses. The subscription's current URL, sent exactly as stored, is not looked up again, so you can rename, disable or change the events of a subscription whose receiver is down.","`status` is `active` or `disabled`.","`enabled_events`, when sent, needs at least one name, no repeats, and replaces the list.","The `secret`, `source` and status filters cannot be changed."],"side_effects":["A new URL receives the retries of earlier events that are still pending.","Disabling stops new deliveries, but retries already scheduled (at most about 2 minutes ahead) still go out."]}}},"/v1/api/store/{team_slug}/setting/webhook_subscription/{id}/log":{"get":{"description":"Returns the subscription's deliveries, newest first, one page at a time. Each delivery is one event sent to this subscription, with the latest attempt's status code and error, when YoPrint retries next, and the event exactly as it was sent (`message`).\n\nUse it to debug your endpoint: `status_code` is what your endpoint answered (`999` when it didn't answer or YoPrint didn't send), and `error` says what went wrong in a sentence of YoPrint's, such as \"The receiver answered with HTTP 500.\" YoPrint doesn't keep your endpoint's reply, so log it on your side.","operationId":"v1_public_webhook_subscription_log","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The webhook subscription's `id`: a hash id from an earlier answer. Only hash ids work here; anything else answers 404 `page_not_found`.","example":"V4keXwwxMQyXw7","in":"path","name":"id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The page to return. A page holds the team's page size (50 unless the team changed it). `per_page` is not read.","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"attempt":1,"created_at":"2026-11-03T15:00:00+00:00","error":null,"id":"gxL14iJJPyg63n","message":{"created_at":"2026-11-03T15:00:00+00:00","id":"VwYKuTP9vd8Dfo","payload":{"calc_total":125000,"formatted_calc_total":"$125.00","id":"BkzhmfgkK2HFTs","name":"Team shirts","scoped_id":"SO1001","status_id":"PLksRyu0AR7Bv4","unique_key":"ord_EXAMPLEuniqueKey"},"type":"order.created","updated_at":"2026-11-03T15:00:00+00:00"},"next_retry_at":null,"sent_at":"2026-11-03T15:00:00+00:00","status":"success","status_code":200,"updated_at":"2026-11-03T15:00:00+00:00","url":"https://example.com/yoprint/webhooks","webhook_message_id":"VwYKuTP9vd8Dfo","webhook_subscription_id":"V4keXwwxMQyXw7"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"properties":{"attempt":{"description":"Attempts made so far: 0 before the first, at most 3.","example":1,"type":"integer"},"created_at":{"description":"When the delivery was queued.","example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"error":{"description":"Why the delivery failed. Null after a successful attempt (`status: success`). YoPrint never stores your endpoint's response body. For a failed attempt, this is one of:\n\n- `The receiver answered with HTTP {status}.` (your endpoint returned an HTTP status other than 200)\n- `Could not reach the receiver (connection, DNS, TLS or timeout error).`\n- `Delivery failed before the receiver answered.`\n- `Not sent: the webhook URL does not reach a public internet address.`\n- `Not sent: this server cannot hold the connection to the checked receiver address.`","example":null,"type":["string","null"]},"id":{"description":"The delivery id: one event to one subscription.","example":"gxL14iJJPyg63n","type":"string"},"message":{"properties":{"created_at":{"description":"When the event happened.","example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"id":{"description":"The event id. Every attempt to deliver this event, to every subscription, carries the same id.","example":"VwYKuTP9vd8Dfo","type":"string"},"payload":{"additionalProperties":true,"description":"The record the event is about, as it was when the event happened. Its fields depend on the event; see \"Events\" on Create a webhook subscription.","example":{"calc_total":125000,"formatted_calc_total":"$125.00","id":"BkzhmfgkK2HFTs","name":"Team shirts","scoped_id":"SO1001","status_id":"PLksRyu0AR7Bv4","unique_key":"ord_EXAMPLEuniqueKey"},"type":"object"},"type":{"description":"The event name.","example":"order.created","type":"string"},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"required":["id","type","payload","created_at","updated_at"],"type":"object"},"next_retry_at":{"description":"When YoPrint tries again, or null when it will not (after a success, or after the last attempt).","example":null,"format":"date-time","type":["string","null"]},"sent_at":{"description":"When the latest attempt was made. Before the first attempt (`status` `pending`), when the delivery was queued. Never null.","example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"status":{"description":"`pending` before the first attempt, `success` when the latest attempt got exactly `200`, `error` for any other status code.","enum":["pending","success","error"],"example":"success","type":"string"},"status_code":{"description":"The HTTP status your endpoint returned on the latest attempt (such as `200` or `500`). Set to `999` when no response was received (for example, connection timeouts, DNS lookup failures, TLS errors, or if the request was blocked before sending). Null before the first attempt.","example":200,"type":["integer","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"url":{"description":"The destination URL for the latest delivery attempt: the full URL on this API. AI apps reading deliveries through YoPrint's MCP server see only the origin (scheme and host, such as `https://example.com`).","example":"https://example.com/yoprint/webhooks","type":["string","null"]},"webhook_message_id":{"description":"The event id, the same as `id` in the body YoPrint sent.","example":"VwYKuTP9vd8Dfo","type":"string"},"webhook_subscription_id":{"example":"V4keXwwxMQyXw7","type":"string"}},"required":["id","webhook_message_id","webhook_subscription_id","attempt","sent_at","next_retry_at","status_code","status","error","url","message","created_at","updated_at"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List deliveries for a webhook subscription","tags":["Webhook subscriptions"],"x-yoprint-docs":{"errors":[{"fix":"Send your personal API key as `Authorization: Bearer YOUR_API_KEY`.","status":401,"when":"The API key is missing or wrong."},{"fix":"Use an `id` from the list operation and check the team slug.","status":404,"when":"No webhook subscription with that id on this team (`error.code` is null and `error.message` starts \"No query results\"), the id is not one of this team's hash ids, or you are not a member of the team (both `page_not_found`)."}],"group":"Team settings","notes":["A delivery shows only its latest attempt. `attempt` counts them.","`status` is `success` only for exactly `200`. Any other `2xx` shows as `error`, even though YoPrint stopped retrying.","The path parameter is the subscription id."],"permission":"Any team member can call it. Reading needs no extra permission.","related":["v1_public_webhook_subscription_show","v1_public_webhook_subscription_update_patch"]}}},"/v1/api/store/{team_slug}/shipment/action/export_csv":{"post":{"description":"Returns a CSV file (`shipment_export_<time>.csv`) with one row per shipment: order number, shipment number (`SHIP-...`), shipping type, customer name, email and contact, and the full shipping address. Made while you wait.","operationId":"v1_public_shipment_export_csv","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"items":["MQyJUnd3oty75h","dNJl954DcXrrND"]},"schema":{"properties":{"items":{"description":"Shipment hash ids. Send an array, even for one.","items":{"type":"string"},"minItems":1,"type":"array"}},"required":["items"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"text/csv":{"schema":{"format":"binary","type":"string"}}},"description":"The CSV file, as an attachment."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/FeatureGatedValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download shipments as CSV","tags":["Shipments"],"x-yoprint-docs":{"errors":[{"fix":"Send an array of your shipment hash ids.","status":422,"when":"`items` is missing, the plan lacks data export, or no id is your team's shipment (`shipment_export_error`, \"Shipment not found\")."},{"fix":"Leave incomplete shipments out (`is_valid` false), or set the shipping type first.","status":500,"when":"One of the shipments has no shipping type, or its order has no customer: the whole export fails with `{ \"message\": \"Server Error\" }`."}],"group":"Shipping","permission":"Any member of the team, on a plan with data export.","related":["v1_public_shipment_filter"],"rules":["Needs the data export feature on your plan: otherwise 422 \"This feature is not available to your team's plan.\""]}}},"/v1/api/store/{team_slug}/shipment/export_label":{"post":{"description":"Returns one PDF of 4\" x 6\" shipment labels (ship-from and ship-to addresses and a barcode), one per shipment, made while you wait.","operationId":"v1_public_shipment_export_label","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"MQyJUnd3oty75h"},{"id":"dNJl954DcXrrND"}],"schema":{"description":"The shipments to include, as a JSON array of objects (not an object with a list inside).","items":{"properties":{"id":{"description":"The hash id of one of the shipments.","example":"MQyJUnd3oty75h","type":"string"}},"required":["id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"The labels as a PDF, shown inline (`Content-Disposition: inline`)."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download 4x6 shipment labels (PDF)","tags":["Shipments"],"x-yoprint-docs":{"errors":[{"fix":"Send at most 100 `{ \"id\": ... }` objects.","status":422,"when":"More than 100 ids (`limit_reached`), or an item without a valid `id`."},{"fix":"Send shipment hash ids from Filter shipments.","status":404,"when":"None of the ids is a shipment of your team (`shipment_not_found`)."}],"group":"Shipping","permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_shipment_export_label_full","v1_public_shipment_export_packing_slip"],"rules":["Send between 1 and 100 shipment ids as `[{ \"id\": ... }]`. More than 100 is a 422 `limit_reached` (\"we only allow export of 100 shipments at a time\").","Ids that aren't your team's shipments are skipped; when none is left the reply is 404 `shipment_not_found`.","These are YoPrint documents (addresses and barcode), not carrier postage labels. Carrier labels come from Download labels as one PDF."]}}},"/v1/api/store/{team_slug}/shipment/export_label_full":{"post":{"description":"Returns one PDF of letter-size shipment labels, one per shipment, made while you wait. Otherwise the same as Download 4x6 shipment labels.","operationId":"v1_public_shipment_export_label_full","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"MQyJUnd3oty75h"},{"id":"dNJl954DcXrrND"}],"schema":{"description":"The shipments to include, as a JSON array of objects (not an object with a list inside).","items":{"properties":{"id":{"description":"The hash id of one of the shipments.","example":"MQyJUnd3oty75h","type":"string"}},"required":["id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"The labels as a PDF, shown inline (`Content-Disposition: inline`)."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download letter-size shipment labels (PDF)","tags":["Shipments"],"x-yoprint-docs":{"errors":[{"fix":"Send at most 100 `{ \"id\": ... }` objects.","status":422,"when":"More than 100 ids (`limit_reached`), or an item without a valid `id`."},{"fix":"Send shipment hash ids from Filter shipments.","status":404,"when":"None of the ids is a shipment of your team (`shipment_not_found`)."}],"group":"Shipping","permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_shipment_export_label"],"rules":["Send between 1 and 100 shipment ids as `[{ \"id\": ... }]`. More than 100 is a 422 `limit_reached` (\"we only allow export of 100 shipments at a time\").","Ids that aren't your team's shipments are skipped; when none is left the reply is 404 `shipment_not_found`.","These are YoPrint documents (addresses and barcode), not carrier postage labels. Carrier labels come from Download labels as one PDF."]}}},"/v1/api/store/{team_slug}/shipment/export_packing_slip":{"post":{"description":"Returns one PDF with a packing slip per shipment, made while you wait.","operationId":"v1_public_shipment_export_packing_slip","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"MQyJUnd3oty75h"},{"id":"dNJl954DcXrrND"}],"schema":{"description":"The shipments to include, as a JSON array of objects (not an object with a list inside).","items":{"properties":{"id":{"description":"The hash id of one of the shipments.","example":"MQyJUnd3oty75h","type":"string"}},"required":["id"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"The packing slips as a PDF, shown inline (`Content-Disposition: inline`)."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download packing slips (PDF)","tags":["Shipments"],"x-yoprint-docs":{"errors":[{"fix":"Send at most 100 `{ \"id\": ... }` objects.","status":422,"when":"More than 100 ids (`limit_reached`), or an item without a valid `id`."},{"fix":"Send shipment hash ids from Filter shipments.","status":404,"when":"None of the ids is a shipment of your team (`shipment_not_found`)."}],"group":"Shipping","permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_shipment_export_label","v1_public_shipment_filter"],"rules":["Send between 1 and 100 shipment ids as `[{ \"id\": ... }]`. More than 100 is a 422 `limit_reached` (\"we only allow export of 100 shipments at a time\").","Ids that aren't your team's shipments are skipped; when none is left the reply is 404 `shipment_not_found`.","These are YoPrint documents (addresses and barcode), not carrier postage labels. Carrier labels come from Download labels as one PDF."]}}},"/v1/api/store/{team_slug}/shipment/filter":{"post":{"description":"Returns one page of your team's shipments that match the filters, across all sales orders (quotes, drafts and deleted shipments are left out).\n\nEach row is a summary with its packages and estimates: number (`scoped_id`, here without the `SHIP-` prefix), order, shipping type, due dates, `ready_to_ship`, packer, status, customer, address and `pdf` links.\n\nEvery condition in `filters` must match (they are joined with AND). Omit `filters` for no filter; an empty array is a 422. A `key` that isn't in the table, a missing `operator` or `value`, or a value of the wrong kind fails the whole request with 422; the message for `filters` (or `sort`) is the bare rule name `validation.filter_rule` (or `validation.filter_sort_rule`), with no detail, so check each filter against the table. Send real values: no key here matches empty columns with `\"null\"` or `\"\"` (for dates, use the `..._is_set` keys where the table has them). Hash ids in `value` are decoded for you. `system-current-user` stands for the caller only where a key's row says so; elsewhere it is compared as a raw value, so with `in` it matches nothing and with `nin` it matches every row that has a value.\n\n| `key` | Kind | Operators and `value` | Meaning |\n| --- | --- | --- | --- |\n| `status_id` | Hash ids | `in` or `nin`, with an array of hash ids. | The shipment status (from List shipment statuses). |\n| `status_type` | Options | `in` or `nin`, with an array of the listed values. | The kind of status: `start` (Pending), `pre_production` or `in_progress` (In Progress), `end` (Completed). |\n| `shipping_type_id` | Hash ids | `in` or `nin`, with an array of hash ids. | The shipping type. |\n| `ready_to_ship` | Yes or no | `eq` or `neq`, with `true` or `false`. | Every job of the shipment's lines is Completed. |\n| `packed_by` | Hash ids | `in` or `nin`, with an array of hash ids. | Who packed it: an array of user hash ids. `system-current-user` is not supported here: with `in` it matches nothing, with `nin` every shipment with a packer. |\n| `customer_due_date` | Date | `eq`, `gte` or `lte`, with a whole number of days counted from now (UTC). See below. | The order's customer due date. This key uses its own date comparison rather than the rule below (it compares the date with the current time), so `eq` may match nothing: use `gte` and `lte` and check the edge days. |\n| `status_last_change_date` | Date | `eq`, `gte` or `lte`, with a whole number of days counted from now (UTC). See below. | When the status last changed. |\n| `status_completion_date` | Date | `eq`, `gte` or `lte`, with a whole number of days counted from now (UTC). See below. | When the shipment reached a Completed status. |\n| `ship_due_date` | Date | `eq`, `gte` or `lte`, with a whole number of days counted from now (UTC). See below. | Don't use: accepted, but this route can't apply it and fails with a server error. |\n| `order_external_type` | Options | `in` or `nin`, with an array of the listed values. | Don't use (`shopify`, `native`): accepted, but this route can't apply it and fails with a server error. |\n| `shipment_source` | Options | `in` or `nin`, with an array of the listed values. | Don't use (`shopify`, `yoprint`, `broken_link`): accepted, but this route can't apply it and fails with a server error. |\n\nA date filter's `value` is a whole number of days, counted from the moment of the request in UTC: `eq` N matches the whole UTC day N days from today (0 is today, -1 yesterday); `gte` N matches dates on or after now plus N days; `lte` N matches dates on or before now **minus** N days. So \"due in the next 7 days\" is `due_date gte 0` and `due_date lte -7`, and \"overdue\" is `due_date lte 0`. This differs from the v2 filters (Filter invoices, the production control calendar), where `lte` and `gte` both count forward.\n\nThe response is one page with `pagination`. The page size is the team's list page size setting (50 unless the team changed it); `per_page` is not read. Send `page` (from 1) in the body or the query string for later pages.","operationId":"v1_public_shipment_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"filters":[{"key":"ready_to_ship","operator":"eq","value":true},{"key":"status_type","operator":"nin","value":["end"]}],"page":1,"sort":[{"direction":"asc","key":"customer_due_date"}]},"schema":{"properties":{"filters":{"description":"Conditions, all of which must match. Omit for no filter.","items":{"properties":{"key":{"description":"What to filter on. See the table in the description.","enum":["status_id","status_type","shipping_type_id","ready_to_ship","packed_by","customer_due_date","status_last_change_date","status_completion_date","ship_due_date","order_external_type","shipment_source"],"type":"string"},"operator":{"description":"How to compare. Each kind of key accepts only some operators.","enum":["eq","neq","gt","gte","lt","lte","in","nin","bt","ct","sw","ew"],"type":"string"},"value":{"description":"What to compare with: text, a number of days, true or false, or an array of hash ids or options, by kind of key.","items":{"type":"string"},"type":["string","number","boolean","array"]}},"required":["key","operator","value"],"type":"object"},"minItems":1,"type":"array"},"page":{"default":1,"description":"The page to read.","minimum":1,"type":"integer"},"sort":{"description":"Sort keys, applied in order. Without `sort` the order is not guaranteed.","items":{"properties":{"direction":{"enum":["asc","desc"],"type":"string"},"key":{"enum":["order_id","status_id","customer_due_date","ship_due_date","shipping_type_id","ready_to_ship","status_last_change_date","status_completion_date"],"type":"string"}},"required":["key","direction"],"type":"object"},"type":"array"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"customer":{"name":"Northwind Apparel"},"customer_due_date":"2026-11-10T00:00:00+00:00","customer_id":"ifAHmADekGZ6id","has_third_party_fulfilled_items":false,"id":"MQyJUnd3oty75h","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","packed_by":null,"pdf":[{"description":"Packing slip with white labeling","label":"Packing Slip","object_type":"shipment","url":"https://example.com/pdf/packing-slip.pdf"}],"ready_to_ship":false,"scoped_id":"12","ship_due_date":"2026-11-08T00:00:00+00:00","shipment_estimates":[{"created_at":"2026-11-03T15:00:00+00:00","frontend_data":[],"frontend_data_version":null,"goshippo_selected_rate_id":"rate_0001","goshippo_shipment_id":"shipment_0001","id":"tVjoZLKlSwZFF5","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","shippo_address_from":{"city":"Austin","company":"","country":"US","email":"","name":"Northwind Apparel","phone":"+1 201 555 0123","state":"TX","street1":"100 Example Street","street2":"","zip":"78701"},"shippo_address_to":{"city":"Denver","company":"","country":"US","email":"alex@example.com","name":"Alex Rivera","phone":"","state":"CO","street1":"100 Example Street","street2":"","zip":"80202"},"shippo_carrier_accounts":[],"shippo_extra":null,"shippo_object_id":"shipment_0001","shippo_parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"shippo_rates":[{"amount":"12.40","amount_local":"12.40","arrives_by":null,"attributes":["CHEAPEST"],"carrier_account":"carrier_0001","currency":"USD","currency_local":"USD","duration_terms":"Delivery in 2 to 5 days.","estimated_days":3,"included_insurance_price":null,"messages":[],"object_created":"2026-11-03T15:00:00Z","object_id":"rate_0001","object_updated":"2026-11-03T15:00:00Z","provider":"USPS","provider_image_200":"https://example.com/usps_200.png","provider_image_75":"https://example.com/usps_75.png","servicelevel":{"extended_token":"usps_ground_advantage","name":"Ground Advantage","terms":"","token":"usps_ground_advantage"},"shipment":"shipment_0001"}],"shippo_shipment_date":"2026-11-03T15:00:00Z","shippo_status":"SUCCESS","type":"integration_shippo"}],"shipment_packages":[{"charges":12400,"created_at":"2026-11-03T15:00:00+00:00","goshippo":{"parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"provider":"USPS","rate_id":"rate_0001"},"height":"4","id":"o6foWpSAayc79D","is_master":true,"length":"12","length_unit":"IN","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","parent_id":null,"pdf":[{"description":"Postage label individually to be printed 4\" x 6\" label","label":"Postage Label (4 in x 6 in label)","url":"https://example.com/labels/o6foWpSAayc79D.pdf"}],"provider_name":"USPS","provider_saturday_delivery":false,"provider_service_code":null,"provider_service_name":"Ground Advantage","provider_shipment_id":"transaction_0001","provider_tracking_number":"9400100000000000000000","shipment_has_third_party_fulfilled_items":false,"shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","status":"pending","type":"goshippo","weight":"2","weight_unit":"LB","width":"10"}],"shipping_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"shipping_type_id":"6OTWtTOpYcBz8q","shipping_type_name":"USPS Ground Advantage","status_id":"AvY6ZbnrTJqpUI"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A shipment summary with its packages and estimates.","properties":{"customer":{"additionalProperties":true,"properties":{"name":{"type":["string","null"]}},"type":"object"},"customer_due_date":{"description":"The order's customer due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"has_third_party_fulfilled_items":{"type":"boolean"},"id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"packed_by":{"description":"Who packed it.","example":null,"type":["string","null"]},"pdf":{"description":"The packing slip and the shipment label in Letter, 4\" x 6\" and 1\" x 2-1/8\" sizes (`is_custom` absent), then one entry per enabled custom shipment PDF template (`label`, `type`, `description`, `url`, the `show_in_*` flags, `is_custom: true`).","items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"is_custom":{"description":"True on custom template entries.","type":"boolean"},"label":{"type":"string"},"object_type":{"type":"string"},"url":{"description":"A download link with its own access token.","type":"string"}},"type":"object"},"type":"array"},"ready_to_ship":{"type":"boolean"},"scoped_id":{"description":"The shipment number, here without the `SHIP-` prefix.","example":"12","type":"string"},"ship_due_date":{"description":"The order's ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shipment_estimates":{"items":{"additionalProperties":true,"description":"A saved shipping estimate.","properties":{"created_at":{"format":"date-time","type":"string"},"frontend_data":{"description":"What you sent as `frontend_data`; an empty list `[]` when you sent none.","type":["object","array"]},"frontend_data_version":{"description":"What you sent, or null."},"goshippo_selected_rate_id":{"description":"The rate chosen when it was saved.","example":"rate_0001","type":["string","null"]},"goshippo_shipment_id":{"description":"The Shippo shipment.","example":"shipment_0001","type":["string","null"]},"id":{"description":"The estimate.","example":"tVjoZLKlSwZFF5","type":"string"},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":["string","null"]},"shippo_address_from":{"additionalProperties":true,"type":"object"},"shippo_address_to":{"additionalProperties":true,"type":"object"},"shippo_carrier_accounts":{"items":{"type":"string"},"type":"array"},"shippo_extra":{"description":"The label options, or null."},"shippo_object_id":{"type":["string","null"]},"shippo_parcels":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"shippo_rates":{"description":"Every rate of that Shippo shipment, as saved (`amount` is a decimal string).","items":{"additionalProperties":true,"description":"A rate, with exactly these keys. Keys Shippo leaves out come back as empty strings.","properties":{"amount":{"example":"12.40","type":"string"},"amount_local":{"example":"12.40","type":"string"},"arrives_by":{"example":null,"type":["string","null"]},"attributes":{"description":"Shippo's tags, for example `CHEAPEST`.","example":["CHEAPEST"],"items":{"type":"string"},"type":"array"},"carrier_account":{"example":"carrier_0001","type":"string"},"currency":{"example":"USD","type":"string"},"currency_local":{"example":"USD","type":"string"},"duration_terms":{"example":"Delivery in 2 to 5 days.","type":["string","null"]},"estimated_days":{"example":3,"type":["integer","null"]},"included_insurance_price":{"example":null,"type":["string","null"]},"messages":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"object_created":{"example":"2026-11-03T15:00:00Z","type":"string"},"object_id":{"description":"The rate id. Send it as `rate_id` to buy this label.","example":"rate_0001","type":"string"},"object_updated":{"example":"2026-11-03T15:00:00Z","type":"string"},"provider":{"example":"USPS","type":"string"},"provider_image_200":{"example":"https://example.com/usps_200.png","type":"string"},"provider_image_75":{"description":"A URL of the carrier logo.","example":"https://example.com/usps_75.png","type":"string"},"servicelevel":{"additionalProperties":false,"description":"Exactly these four keys; null when Shippo sends no service level.","properties":{"extended_token":{"example":"usps_ground_advantage","type":"string"},"name":{"example":"Ground Advantage","type":"string"},"terms":{"example":"","type":"string"},"token":{"example":"usps_ground_advantage","type":"string"}},"type":"object"},"shipment":{"description":"The Shippo shipment this rate belongs to.","example":"shipment_0001","type":"string"}},"type":"object"},"type":"array"},"shippo_shipment_date":{"type":["string","null"]},"shippo_status":{"example":"SUCCESS","type":["string","null"]},"type":{"example":"integration_shippo","type":"string"}},"type":"object"},"type":"array"},"shipment_packages":{"items":{"additionalProperties":true,"description":"A package.","properties":{"charges":{"description":"The label cost. For a multi-parcel label every package repeats the rate's full amount: read the master's value and don't add packages up. Null for external labels. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12400,"type":["integer","number","string","null"]},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"from_address":{"description":"The address record behind `from_address_id`, or null when it is not set."},"from_address_id":{"description":"Older packages only: the ship-from address record; null otherwise.","example":null,"type":["string","null"]},"goshippo":{"additionalProperties":true,"description":"Shippo labels only: the Shippo details (shipment, rate, carrier, addresses, parcels).","properties":{"address_from":{"description":"The ship-from address sent to Shippo."},"address_return":{"description":"The return address sent to Shippo."},"address_to":{"description":"The ship-to address sent to Shippo."},"carrier_id":{"description":"The Shippo carrier account.","type":["string","null"]},"parcel_id":{"description":"The Shippo parcel.","type":["string","null"]},"parcels":{"description":"The parcels of the Shippo shipment."},"provider":{"type":["string","null"]},"provider_image_200":{"type":["string","null"]},"provider_image_75":{"type":["string","null"]},"provider_tracking_number":{"type":["string","null"]},"rate_id":{"description":"The Shippo rate bought.","type":["string","null"]},"shipment_data":{"description":"The Shippo shipment the rate came from."},"shipment_id":{"description":"The Shippo shipment.","type":["string","null"]}},"type":"object"},"height":{"description":"Parcel size and weight as stored, in `length_unit` and `weight_unit`. Null for external labels.","type":["number","string","null"]},"id":{"description":"The package.","example":"o6foWpSAayc79D","type":"string"},"is_master":{"description":"The first package of a label (the others have `parent_id`).","type":"boolean"},"length":{"type":["number","string","null"]},"length_unit":{"description":"Shippo labels only, upper case.","example":"IN","type":["string","null"]},"order_external_ids":{"description":"The order's links to external systems.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_external_type":{"description":"`shopify` when the order came from Shopify.","type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"example":"sales_order","type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"parent_id":{"description":"The master package, for the other parcels of a multi-parcel label.","example":null,"type":["string","null"]},"pdf":{"description":"Not on external labels: the label file. `label` and `description` are fixed texts that always say 4 x 6, whatever your label size setting.","items":{"additionalProperties":true,"properties":{"description":{"example":"Postage label individually to be printed 4\" x 6\" label","type":"string"},"label":{"example":"Postage Label (4 in x 6 in label)","type":"string"},"url":{"description":"For a Shippo label, Shippo's signed link to the label file: don't publish it.","type":"string"}},"type":"object"},"type":"array"},"provider_name":{"description":"The carrier.","example":"USPS","type":["string","null"]},"provider_saturday_delivery":{"description":"Shippo labels only (absent on external labels); always false today.","type":"boolean"},"provider_service_code":{"description":"For external labels, `ups`, `fedex` or `other`. For Shippo labels it may be null: read the service from `provider_service_name`.","type":["string","null"]},"provider_service_name":{"example":"Ground Advantage","type":["string","null"]},"provider_shipment_id":{"description":"The Shippo transaction id (Shippo labels).","type":["string","null"]},"provider_tracking_number":{"example":"9400100000000000000000","type":["string","null"]},"shipment_external_type":{"description":"`shopify` when the shipment is linked to Shopify.","type":["string","null"]},"shipment_has_third_party_fulfilled_items":{"type":"boolean"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":"string"},"shipment_shopify_sync":{"description":"Shopify sync state of the shipment."},"status":{"enum":["pending","ready-to-ship","shipped","delivered"],"example":"pending","type":"string"},"to_address":{"description":"The address record behind `to_address_id`, or null when it is not set."},"to_address_id":{"description":"Older packages only: the ship-to address record; null otherwise.","example":null,"type":["string","null"]},"type":{"description":"`goshippo` a label bought through Shippo; `external_label` a label recorded from elsewhere.","enum":["goshippo","external_label","single_label"],"example":"goshippo","type":"string"},"weight":{"type":["number","string","null"]},"weight_unit":{"description":"Shippo labels only, upper case.","example":"LB","type":["string","null"]},"width":{"type":["number","string","null"]}},"type":"object"},"type":"array"},"shipping_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"shipping_type_id":{"description":"The shipping type.","example":"6OTWtTOpYcBz8q","type":["string","null"]},"shipping_type_name":{"example":"USPS Ground Advantage","type":["string","null"]},"status_id":{"description":"The shipment status.","example":"AvY6ZbnrTJqpUI","type":["string","null"]}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Filter shipments","tags":["Shipments"],"x-yoprint-docs":{"errors":[{"fix":"Check each filter against the table.","status":422,"when":"A filter has an unknown `key`, a missing part, or an operator or value its kind doesn't accept."},{"fix":"Leave those keys out.","status":500,"when":"You filtered on `ship_due_date`, `order_external_type` or `shipment_source`."}],"group":"Shipping","permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_shipment_show","v1_public_status_list_shipment","v1_public_shipment_export_packing_slip"]}}},"/v1/api/store/{team_slug}/shipment_package/filter":{"post":{"description":"Returns one page of your team's packages across all sales orders (quotes, drafts and autosave copies are left out) that match the filters.\n\nEvery condition in `filters` must match (they are joined with AND). Omit `filters` for no filter; an empty array is a 422. A `key` that isn't in the table, a missing `operator` or `value`, or a value of the wrong kind fails the whole request with 422; the message for `filters` (or `sort`) is the bare rule name `validation.filter_rule` (or `validation.filter_sort_rule`), with no detail, so check each filter against the table. Send real values: no key here matches empty columns with `\"null\"` or `\"\"` (for dates, use the `..._is_set` keys where the table has them). Hash ids in `value` are decoded for you. `system-current-user` stands for the caller only where a key's row says so; elsewhere it is compared as a raw value, so with `in` it matches nothing and with `nin` it matches every row that has a value.\n\n| `key` | Kind | Operators and `value` | Meaning |\n| --- | --- | --- | --- |\n| `status` | Options | `in` or `nin`, with an array of the listed values. | The package status: `pending`, `ready-to-ship`, `shipped`, `delivered`. |\n| `shipment_status_id` | Hash ids | `in` or `nin`, with an array of hash ids. | The status of the package's shipment. |\n| `created_at` | Date | `eq`, `gte` or `lte`, with a whole number of days counted from now (UTC). See below. | When the package was created. |\n\nA date filter's `value` is a whole number of days, counted from the moment of the request in UTC: `eq` N matches the whole UTC day N days from today (0 is today, -1 yesterday); `gte` N matches dates on or after now plus N days; `lte` N matches dates on or before now **minus** N days. So \"due in the next 7 days\" is `due_date gte 0` and `due_date lte -7`, and \"overdue\" is `due_date lte 0`. This differs from the v2 filters (Filter invoices, the production control calendar), where `lte` and `gte` both count forward.\n\nThe response is one page with `pagination`. The page size is the team's list page size setting (50 unless the team changed it); `per_page` is not read. Send `page` (from 1) in the body or the query string for later pages.","operationId":"v1_public_shipment_package_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"filters":[{"key":"status","operator":"in","value":["pending","ready-to-ship"]}],"page":1,"sort":[{"direction":"desc","key":"created_at"}]},"schema":{"properties":{"filters":{"description":"Conditions, all of which must match. Omit for no filter.","items":{"properties":{"key":{"description":"What to filter on. See the table in the description.","enum":["status","shipment_status_id","created_at"],"type":"string"},"operator":{"description":"How to compare. Each kind of key accepts only some operators.","enum":["eq","neq","gt","gte","lt","lte","in","nin","bt","ct","sw","ew"],"type":"string"},"value":{"description":"What to compare with: text, a number of days, true or false, or an array of hash ids or options, by kind of key.","items":{"type":"string"},"type":["string","number","boolean","array"]}},"required":["key","operator","value"],"type":"object"},"minItems":1,"type":"array"},"page":{"default":1,"description":"The page to read.","minimum":1,"type":"integer"},"sort":{"description":"Sort keys, applied in order. Without `sort` the order is not guaranteed.","items":{"properties":{"direction":{"enum":["asc","desc"],"type":"string"},"key":{"enum":["order_id","shipment_id","status","provider_service_name","created_at"],"type":"string"}},"required":["key","direction"],"type":"object"},"type":"array"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"charges":12400,"created_at":"2026-11-03T15:00:00+00:00","goshippo":{"parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"provider":"USPS","rate_id":"rate_0001"},"height":"4","id":"o6foWpSAayc79D","is_master":true,"length":"12","length_unit":"IN","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","parent_id":null,"pdf":[{"description":"Postage label individually to be printed 4\" x 6\" label","label":"Postage Label (4 in x 6 in label)","url":"https://example.com/labels/o6foWpSAayc79D.pdf"}],"provider_name":"USPS","provider_saturday_delivery":false,"provider_service_code":null,"provider_service_name":"Ground Advantage","provider_shipment_id":"transaction_0001","provider_tracking_number":"9400100000000000000000","shipment_has_third_party_fulfilled_items":false,"shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","status":"pending","type":"goshippo","weight":"2","weight_unit":"LB","width":"10"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A package.","properties":{"charges":{"description":"The label cost. For a multi-parcel label every package repeats the rate's full amount: read the master's value and don't add packages up. Null for external labels. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12400,"type":["integer","number","string","null"]},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"from_address":{"description":"The address record behind `from_address_id`, or null when it is not set."},"from_address_id":{"description":"Older packages only: the ship-from address record; null otherwise.","example":null,"type":["string","null"]},"goshippo":{"additionalProperties":true,"description":"Shippo labels only: the Shippo details (shipment, rate, carrier, addresses, parcels).","properties":{"address_from":{"description":"The ship-from address sent to Shippo."},"address_return":{"description":"The return address sent to Shippo."},"address_to":{"description":"The ship-to address sent to Shippo."},"carrier_id":{"description":"The Shippo carrier account.","type":["string","null"]},"parcel_id":{"description":"The Shippo parcel.","type":["string","null"]},"parcels":{"description":"The parcels of the Shippo shipment."},"provider":{"type":["string","null"]},"provider_image_200":{"type":["string","null"]},"provider_image_75":{"type":["string","null"]},"provider_tracking_number":{"type":["string","null"]},"rate_id":{"description":"The Shippo rate bought.","type":["string","null"]},"shipment_data":{"description":"The Shippo shipment the rate came from."},"shipment_id":{"description":"The Shippo shipment.","type":["string","null"]}},"type":"object"},"height":{"description":"Parcel size and weight as stored, in `length_unit` and `weight_unit`. Null for external labels.","type":["number","string","null"]},"id":{"description":"The package.","example":"o6foWpSAayc79D","type":"string"},"is_master":{"description":"The first package of a label (the others have `parent_id`).","type":"boolean"},"length":{"type":["number","string","null"]},"length_unit":{"description":"Shippo labels only, upper case.","example":"IN","type":["string","null"]},"order_external_ids":{"description":"The order's links to external systems.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_external_type":{"description":"`shopify` when the order came from Shopify.","type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"example":"sales_order","type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"parent_id":{"description":"The master package, for the other parcels of a multi-parcel label.","example":null,"type":["string","null"]},"pdf":{"description":"Not on external labels: the label file. `label` and `description` are fixed texts that always say 4 x 6, whatever your label size setting.","items":{"additionalProperties":true,"properties":{"description":{"example":"Postage label individually to be printed 4\" x 6\" label","type":"string"},"label":{"example":"Postage Label (4 in x 6 in label)","type":"string"},"url":{"description":"For a Shippo label, Shippo's signed link to the label file: don't publish it.","type":"string"}},"type":"object"},"type":"array"},"provider_name":{"description":"The carrier.","example":"USPS","type":["string","null"]},"provider_saturday_delivery":{"description":"Shippo labels only (absent on external labels); always false today.","type":"boolean"},"provider_service_code":{"description":"For external labels, `ups`, `fedex` or `other`. For Shippo labels it may be null: read the service from `provider_service_name`.","type":["string","null"]},"provider_service_name":{"example":"Ground Advantage","type":["string","null"]},"provider_shipment_id":{"description":"The Shippo transaction id (Shippo labels).","type":["string","null"]},"provider_tracking_number":{"example":"9400100000000000000000","type":["string","null"]},"shipment_external_type":{"description":"`shopify` when the shipment is linked to Shopify.","type":["string","null"]},"shipment_has_third_party_fulfilled_items":{"type":"boolean"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":"string"},"shipment_shopify_sync":{"description":"Shopify sync state of the shipment."},"status":{"enum":["pending","ready-to-ship","shipped","delivered"],"example":"pending","type":"string"},"to_address":{"description":"The address record behind `to_address_id`, or null when it is not set."},"to_address_id":{"description":"Older packages only: the ship-to address record; null otherwise.","example":null,"type":["string","null"]},"type":{"description":"`goshippo` a label bought through Shippo; `external_label` a label recorded from elsewhere.","enum":["goshippo","external_label","single_label"],"example":"goshippo","type":"string"},"weight":{"type":["number","string","null"]},"weight_unit":{"description":"Shippo labels only, upper case.","example":"LB","type":["string","null"]},"width":{"type":["number","string","null"]}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Filter packages","tags":["Shipment packages"],"x-yoprint-docs":{"errors":[{"fix":"Check each filter against the table.","status":422,"when":"A filter breaks the table."}],"group":"Shipping","permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_shipment_package_index","v1_public_shipment_package_track"]}}},"/v1/api/store/{team_slug}/shipment_package/{id}/track":{"patch":{"description":"Asks Shippo for the package's current tracking and returns Shippo's track object, unchanged, as `data` (its fields are Shippo's: carrier, tracking number, current status and history). The answer is not the usual envelope: it is `{ \"status\": 200, \"success\": true, \"type\": \"<package type>\", \"data\": {...} }`, with `status` the integer 200 and `type` `goshippo` or `external_label`. Despite the PATCH method it changes nothing in YoPrint: package status isn't updated from tracking.\n\nFor a package YoPrint can't track (recorded with Record a label bought elsewhere, or whose Shippo integration is gone), `data` is `{ \"packages\": null }`.","operationId":"v1_public_shipment_package_track","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The package's hash id. Hash ids only: a unique key or a document number gives 404.","example":"o6foWpSAayc79D","in":"path","name":"id","required":true,"schema":{"example":"o6foWpSAayc79D","type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"tracked":{"summary":"A Shippo package","value":{"data":{"carrier":"usps","eta":"2026-11-06T00:00:00Z","tracking_history":[{"status":"PRE_TRANSIT","status_date":"2026-11-03T09:00:00Z","status_details":"Label created"}],"tracking_number":"EXAMPLE-TRACKING-0001","tracking_status":{"status":"TRANSIT","status_date":"2026-11-04T09:00:00Z","status_details":"In transit to destination"}},"status":200,"success":true,"type":"goshippo"}},"untracked":{"summary":"A label bought elsewhere","value":{"data":{"packages":null},"status":200,"success":true,"type":"external_label"}}},"schema":{"properties":{"data":{"additionalProperties":true,"description":"Shippo's track object as Shippo sent it (for example `carrier`, `tracking_number`, `tracking_status`, `tracking_history`, `eta`), or `{ \"packages\": null }` when the package can't be tracked.","type":"object"},"status":{"const":200,"description":"Always the integer 200.","type":"integer"},"success":{"const":true,"type":"boolean"},"type":{"description":"The package type.","enum":["goshippo","external_label"],"type":"string"}},"required":["status","success","type","data"],"type":"object"}}},"description":"The package type and Shippo's track object, in a body of its own (not the usual envelope)."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get live tracking for a package","tags":["Shipment packages"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Check the package id.","status":404,"when":"The package isn't your team's."},{"fix":"Check the addresses, parcels and ids, then retry once. Do not loop.","status":500,"when":"Shippo refused the request or could not be reached. Shippo errors are not translated into 4xx replies."}],"group":"Shipping","notes":["To mark a package shipped or delivered, update the package `status` yourself."],"permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_shipment_package_show","v2_public_shipment_package_update"],"response":"free-form","side_effects":["Calls Shippo's tracking API for a Shippo package (read-only; it buys nothing). Saves nothing."]}}},"/v1/api/store/{team_slug}/source-imports/activity":{"get":{"description":"Lists the Import Portal's import activity, newest first unless you ask for `sort=oldest`, with paging by cursor. Pass `meta.next_cursor` as `cursor` to read the next page. The answer is plain JSON, `{data, meta}`, not the usual `{success, status, data}` envelope.\n\nCSV events are the Import Portal's CSV imports of customers, vendors and products, once finished: `import_completed`, `import_partial_completed` or `import_failed`, with counts. You see each kind only if you can import it. Service pricing uploads are not in this feed; list them with `GET /v1/api/store/{team_slug}/imports`.","operationId":"v1_public_source_imports_activity_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"in":"query","name":"source","required":false,"schema":{"default":"all","enum":["all","csv"],"type":"string"}},{"in":"query","name":"sort","required":false,"schema":{"default":"newest","enum":["newest","oldest"],"type":"string"}},{"description":"Events per page. Below 1 or not a number reads as 50; above 100 reads as 100.","in":"query","name":"limit","required":false,"schema":{"default":50,"maximum":100,"minimum":1,"type":"integer"}},{"description":"The previous page's `meta.next_cursor`. An invalid cursor is ignored, and you get the first page.","in":"query","name":"cursor","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"counts":{"already_existing_entity_count":0,"already_existing_source_row_count":0,"entity_count":2,"excluded_entity_count":0,"excluded_source_row_count":0,"failed_entity_count":0,"failed_source_row_count":0,"imported_entity_count":2,"imported_source_row_count":2,"not_processed_entity_count":0,"not_processed_source_row_count":0,"pending_entity_count":0,"pending_source_row_count":0,"preflight_blocked_entity_count":0,"preflight_blocked_source_row_count":0,"removed_entity_count":0,"removed_source_row_count":0,"source_row_count":2,"submitted_entity_count":2,"submitted_source_row_count":2,"unresolved_entity_count":0,"unresolved_source_row_count":0},"detail":"2 imported · 0 need attention","entityType":"customer","id":"csv:csv-mNEytAlBIJf7j1","message":"CSV import completed","receipt_id":"csv-mNEytAlBIJf7j1","sourceType":"csv","timestamp":"2026-11-03T10:10:00+00:00","type":"import_completed"}],"meta":{"has_more":false,"limit":50,"next_cursor":null}},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A CSV import event.","properties":{"counts":{"additionalProperties":{"type":"integer"},"description":"Entity and source-row counts: `entity_count` and `source_row_count`, then `submitted_`, `imported_`, `failed_`, `not_processed_`, `unresolved_`, `removed_`, `already_existing_`, `preflight_blocked_`, `excluded_` and `pending_` each with `entity_count` and `source_row_count`. Left out when the import could not be verified.","type":"object"},"detail":{"description":"For example \"2 imported · 0 need attention\".","type":"string"},"entityType":{"enum":["customer","vendor","simple_product","variant_product"],"type":"string"},"id":{"description":"`csv:` and the import's `receipt_id`.","type":"string"},"message":{"description":"\"CSV import completed\", \"Some entries were imported\" or \"No entries were imported\" (\"CSV import could not be verified\" when YoPrint stopped the import for a failed integrity check).","type":"string"},"receipt_id":{"description":"The Import Portal CSV import's id (`csv-...`).","type":"string"},"sourceType":{"const":"csv","type":"string"},"timestamp":{"description":"When the import finished.","format":"date-time","type":"string"},"type":{"enum":["import_completed","import_partial_completed","import_failed"],"type":"string"}},"title":"CSV event","type":"object"},"type":"array"},"meta":{"properties":{"has_more":{"type":"boolean"},"limit":{"type":"integer"},"next_cursor":{"description":"Null on the last page.","type":["string","null"]}},"type":"object"}},"required":["data","meta"],"type":"object"}}},"description":"A page of events."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List import activity","tags":["CSV imports"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team admin.","status":403,"when":"You can't import anything (a plain `{\"message\": \"Insufficient Permission\"}` body, not the usual envelope)."}],"group":"Imports and exports","notes":["Unrecognized `source` or `sort` values are treated as their defaults."],"permission":"Any member who can import some kind of record.","related":["v1_public_imports_index"]}}},"/v1/api/store/{team_slug}/tag":{"get":{"description":"Lists the team's tags, each with `id`, `name` and `color_hex`. The same tags are used on customers and on sales orders. The list is paged: `pagination` gives `total`, `count`, `perPage`, `currentPage` and `totalPages`. Ask for the next page with `page`; the page size is the team's setting (50 unless changed), and `per_page` is ignored.","operationId":"v1_public_tag_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The page to return. Pages hold the team's page size (`pagination_per_page` in team settings: 50 unless changed, 5 to 100). `per_page` is not read here.","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"color_hex":{"description":"Such as `#2563EB`. Null for a tag saved without a color.","type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List tags","tags":["Tags"],"x-yoprint-docs":{"group":"Products and catalog","permission":"Any member of the team.","related":["v1_public_tag_store","v1_public_customer_tag_attach","v1_public_sales_order_tag_attach"]}},"post":{"description":"Creates a tag and returns it. Put it on customers with Tag a customer, and on sales orders with the sales order tag operations.","operationId":"v1_public_tag_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"color_hex":"#2563EB","name":"Wholesale"},"schema":{"additionalProperties":false,"properties":{"color_hex":{"description":"`#` and 3 or 6 hex digits.","pattern":"^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$","type":"string"},"name":{"description":"Need not be unique.","type":"string"}},"required":["name","color_hex"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"color_hex":{"description":"Such as `#2563EB`. Null for a tag saved without a color.","type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a tag","tags":["Tags"],"x-yoprint-docs":{"errors":[{"fix":"Send both, with a hex color.","status":422,"when":"`name` or `color_hex` is missing, or `color_hex` is not `#RGB` or `#RRGGBB`. `error.code` is `validation_failed`."}],"group":"Products and catalog","permission":"Any member of the team.","related":["v1_public_customer_tag_attach","v1_public_sales_order_tag_attach"],"rules":["Tag names are not checked for duplicates: look in List tags before creating one."]}}},"/v1/api/store/{team_slug}/tag/get_by_id":{"post":{"description":"Returns the tags you name, up to 500 in one request. Ids that are not the team's tags are left out. Not paged.","operationId":"v1_public_tag_get_by_id","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"item":[{"id":"zzVW0sylTIm6oo"},{"id":"WUDLhVphzq2dFt"}]},"schema":{"additionalProperties":false,"properties":{"item":{"items":{"additionalProperties":false,"properties":{"id":{"description":"A tag id.","type":"string"}},"required":["id"],"type":"object"},"maxItems":500,"type":"array"}},"required":["item"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"color_hex":"#2563EB","id":"zzVW0sylTIm6oo","name":"Wholesale"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"color_hex":{"description":"Such as `#2563EB`. Null for a tag saved without a color.","type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get tags by id","tags":["Tags"],"x-yoprint-docs":{"errors":[{"fix":"Send 1 to 500 ids.","status":422,"when":"`item` is missing or empty, has more than 500 entries, or an `id` is not a valid id. `error.code` is `validation_failed`."}],"group":"Products and catalog","permission":"Any member of the team.","related":["v1_public_tag_index"]}}},"/v1/api/store/{team_slug}/tag/{id}":{"delete":{"description":"Deletes a tag for good and takes it off every customer and sales order that has it. There is no restore.","operationId":"v1_public_tag_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The tag's id (`id` from List tags). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a tag","tags":["Tags"],"x-yoprint-docs":{"errors":[{"fix":"Check the id.","status":404,"when":"No tag with this id in the team. `error.code` is null and `error.message` names the record type."}],"group":"Products and catalog","permission":"Any member of the team.","related":["v1_public_tag_index"],"side_effects":["Removes the tag from every customer and sales order."]}},"patch":{"description":"Renames or recolors a tag everywhere it is used, and returns it.\n\nUse `PUT`: it checks the fields. `PATCH` takes the same body but checks nothing.","operationId":"v1_public_tag_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The tag's id (`id` from List tags). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"color_hex":"#16A34A"},"schema":{"additionalProperties":false,"properties":{"color_hex":{"pattern":"^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$","type":"string"},"name":{"type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"color_hex":"#16A34A","id":"zzVW0sylTIm6oo","name":"Wholesale"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"color_hex":{"description":"Such as `#2563EB`. Null for a tag saved without a color.","type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a tag (PATCH)","tags":["Tags"],"x-yoprint-docs":{"errors":[{"fix":"Check the id.","status":404,"when":"No tag with this id in the team. `error.code` is null and `error.message` names the record type."}],"group":"Products and catalog","permission":"Any member of the team.","related":["v1_public_tag_index"]}},"put":{"description":"Renames or recolors a tag everywhere it is used, and returns it.\n\nUse `PUT`: it checks the fields. `PATCH` takes the same body but checks nothing.","operationId":"v1_public_tag_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The tag's id (`id` from List tags). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"color_hex":"#16A34A"},"schema":{"additionalProperties":false,"properties":{"color_hex":{"pattern":"^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$","type":"string"},"name":{"type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"color_hex":"#16A34A","id":"zzVW0sylTIm6oo","name":"Wholesale"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"color_hex":{"description":"Such as `#2563EB`. Null for a tag saved without a color.","type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","color_hex"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a tag","tags":["Tags"],"x-yoprint-docs":{"errors":[{"fix":"Send a hex color.","status":422,"when":"`PUT` only: `name` is not a string, or `color_hex` is not `#RGB` or `#RRGGBB`. `error.code` is `validation_failed`."},{"fix":"Check the id.","status":404,"when":"No tag with this id in the team. `error.code` is null and `error.message` names the record type."}],"group":"Products and catalog","permission":"Any member of the team.","related":["v1_public_tag_index"]}}},"/v1/api/store/{team_slug}/user_api_key/create_api_key":{"post":{"description":"Refused on the public API: once your key is accepted, it answers `403` with error code `self_credential`.\n\nYou need a key to call the API at all, so the first key is always created in the YoPrint web app, on your Profile page.","operationId":"v1_public_user_api_key_create","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create your personal API key (refused on the public API)","tags":["API key"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Manage the key on your Profile page in the YoPrint web app.","status":403,"when":"Every request with a working key: `{\"status\": 403, \"success\": false, \"error\": {\"code\": \"self_credential\", \"message\": \"Manage your API key in YoPrint, not through the API.\"}}`."},{"fix":"Send a working key; check it with the sign-in check.","status":401,"when":"The key is missing or wrong (`unauthenticated`)."},{"fix":"Use your own team's slug.","status":404,"when":"The key's owner is not a member of this team, or the team slug does not exist (`page_not_found`)."}],"group":"Account","notes":["Manage your key in the YoPrint web app: open your Profile, then the API key section. There you can create the key, copy it, see when it was last used, and reset it. Resetting stops the old key at once.","To check that a key works, call `GET /v1/api/store/{team_slug}/is_authenticated`."],"related":["v1_public_misc_is_authenticated"],"rules":["The key is checked first, as on every operation: a missing or wrong key gets 401, and a key whose owner is not a member of the team gets 404. Any request that passes those checks gets 403 `self_credential`. Nothing is read, created or changed.","A personal API key cannot read, create or reset itself. If a key leaks, whoever holds it cannot lock you out by replacing it."]}}},"/v1/api/store/{team_slug}/user_api_key/get_api_key":{"get":{"description":"Refused on the public API: once your key is accepted, it answers `403` with error code `self_credential`.\n\nYour key is shown on your Profile page in the YoPrint web app, with when it was last used. To check that a key works, call `GET /v1/api/store/{team_slug}/is_authenticated` instead.","operationId":"v1_public_user_api_key_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show your personal API key (refused on the public API)","tags":["API key"],"x-yoprint-docs":{"errors":[{"fix":"Manage the key on your Profile page in the YoPrint web app.","status":403,"when":"Every request with a working key: `{\"status\": 403, \"success\": false, \"error\": {\"code\": \"self_credential\", \"message\": \"Manage your API key in YoPrint, not through the API.\"}}`."},{"fix":"Send a working key; check it with the sign-in check.","status":401,"when":"The key is missing or wrong (`unauthenticated`)."},{"fix":"Use your own team's slug.","status":404,"when":"The key's owner is not a member of this team, or the team slug does not exist (`page_not_found`)."}],"group":"Account","notes":["Manage your key in the YoPrint web app: open your Profile, then the API key section. There you can create the key, copy it, see when it was last used, and reset it. Resetting stops the old key at once.","To check that a key works, call `GET /v1/api/store/{team_slug}/is_authenticated`."],"related":["v1_public_misc_is_authenticated"],"rules":["The key is checked first, as on every operation: a missing or wrong key gets 401, and a key whose owner is not a member of the team gets 404. Any request that passes those checks gets 403 `self_credential`. Nothing is read, created or changed.","A personal API key cannot read, create or reset itself. If a key leaks, whoever holds it cannot lock you out by replacing it."]}}},"/v1/api/store/{team_slug}/user_api_key/reset_api_key":{"post":{"description":"Refused on the public API: once your key is accepted, it answers `403` with error code `self_credential`.\n\nTo replace a key, reset it on your Profile page in the YoPrint web app. The old key stops working at once, so update every integration that uses it.","operationId":"v1_public_user_api_key_reset","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Replace your personal API key (refused on the public API)","tags":["API key"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Manage the key on your Profile page in the YoPrint web app.","status":403,"when":"Every request with a working key: `{\"status\": 403, \"success\": false, \"error\": {\"code\": \"self_credential\", \"message\": \"Manage your API key in YoPrint, not through the API.\"}}`."},{"fix":"Send a working key; check it with the sign-in check.","status":401,"when":"The key is missing or wrong (`unauthenticated`)."},{"fix":"Use your own team's slug.","status":404,"when":"The key's owner is not a member of this team, or the team slug does not exist (`page_not_found`)."}],"group":"Account","notes":["Manage your key in the YoPrint web app: open your Profile, then the API key section. There you can create the key, copy it, see when it was last used, and reset it. Resetting stops the old key at once.","To check that a key works, call `GET /v1/api/store/{team_slug}/is_authenticated`."],"related":["v1_public_misc_is_authenticated"],"rules":["The key is checked first, as on every operation: a missing or wrong key gets 401, and a key whose owner is not a member of the team gets 404. Any request that passes those checks gets 403 `self_credential`. Nothing is read, created or changed.","A personal API key cannot read, create or reset itself. If a key leaks, whoever holds it cannot lock you out by replacing it."]}}},"/v1/api/store/{team_slug}/vendor":{"get":{"description":"Lists the team's live vendors (the suppliers you buy from on purchase orders), each with its `contacts`. The list is paged: `pagination` gives `total`, `count`, `perPage`, `currentPage` and `totalPages`. Ask for the next page with `page`; the page size is the team's setting (50 unless changed), and `per_page` is ignored.","operationId":"v1_public_vendor_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The page to return. Pages hold the team's page size (`pagination_per_page` in team settings: 50 unless changed, 5 to 100). `per_page` is not read here.","example":1,"in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"account_number":"ACCT-1001","contacts":[{"created_at":"2026-11-01T09:00:00+00:00","default_receive_sms":false,"email":"sam@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Sam","id":"fopJXRDkZ8Qk7S","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","trashed":false,"updated_at":"2026-11-01T09:00:00+00:00","vendor_id":"MFwvMEIK7ud89l"}],"default_vendor_note":null,"id":"MFwvMEIK7ud89l","internal_notes":null,"name":"Example Blanks Co","trashed":false,"website":"https://example.com"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"account_number":{"type":["string","null"]},"contacts":{"description":"Every contact, deleted ones included.","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"default_vendor_note":{"type":["string","null"]},"id":{"type":"string"},"internal_notes":{"type":["string","null"]},"name":{"type":["string","null"]},"trashed":{"description":"True when the vendor is deleted.","type":"boolean"},"website":{"type":["string","null"]}},"required":["id","name","trashed"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List vendors","tags":["Vendors"],"x-yoprint-docs":{"group":"Purchasing","permission":"Any member of the team.","related":["v1_public_vendor_store","v1_public_vendor_show"]}},"post":{"description":"Creates a vendor, with its contacts, and returns it with `contacts`. The first contact you send becomes the primary contact.\n\nA vendor is a supplier you buy from: purchase orders and your products name one.","operationId":"v1_public_vendor_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"account_number":"ACCT-1001","contact":[{"email":"sam@example.com","first_name":"Sam","last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US"}],"name":"Example Blanks Co","website":"https://example.com"},"schema":{"additionalProperties":false,"properties":{"account_number":{"description":"Your account number with this vendor.","type":"string"},"contact":{"description":"The vendor's contacts. The first one becomes primary.","items":{"additionalProperties":false,"properties":{"email":{"format":"email","type":"string"},"fax":{"description":"Checked as a real number for `fax_country`.","type":"string"},"fax_country":{"type":"string"},"first_name":{"description":"The contact's first name.","type":"string"},"last_name":{"description":"The contact's last name.","type":"string"},"phone":{"type":"string"},"phone_country":{"description":"Two-letter country code of `phone`, such as `US`. Required with `phone`.","type":"string"}},"type":"object"},"type":"array"},"default_vendor_note":{"description":"A note for the vendor, available on purchase order PDFs.","type":"string"},"internal_notes":{"description":"Notes for your team only.","type":"string"},"name":{"description":"The vendor's name. Not required by the API (a vendor can be saved without one), but send it: it is how the vendor is shown everywhere.","type":"string"},"website":{"description":"The website address.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_number":"ACCT-1001","contacts":[{"created_at":"2026-11-01T09:00:00+00:00","default_receive_sms":false,"email":"sam@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Sam","id":"fopJXRDkZ8Qk7S","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","trashed":false,"updated_at":"2026-11-01T09:00:00+00:00","vendor_id":"MFwvMEIK7ud89l"}],"default_vendor_note":null,"id":"MFwvMEIK7ud89l","internal_notes":null,"name":"Example Blanks Co","trashed":false,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"account_number":{"type":["string","null"]},"contacts":{"description":"Every contact, deleted ones included.","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"default_vendor_note":{"type":["string","null"]},"id":{"type":"string"},"internal_notes":{"type":["string","null"]},"name":{"type":["string","null"]},"trashed":{"description":"True when the vendor is deleted.","type":"boolean"},"website":{"type":["string","null"]}},"required":["id","name","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a vendor","tags":["Vendors"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team owner to raise Manage Vendors for your role.","status":403,"when":"Your role cannot create vendors. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Send text fields as strings.","status":422,"when":"A field has the wrong type. `error.code` is `validation_failed`."}],"group":"Purchasing","permission":"Needs the Manage Vendors permission at the level that can create vendors.","related":["v1_public_vendor_contact_store","v1_public_vendor_update_patch"],"rules":["Only the vendor's own fields are checked, as strings. `name` is not required, and contacts sent here are not checked at all: add a contact with Add a contact to a vendor when you want its fields checked.","Vendor names need not be unique."]}}},"/v1/api/store/{team_slug}/vendor/{hash_id}":{"delete":{"description":"Deletes a vendor. Nothing blocks it: purchase orders and products that name the vendor keep it. It can be restored.","operationId":"v1_public_vendor_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a vendor","tags":["Vendors"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team owner to raise Manage Vendors for your role.","status":403,"when":"Your role cannot update vendors. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the id.","status":404,"when":"No live vendor with this id. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Needs the Manage Vendors permission at the level that can update vendors.","related":["v1_public_vendor_restore"]}},"get":{"description":"Returns one vendor, deleted ones included (`trashed`), with its `contacts` (deleted ones included).","operationId":"v1_public_vendor_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_number":"ACCT-1001","contacts":[{"created_at":"2026-11-01T09:00:00+00:00","default_receive_sms":false,"email":"sam@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Sam","id":"fopJXRDkZ8Qk7S","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","trashed":false,"updated_at":"2026-11-01T09:00:00+00:00","vendor_id":"MFwvMEIK7ud89l"}],"default_vendor_note":null,"id":"MFwvMEIK7ud89l","internal_notes":null,"name":"Example Blanks Co","trashed":false,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"account_number":{"type":["string","null"]},"contacts":{"description":"Every contact, deleted ones included.","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"default_vendor_note":{"type":["string","null"]},"id":{"type":"string"},"internal_notes":{"type":["string","null"]},"name":{"type":["string","null"]},"trashed":{"description":"True when the vendor is deleted.","type":"boolean"},"website":{"type":["string","null"]}},"required":["id","name","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a vendor","tags":["Vendors"],"x-yoprint-docs":{"group":"Purchasing","permission":"Any member of the team.","related":["v1_public_vendor_update_patch"]}},"patch":{"description":"Changes the fields you send and returns the vendor. Contacts have their own operations.\n\nWe recommend `PUT`: it validates that all provided fields are strings and returns 422 if any type is invalid. `PATCH` accepts the exact same body but skips field validation entirely.","operationId":"v1_public_vendor_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"account_number":"ACCT-2002","default_vendor_note":"Ship blanks folded, not on hangers."},"schema":{"additionalProperties":false,"properties":{"account_number":{"type":"string"},"default_vendor_note":{"type":"string"},"internal_notes":{"type":"string"},"name":{"type":"string"},"website":{"description":"The website address.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_number":"ACCT-2002","contacts":[{"created_at":"2026-11-01T09:00:00+00:00","default_receive_sms":false,"email":"sam@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Sam","id":"fopJXRDkZ8Qk7S","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","trashed":false,"updated_at":"2026-11-01T09:00:00+00:00","vendor_id":"MFwvMEIK7ud89l"}],"default_vendor_note":"Ship blanks folded, not on hangers.","id":"MFwvMEIK7ud89l","internal_notes":null,"name":"Example Blanks Co","trashed":false,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"account_number":{"type":["string","null"]},"contacts":{"description":"Every contact, deleted ones included.","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"default_vendor_note":{"type":["string","null"]},"id":{"type":"string"},"internal_notes":{"type":["string","null"]},"name":{"type":["string","null"]},"trashed":{"description":"True when the vendor is deleted.","type":"boolean"},"website":{"type":["string","null"]}},"required":["id","name","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a vendor (PATCH)","tags":["Vendors"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team owner to raise Manage Vendors for your role.","status":403,"when":"Your role cannot update vendors. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Restore a deleted vendor first.","status":404,"when":"No live vendor with this id. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Needs the Manage Vendors permission at the level that can update vendors.","related":["v1_public_vendor_show"],"rules":["To clear a text field, send an empty string; `null` is ignored (it is dropped before the request is read)."]}},"put":{"description":"Changes the fields you send and returns the vendor. Contacts have their own operations.\n\nWe recommend `PUT`: it validates that all provided fields are strings and returns 422 if any type is invalid. `PATCH` accepts the exact same body but skips field validation entirely.","operationId":"v1_public_vendor_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"account_number":"ACCT-2002","default_vendor_note":"Ship blanks folded, not on hangers."},"schema":{"additionalProperties":false,"properties":{"account_number":{"type":"string"},"default_vendor_note":{"type":"string"},"internal_notes":{"type":"string"},"name":{"type":"string"},"website":{"description":"The website address.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"account_number":"ACCT-2002","contacts":[{"created_at":"2026-11-01T09:00:00+00:00","default_receive_sms":false,"email":"sam@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Sam","id":"fopJXRDkZ8Qk7S","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","trashed":false,"updated_at":"2026-11-01T09:00:00+00:00","vendor_id":"MFwvMEIK7ud89l"}],"default_vendor_note":"Ship blanks folded, not on hangers.","id":"MFwvMEIK7ud89l","internal_notes":null,"name":"Example Blanks Co","trashed":false,"website":"https://example.com"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"account_number":{"type":["string","null"]},"contacts":{"description":"Every contact, deleted ones included.","items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"default_vendor_note":{"type":["string","null"]},"id":{"type":"string"},"internal_notes":{"type":["string","null"]},"name":{"type":["string","null"]},"trashed":{"description":"True when the vendor is deleted.","type":"boolean"},"website":{"type":["string","null"]}},"required":["id","name","trashed"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a vendor","tags":["Vendors"],"x-yoprint-docs":{"errors":[{"fix":"Send text fields as strings.","status":422,"when":"A field is not a string. `error.code` is `validation_failed`."},{"fix":"Ask a team owner to raise Manage Vendors for your role.","status":403,"when":"Your role cannot update vendors. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Restore a deleted vendor first.","status":404,"when":"No live vendor with this id. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Needs the Manage Vendors permission at the level that can update vendors.","related":["v1_public_vendor_show"],"rules":["To clear a text field, send an empty string; `null` is ignored (it is dropped before the request is read)."]}}},"/v1/api/store/{team_slug}/vendor/{hash_id}/contact":{"get":{"description":"Lists every contact of the vendor, deleted ones included (`trashed`). Not paged, in no set order. Warning: YoPrint does not verify that the vendor ID exists. Passing an unknown or deleted vendor ID returns an empty list `[]` instead of a 404.","operationId":"v1_public_vendor_contact_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"created_at":"2026-11-01T09:00:00+00:00","default_receive_sms":false,"email":"sam@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Sam","id":"fopJXRDkZ8Qk7S","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","trashed":false,"updated_at":"2026-11-01T09:00:00+00:00","vendor_id":"MFwvMEIK7ud89l"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a vendor's contacts","tags":["Vendor contacts"],"x-yoprint-docs":{"group":"Purchasing","permission":"Any member of the team.","related":["v1_public_vendor_contact_store"]}},"post":{"description":"Adds a contact to the vendor and returns it. It becomes primary only when the vendor has no other live contact; `is_primary` is required but not used.","operationId":"v1_public_vendor_contact_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"email":"riley@example.com","first_name":"Riley","is_primary":false,"last_name":"Chen"},"schema":{"additionalProperties":false,"properties":{"email":{"format":"email","type":"string"},"fax":{"description":"Checked as a real number for `fax_country`.","type":"string"},"fax_country":{"type":"string"},"first_name":{"description":"The contact's first name.","type":"string"},"is_primary":{"description":"Required, but not used.","type":"boolean"},"last_name":{"description":"The contact's last name.","type":"string"},"phone":{"description":"Checked as a real number for `phone_country`.","type":"string"},"phone_country":{"description":"Required with `phone`.","type":"string"}},"required":["first_name","is_primary"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-03T09:00:00+00:00","default_receive_sms":false,"email":"riley@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Riley","id":"Nd77ZXOndfLohn","is_external":false,"is_primary":false,"last_name":"Chen","phone":null,"phone_country":null,"trashed":false,"updated_at":"2026-11-03T09:00:00+00:00","vendor_id":"MFwvMEIK7ud89l"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add a contact to a vendor","tags":["Vendor contacts"],"x-yoprint-docs":{"errors":[{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"`first_name` or `is_primary` is missing, or the phone is not valid for `phone_country`. `error.code` is `validation_failed`."},{"fix":"Ask a team owner to raise Manage Vendors for your role.","status":403,"when":"Your role cannot update vendors. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."}],"group":"Purchasing","permission":"Needs the Manage Vendors permission at the level that can update vendors.","related":["v1_public_vendor_contact_primary"],"rules":["Warning: YoPrint does not verify that the vendor ID exists. The contact is saved under the vendor ID from the path even when that vendor is deleted or does not exist. Check the vendor ID before adding a contact."]}}},"/v1/api/store/{team_slug}/vendor/{hash_id}/contact/{id}":{"delete":{"description":"Deletes a vendor contact. It can be restored. The primary contact can't be deleted: make another contact primary first.","operationId":"v1_public_vendor_contact_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The contact's id (`id` from List a customer's contacts, or from List a vendor's contacts). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a vendor contact","tags":["Vendor contacts"],"x-yoprint-docs":{"errors":[{"fix":"Set another contact as primary first. Don't retry the same call.","status":500,"when":"The contact is primary. This route answers HTTP 500 with `error.code` `delete_fail` and `error.message` null; nothing is deleted."},{"fix":"Ask a team owner to raise Manage Vendors for your role.","status":403,"when":"Your role cannot update vendors. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the ids.","status":404,"when":"Not a live contact of this vendor. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Needs the Manage Vendors permission at the level that can update vendors.","related":["v1_public_vendor_contact_restore"]}},"get":{"description":"Returns one live contact of the vendor.","operationId":"v1_public_vendor_contact_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The contact's id (`id` from List a customer's contacts, or from List a vendor's contacts). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-01T09:00:00+00:00","default_receive_sms":false,"email":"sam@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Sam","id":"fopJXRDkZ8Qk7S","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","trashed":false,"updated_at":"2026-11-01T09:00:00+00:00","vendor_id":"MFwvMEIK7ud89l"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a vendor contact","tags":["Vendor contacts"],"x-yoprint-docs":{"group":"Purchasing","permission":"Any member of the team.","related":["v1_public_vendor_contact_update_patch"]}},"patch":{"description":"Changes the fields you send and returns the contact. `is_primary` is not changed here: use Set a vendor's primary contact.\n\nWe recommend `PUT`: it validates email format and verifies that phone and fax numbers match their country codes (returning 422 if invalid). `PATCH` accepts the exact same body but skips validation entirely.","operationId":"v1_public_vendor_contact_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The contact's id (`id` from List a customer's contacts, or from List a vendor's contacts). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"email":"sam@example.com"},"schema":{"additionalProperties":false,"properties":{"email":{"format":"email","type":"string"},"fax":{"description":"Checked as a real number for `fax_country`.","type":"string"},"fax_country":{"type":"string"},"first_name":{"description":"The contact's first name.","type":"string"},"last_name":{"description":"The contact's last name.","type":"string"},"phone":{"type":"string"},"phone_country":{"description":"Two-letter country code of `phone`, such as `US`. Required with `phone`.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-01T09:00:00+00:00","default_receive_sms":false,"email":"sam@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Sam","id":"fopJXRDkZ8Qk7S","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","trashed":false,"updated_at":"2026-11-01T09:00:00+00:00","vendor_id":"MFwvMEIK7ud89l"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a vendor contact (PATCH)","tags":["Vendor contacts"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team owner to raise Manage Vendors for your role.","status":403,"when":"Your role cannot update vendors. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the ids.","status":404,"when":"Not a live contact of this vendor. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Needs the Manage Vendors permission at the level that can update vendors.","related":["v1_public_vendor_contact_primary"],"rules":["To clear a text field, send an empty string; `null` is ignored (it is dropped before the request is read)."]}},"put":{"description":"Changes the fields you send and returns the contact. `is_primary` is not changed here: use Set a vendor's primary contact.\n\nWe recommend `PUT`: it validates email format and verifies that phone and fax numbers match their country codes (returning 422 if invalid). `PATCH` accepts the exact same body but skips validation entirely.","operationId":"v1_public_vendor_contact_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The contact's id (`id` from List a customer's contacts, or from List a vendor's contacts). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"email":"sam@example.com"},"schema":{"additionalProperties":false,"properties":{"email":{"format":"email","type":"string"},"fax":{"description":"Checked as a real number for `fax_country`.","type":"string"},"fax_country":{"type":"string"},"first_name":{"description":"The contact's first name.","type":"string"},"last_name":{"description":"The contact's last name.","type":"string"},"phone":{"type":"string"},"phone_country":{"description":"Two-letter country code of `phone`, such as `US`. Required with `phone`.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-01T09:00:00+00:00","default_receive_sms":false,"email":"sam@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Sam","id":"fopJXRDkZ8Qk7S","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","trashed":false,"updated_at":"2026-11-01T09:00:00+00:00","vendor_id":"MFwvMEIK7ud89l"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a vendor contact","tags":["Vendor contacts"],"x-yoprint-docs":{"errors":[{"fix":"Send the country code with the number.","status":422,"when":"A phone or fax is not valid for its country, or a field has the wrong type. `error.code` is `validation_failed`."},{"fix":"Ask a team owner to raise Manage Vendors for your role.","status":403,"when":"Your role cannot update vendors. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the ids.","status":404,"when":"Not a live contact of this vendor. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Needs the Manage Vendors permission at the level that can update vendors.","related":["v1_public_vendor_contact_primary"],"rules":["To clear a text field, send an empty string; `null` is ignored (it is dropped before the request is read)."]}}},"/v1/api/store/{team_slug}/vendor/{hash_id}/contact/{id}/primary":{"patch":{"description":"Makes this contact the vendor's primary contact; the previous one stops being primary. Returns the contact.","operationId":"v1_public_vendor_contact_primary","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The contact's id (`id` from List a customer's contacts, or from List a vendor's contacts). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-01T09:00:00+00:00","default_receive_sms":false,"email":"sam@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Sam","id":"fopJXRDkZ8Qk7S","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","trashed":false,"updated_at":"2026-11-01T09:00:00+00:00","vendor_id":"MFwvMEIK7ud89l"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"description":"Customer contacts only.","type":"string"},"default_receive_sms":{"type":"boolean"},"email":{"type":["string","null"]},"external_type":{"type":["string","null"]},"fax":{"type":["string","null"]},"fax_country":{"type":["string","null"]},"first_name":{"type":["string","null"]},"id":{"type":"string"},"is_external":{"description":"True for a contact synced from Shopify; such contacts are read-only.","type":"boolean"},"is_primary":{"type":"boolean"},"last_name":{"type":["string","null"]},"phone":{"type":["string","null"]},"phone_country":{"type":["string","null"]},"send_invoice":{"description":"Customer contacts only.","type":"boolean"},"trashed":{"description":"True when the contact is deleted.","type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"vendor_id":{"description":"Vendor contacts only.","type":"string"}},"required":["id","first_name","is_primary","trashed","created_at","updated_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set a vendor's primary contact","tags":["Vendor contacts"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Ask a team owner to raise Manage Vendors for your role.","status":403,"when":"Your role cannot update vendors. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Restore it first.","status":404,"when":"Not a live contact of this vendor. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Needs the Manage Vendors permission at the level that can update vendors.","related":["v1_public_vendor_contact_index"]}}},"/v1/api/store/{team_slug}/vendor/{hash_id}/contact/{id}/restore":{"patch":{"description":"Brings back a deleted vendor contact as it was. Answers `success: true` with `data: null`.","operationId":"v1_public_vendor_contact_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The contact's id (`id` from List a customer's contacts, or from List a vendor's contacts). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a deleted vendor contact","tags":["Vendor contacts"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Check the ids.","status":404,"when":"Not a contact of this vendor. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Any member of the team.","related":["v1_public_vendor_contact_destroy"]}}},"/v1/api/store/{team_slug}/vendor/{hash_id}/external_id/{id}":{"delete":{"description":"Removes the link between this vendor and its QuickBooks Online vendor for the connection `{id}`. Nothing changes in QuickBooks. Answers `success: true` with `data: null`, also when nothing was linked or `{id}` is no integration of the team.","operationId":"v1_public_vendor_external_id_delete","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The QuickBooks Online connection's id (`id` from List integrations), not the QuickBooks record's Id. A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Unlink a vendor from QuickBooks","tags":["Vendors"],"x-yoprint-docs":{"group":"Purchasing","permission":"Any member of the team.","related":["v1_public_vendor_external_id_update"]}},"get":{"description":"Reads the QuickBooks Online vendor linked to this vendor for the QuickBooks connection `{id}`: its QuickBooks `id` and `name`, `override` (the override lock), `attached_by_user` and `vendor_id`, or an empty `data` when nothing is linked. Calls QuickBooks Online each time.","operationId":"v1_public_vendor_external_id_get","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The QuickBooks Online connection's id (`id` from List integrations), not the QuickBooks record's Id. A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"attached_by_user":true,"id":"42","name":"Example Blanks Co","override":false,"vendor_id":"MFwvMEIK7ud89l"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"description":"The linked QuickBooks record, or an empty list `[]` when nothing is linked.","properties":{"attached_by_user":{"description":"True when someone linked it by hand.","type":"boolean"},"id":{"description":"The QuickBooks Id.","type":"string"},"name":{"description":"Its DisplayName in QuickBooks.","type":["string","null"]},"override":{"description":"The override lock: true means YoPrint never overwrites it. Returned exactly as `override_lock` was sent when linking (a JSON boolean when you sent one), and false when it was never set.","type":["boolean","integer","string"]},"vendor_id":{"type":"string"}},"type":["object","array"]},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get the QuickBooks vendor linked to a vendor","tags":["Vendors"],"x-yoprint-docs":{"errors":[{"fix":"Use the QuickBooks connection id from List integrations.","status":422,"when":"`{id}` is not a QuickBooks Online connection (`error.code` `external_integration_not_found`, `error.message` null)."},{"fix":"Reconnect QuickBooks Online under Apps, or retry later.","status":422,"when":"The QuickBooks Online connection can't be used: it is waiting to be reconnected (`error.code` `auth_error`), or its sign-in expired, QuickBooks refused it or QuickBooks could not be reached (`bootstrap_error`, with the reason in `error.message`)."}],"group":"Purchasing","notes":["Deleted vendors can be read too. A link whose QuickBooks vendor no longer exists also answers an empty `data`."],"permission":"Any member of the team.","related":["v1_public_vendor_external_id_update","v1_public_external_integration_index"],"side_effects":["Calls the QuickBooks Online API with the team's connection."]}},"put":{"description":"Links this vendor to an existing QuickBooks Online vendor, so YoPrint syncs it to that vendor. YoPrint looks the QuickBooks vendor up first, so it must exist. Answers `success: true` with `data: null`.\n\nWith `override_lock: true`, later syncs leave the QuickBooks vendor's details alone.","operationId":"v1_public_vendor_external_id_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The QuickBooks Online connection's id (`id` from List integrations), not the QuickBooks record's Id. A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"uAu3dAKIaHyAYk","in":"path","name":"id","required":true,"schema":{"example":"uAu3dAKIaHyAYk","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"external_id":"42","override_lock":false},"schema":{"additionalProperties":false,"properties":{"external_id":{"description":"The QuickBooks Online vendor Id.","type":"string"},"override_lock":{"description":"True: never overwrite this QuickBooks vendor from YoPrint. Defaults to false. Send a JSON boolean: it is stored as sent and read back as `override`.","type":"boolean"}},"required":["external_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Link a vendor to a QuickBooks vendor","tags":["Vendors"],"x-yoprint-docs":{"errors":[{"fix":"Send `external_id`.","status":422,"when":"`external_id` is missing, or `override_lock` is not a boolean. `error.code` is `validation_failed`."},{"fix":"Use the QuickBooks connection id.","status":422,"when":"`{id}` is an integration but not QuickBooks Online (`error.code` `unable_save_external_id`)."},{"fix":"Check the QuickBooks vendor Id.","status":422,"when":"QuickBooks has no vendor with this Id (`error.code` `validation_error`, \"Cannot find corresponding  QuickBook Online resource :Vendor\")."},{"fix":"Reconnect QuickBooks Online under Apps, or retry later.","status":422,"when":"The QuickBooks Online connection can't be used: it is waiting to be reconnected (`error.code` `auth_error`), or its sign-in expired, QuickBooks refused it or QuickBooks could not be reached (`bootstrap_error`, with the reason in `error.message`)."},{"fix":"Check both ids.","status":404,"when":"No vendor or integration with these ids. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","notes":["Deleted vendors can be linked too."],"permission":"Any member of the team.","related":["v1_public_vendor_external_id_get","v1_public_vendor_external_id_delete"],"side_effects":["Calls the QuickBooks Online API to read the vendor, then saves the link."]}}},"/v1/api/store/{team_slug}/vendor/{hash_id}/media":{"get":{"description":"Lists every file on the vendor, each with `id`, `collection`, `name`, `file_name`, `mime_type`, `size`, `position` and download links. Not paged.","operationId":"v1_public_vendor_media_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"collection":"default","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"file_name":"price-list.pdf","id":"YMlcxHYran1mzL","is_image":false,"mime_type":"application/pdf","name":"Price list 2026","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/YMlcxHYran1mzL/download","view_url":"https://example.com/media/YMlcxHYran1mzL/view"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a vendor's files","tags":["Vendor files"],"x-yoprint-docs":{"group":"Purchasing","permission":"Any member of the team.","related":["v1_public_vendor_media_store"]}},"post":{"description":"Uploads one file to the vendor and returns it. Send `multipart/form-data`, not JSON: the file goes in the `media` part.","operationId":"v1_public_vendor_media_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"properties":{"collection":{"default":"default","description":"Where the file goes. `mockup` takes images a preview can be made of (PNG, JPG, GIF, TIFF, BMP, WebP, SVG, HEIC, AVIF; at most 120 megapixels).","enum":["default","mockup","production_file"],"type":"string"},"media":{"description":"The file.","format":"binary","type":"string"}},"required":["media"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"collection":"default","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"file_name":"price-list.pdf","id":"YMlcxHYran1mzL","is_image":false,"mime_type":"application/pdf","name":"Price list 2026","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/YMlcxHYran1mzL/download","view_url":"https://example.com/media/YMlcxHYran1mzL/view"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/MediaUploadValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Upload a file to a vendor","tags":["Vendor files"],"x-yoprint-docs":{"errors":[{"fix":"Send the file as multipart form data.","status":422,"when":"`media` is missing or not a file, or `collection` is not allowed. `error.code` is `validation_failed`."},{"fix":"Put the file in a .zip, or send a different file type.","status":422,"when":"The file is a web page, a script or a program, judged by its extension and by its detected type (for example .html, .js, .php, .py, .sh, .exe, .bat, .jar, .apk, .app, .dmg). `error.fields.media` says \"This type of file cannot be uploaded.\" (`validation_failed`)."},{"fix":"Send it as a production file, or a smaller image.","status":422,"when":"A `mockup` is not an image a preview can be made of (`error.code` `mockup_type_not_allowed`), or an image is over 120 megapixels (`error.code` `image_not_allowed`)."},{"fix":"Check the id.","status":404,"when":"No live vendor with this id. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Any member of the team.","related":["v1_public_vendor_media_index","v1_public_vendor_media_sync"]}}},"/v1/api/store/{team_slug}/vendor/{hash_id}/media/{media_reference}":{"delete":{"description":"Deletes one file from the vendor.","operationId":"v1_public_vendor_media_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The file's id (`id` from List a vendor's files). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"YMlcxHYran1mzL","in":"path","name":"media_reference","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a vendor file","tags":["Vendor files"],"x-yoprint-docs":{"errors":[{"fix":"Check the ids.","status":404,"when":"Not a file of this vendor. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Any member of the team.","related":["v1_public_vendor_media_sync"]}},"get":{"description":"Returns one file of the vendor.","operationId":"v1_public_vendor_media_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"The file's id (`id` from List a vendor's files). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"YMlcxHYran1mzL","in":"path","name":"media_reference","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"collection":"default","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"file_name":"price-list.pdf","id":"YMlcxHYran1mzL","is_image":false,"mime_type":"application/pdf","name":"Price list 2026","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/YMlcxHYran1mzL/download","view_url":"https://example.com/media/YMlcxHYran1mzL/view"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a vendor file","tags":["Vendor files"],"x-yoprint-docs":{"group":"Purchasing","permission":"Any member of the team.","related":["v1_public_vendor_media_index"]}},"post":{"description":"Changes several of the vendor's files in one request and returns all its files. The last path segment must be the word `sync`.\n\nEach item names a file and an `action`: `update` sets its `name` and `position`, `delete` removes it. Items run in order, all or nothing.","operationId":"v1_public_vendor_media_sync","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}},{"description":"Always the word `sync`. The route only matches `sync`: any other value answers 405 (an HTML page unless you send `Accept: application/json`).","example":"sync","in":"path","name":"media_reference","required":true,"schema":{"enum":["sync"],"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"data":[{"action":"update","id":"YMlcxHYran1mzL","name":"Price list 2026","position":0},{"action":"delete","id":"mBwjI68SoEttbX"}]},"schema":{"additionalProperties":false,"properties":{"data":{"items":{"additionalProperties":false,"properties":{"action":{"enum":["update","delete"],"type":"string"},"id":{"description":"The file id.","type":"string"},"name":{"description":"`update`: the new display name.","type":"string"},"position":{"description":"`update`: where the file sorts, a whole number from 0.","minimum":0,"type":"integer"}},"required":["id","action"],"type":"object"},"minItems":1,"type":"array"}},"required":["data"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"collection":"default","created_at":"2026-11-01T09:00:00+00:00","custom_properties":[],"file_name":"price-list.pdf","id":"YMlcxHYran1mzL","is_image":false,"mime_type":"application/pdf","name":"Price list 2026","position":0,"preview":null,"show_in_pdf":null,"size":48211,"source_media_id":null,"url":"https://example.com/media/YMlcxHYran1mzL/download","view_url":"https://example.com/media/YMlcxHYran1mzL/view"}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"All the vendor's files after the changes.","items":{"additionalProperties":true,"properties":{"collection":{"description":"Customer files: `tax_exemption`, `internal_file` or `external_file`. Vendor files: `default`, `mockup` or `production_file`.","type":"string"},"created_at":{"format":"date-time","type":"string"},"custom_properties":{"additionalProperties":true,"type":["object","array"]},"customer_id":{"description":"Customer files only.","type":"string"},"dimensions":{"description":"Pixel size of an image, read from its header; null for other files and for images uploaded before the size was recorded.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"type":"string"},"id":{"type":"string"},"is_image":{"type":"boolean"},"mime_type":{"type":["string","null"]},"name":{"description":"The display name.","type":["string","null"]},"position":{"description":"Where the file sorts.","type":["integer","null"]},"preview":{"additionalProperties":true,"description":"Preview image links `small`, `medium` and `large` (250, 800 and 1200 px), or null when there is no preview.","type":["object","null"]},"preview_state":{"description":"`ready`: the preview links work. `processing`: an image over 10 MB whose stored preview a worker is still making (seconds); read the file again, or in the web app wait for `media.preview_state_changed` on the team channel. `too_large`: an image over 120 megapixels; it never gets a preview. `failed`: the worker gave up. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"type":["boolean","null"]},"size":{"description":"Bytes.","type":"integer"},"source_media_id":{"type":["string","null"]},"url":{"description":"Where to download the file.","type":["string","null"]},"view_url":{"description":"A signed link to view the file. It expires: read it fresh, and don't store it.","type":["string","null"]}},"required":["id","collection","name","file_name","mime_type","size","created_at"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Rename, reorder or delete vendor files","tags":["Vendor files"],"x-yoprint-docs":{"errors":[{"fix":"Fix each field named in `error.fields`; its keys are field paths such as `contact.0.phone`.","status":422,"when":"`data` is empty, or an item has no `id` or an `action` other than `update` and `delete`. `error.code` is `validation_failed`."},{"fix":"End the path with `/media/sync`.","status":405,"when":"The last path segment is not `sync`."},{"fix":"List the vendor's files first.","status":404,"when":"An `id` is not a file of this vendor. Nothing is changed. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Any member of the team.","related":["v1_public_vendor_media_index"]}}},"/v1/api/store/{team_slug}/vendor/{hash_id}/restore":{"patch":{"description":"Brings back a deleted vendor. Answers `success: true` with `data: null`. Restoring a vendor that is not deleted also succeeds.","operationId":"v1_public_vendor_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The vendor's id (`id` from List vendors). A hash id from an earlier answer; unique keys and document numbers (such as `PO0042`) don't work here.","example":"EDhVUaC6jbLbed","in":"path","name":"hash_id","required":true,"schema":{"example":"EDhVUaC6jbLbed","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a deleted vendor","tags":["Vendors"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Ask a team owner to raise Manage Vendors for your role.","status":403,"when":"Your role cannot update vendors. This 403 has a short body, `{\"message\": \"Insufficient Permission\"}`, with no `success` or `error`."},{"fix":"Check the id.","status":404,"when":"No vendor with this id, deleted or not. `error.code` is null and `error.message` names the record type."}],"group":"Purchasing","permission":"Needs the Manage Vendors permission at the level that can update vendors.","related":["v1_public_vendor_destroy"]}}},"/v1/api/store/{team_slug}/work_pipeline/bulk_update_position":{"post":{"description":"Sets the position of several tasks at once, as the web app does when you drag tasks on a board or within a job. Returns the updated tasks.\n\nPositions only order tasks; they don't need to be consecutive. All rows save together or none do.","operationId":"v1_public_work_pipeline_bulk_update_position","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"id":"hpioY1gDBQZdbI","position":1},{"id":"t7PBSkbHdIPjfl","position":2}],"schema":{"description":"A JSON array of `{ id, position }` pairs (not an object with a list inside).","items":{"properties":{"id":{"description":"The task. Each task at most once.","example":"V4keXwwxMQyXw7","type":"string"},"position":{"description":"The new position. Lower comes first.","example":1,"maximum":2147483647,"minimum":-2147483648,"type":"integer"}},"required":["id","position"],"type":"object"},"minItems":1,"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-05T17:00:00+00:00","id":"hpioY1gDBQZdbI","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"hTFITko5Q0R83y","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T15:05:00+00:00"},{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-06T17:00:00+00:00","id":"t7PBSkbHdIPjfl","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Print","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":2,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-05T09:00:00+00:00","status":{"color":"#9e9e9e","customer_label":"Pending","id":"P32Ic61q2HqUCD","label":"To do","pipeline_id":"SE3SfXjt6dPfnH","position":1,"role":"pipeline","trashed":false,"type":"start"},"status_completion_date":null,"status_id":"P32Ic61q2HqUCD","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T15:05:00+00:00"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A task.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Reorder tasks","tags":["Tasks"],"x-yoprint-docs":{"errors":[{"fix":"Send each task once with an integer position.","status":422,"when":"A missing or non-integer `position`, or an id that isn't a valid hash id (`validation_failed`, details in `error.fields`)."},{"fix":"Send each task of your team once.","status":422,"when":"A duplicate id, or an id that isn't one of your team's tasks (`job_validation_error`)."}],"group":"Production","permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_work_pipeline_filter","v2_public_job_work_pipeline_update"],"rules":["Each task may appear once: duplicates are a 422 \"Duplicate work pipeline IDs are not allowed.\"","Every id must be a task of your team, or nothing is saved: 422 \"Work pipeline not found!\""]}}},"/v1/api/store/{team_slug}/work_pipeline/calendar":{"post":{"description":"Tasks whose start or due date falls in the range, or whose dates span it. Returns at most 1,200 Tasks, in the requested sort, then Task id order. This route ignores `page` and `per_page` and never returns `pagination`.\n\nThe range runs from the start of the day of `start_date` to the end of the day of `end_date`. Send both as ISO 8601 date-times in UTC (`2026-11-01T00:00:00Z`): the day boundaries are taken from the date as written. Only tasks of live jobs on sales orders are listed.\n\nIf a range may hold more than 1,200 tasks, split it into shorter ranges. You can narrow it with the same `filters` and `sort` as Filter tasks. A date filter's `value` is a whole number of days, counted from the moment of the request in UTC: `eq` N matches the whole UTC day N days from today (0 is today, -1 yesterday); `gte` N matches dates on or after now plus N days; `lte` N matches dates on or before now **minus** N days. So \"due in the next 7 days\" is `due_date gte 0` and `due_date lte -7`, and \"overdue\" is `due_date lte 0`. This differs from the v2 filters (Filter invoices, the production control calendar), where `lte` and `gte` both count forward.","operationId":"v1_public_work_pipeline_calendar","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"end_date":"2026-11-07T00:00:00Z","filters":[{"key":"pipeline_id","operator":"in","value":["SE3SfXjt6dPfnH"]}],"start_date":"2026-11-01T00:00:00Z"},"schema":{"properties":{"end_date":{"description":"The last day of the range (ISO 8601).","format":"date-time","type":"string"},"filters":{"description":"Conditions, all of which must match. Omit for no filter.","items":{"properties":{"key":{"description":"What to filter on. See the table in the description.","enum":["status_id","status_type","pipeline_id","assigned_users","assigned_to_me","order_created_by","is_rush","start_date","due_date","start_date_is_set","due_date_is_set","status_last_change_date","status_completion_date","search"],"type":"string"},"operator":{"description":"How to compare. Each kind of key accepts only some operators.","enum":["eq","neq","gt","gte","lt","lte","in","nin","bt","ct","sw","ew"],"type":"string"},"value":{"description":"What to compare with: text, a number of days, true or false, or an array of hash ids or options, by kind of key.","items":{"type":"string"},"type":["string","number","boolean","array"]}},"required":["key","operator","value"],"type":"object"},"minItems":1,"type":"array"},"sort":{"description":"Sort keys, applied in order, then by task id. Without `sort` the tasks come by task id.","items":{"properties":{"direction":{"enum":["asc","desc"],"type":"string"},"key":{"enum":["status_id","status_label","pipeline_id","job_id","start_date","due_date","status_last_change_date","status_completion_date","job_item_count","order_cust_due_date","order_due_date","order_ship_due_date","order_ship_due_date_undated_last","created_at_id"],"type":"string"}},"required":["key","direction"],"type":"object"},"type":"array"},"start_date":{"description":"The first day of the range (ISO 8601).","format":"date-time","type":"string"}},"required":["start_date","end_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-05T17:00:00+00:00","id":"hpioY1gDBQZdbI","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"hTFITko5Q0R83y","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T15:05:00+00:00"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A task.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List tasks in a date range","tags":["Tasks"],"x-yoprint-docs":{"errors":[{"fix":"Send both dates and valid filters.","status":422,"when":"A date is missing or not ISO 8601, or a filter is invalid."}],"group":"Production","notes":["You get the 1,200 tasks with the lowest ids (or first in your sort) in the range; nothing tells you more were left out."],"permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_work_pipeline_filter","v1_public_job_calendar","v1_public_production_control_filter"],"rules":["`start_date` and `end_date` are required ISO 8601 dates.","A task is in the range when its start or due date falls in it, or it starts before and is due after it. Undated tasks never appear."]}}},"/v1/api/store/{team_slug}/work_pipeline/filter":{"post":{"description":"Returns one page of your team's tasks across all jobs that match the filters, in the order you ask for.\n\nOnly tasks of live jobs on sales orders are listed.\n\nEvery condition in `filters` must match (they are joined with AND). Omit `filters` for no filter; an empty array is a 422. A `key` that isn't in the table, a missing `operator` or `value`, or a value of the wrong kind fails the whole request with 422; the message for `filters` (or `sort`) is the bare rule name `validation.filter_rule` (or `validation.filter_sort_rule`), with no detail, so check each filter against the table. Send real values: no key here matches empty columns with `\"null\"` or `\"\"` (for dates, use the `..._is_set` keys where the table has them). Hash ids in `value` are decoded for you. `system-current-user` stands for the caller only where a key's row says so; elsewhere it is compared as a raw value, so with `in` it matches nothing and with `nin` it matches every row that has a value.\n\n| `key` | Kind | Operators and `value` | Meaning |\n| --- | --- | --- | --- |\n| `status_id` | Hash ids | `in` or `nin`, with an array of hash ids. | The task status (statuses belong to a task preset). |\n| `status_type` | Options | `in` or `nin`, with an array of the listed values. | The kind of status: `start` (Pending), `pre_production` or `in_progress` (In Progress), `end` (Completed). |\n| `pipeline_id` | Hash ids | `in` or `nin`, with an array of hash ids. | The task preset. |\n| `assigned_users` | Hash ids | `in` or `nin`, with an array of hash ids. | Assigned users (user hash ids, or `system-current-user`). `in` matches tasks with one of them. `nin` matches tasks that have an assignee outside the list, not tasks without those users. |\n| `assigned_to_me` | Yes or no | `eq` or `neq`, with `true` or `false`. | Send `eq` `true` for tasks assigned to the caller. The operator isn't read (`neq true` means the same). `false` matches tasks that have someone other than the caller assigned; unassigned tasks never match. |\n| `order_created_by` | Hash ids | `in` or `nin`, with an array of hash ids. | Who created the sales order (user hash ids). `system-current-user` is not supported here: with `in` it matches nothing, with `nin` everything. |\n| `is_rush` | Yes or no | `eq` or `neq`, with `true` or `false`. | The task belongs to a rush job. |\n| `start_date` | Date | `eq`, `gte` or `lte`, with a whole number of days counted from now (UTC). See below. | The task's start date. |\n| `due_date` | Date | `eq`, `gte` or `lte`, with a whole number of days counted from now (UTC). See below. | The task's due date. |\n| `start_date_is_set` | Yes or no | `eq` or `neq`, with `true` or `false`. | The task has a start date (`eq true`) or none (`eq false`). Use `eq` only: any `neq` means \"has the date\". |\n| `due_date_is_set` | Yes or no | `eq` or `neq`, with `true` or `false`. | The task has a due date (`eq true`) or none (`eq false`). Use `eq` only: any `neq` means \"has the date\". |\n| `status_last_change_date` | Date | `eq`, `gte` or `lte`, with a whole number of days counted from now (UTC). See below. | When the status last changed. |\n| `status_completion_date` | Date | `eq`, `gte` or `lte`, with a whole number of days counted from now (UTC). See below. | When the task reached a Completed status. |\n| `search` | Text search | Any operator (`ct` reads best). The value must not be empty. | Task name, plus the job and order fields Filter jobs searches. |\n\nA date filter's `value` is a whole number of days, counted from the moment of the request in UTC: `eq` N matches the whole UTC day N days from today (0 is today, -1 yesterday); `gte` N matches dates on or after now plus N days; `lte` N matches dates on or before now **minus** N days. So \"due in the next 7 days\" is `due_date gte 0` and `due_date lte -7`, and \"overdue\" is `due_date lte 0`. This differs from the v2 filters (Filter invoices, the production control calendar), where `lte` and `gte` both count forward.\n\nThe response is one page with `pagination`. The page size is the team's list page size setting (50 unless the team changed it); `per_page` is not read. Send `page` (from 1) in the body or the query string for later pages.","operationId":"v1_public_work_pipeline_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"filters":[{"key":"assigned_to_me","operator":"eq","value":true},{"key":"status_type","operator":"nin","value":["end"]}],"page":1,"sort":[{"direction":"asc","key":"due_date"}]},"schema":{"properties":{"filters":{"description":"Conditions, all of which must match. Omit for no filter.","items":{"properties":{"key":{"description":"What to filter on. See the table in the description.","enum":["status_id","status_type","pipeline_id","assigned_users","assigned_to_me","order_created_by","is_rush","start_date","due_date","start_date_is_set","due_date_is_set","status_last_change_date","status_completion_date","search"],"type":"string"},"operator":{"description":"How to compare. Each kind of key accepts only some operators.","enum":["eq","neq","gt","gte","lt","lte","in","nin","bt","ct","sw","ew"],"type":"string"},"value":{"description":"What to compare with: text, a number of days, true or false, or an array of hash ids or options, by kind of key.","items":{"type":"string"},"type":["string","number","boolean","array"]}},"required":["key","operator","value"],"type":"object"},"minItems":1,"type":"array"},"page":{"default":1,"description":"The page to read.","minimum":1,"type":"integer"},"sort":{"description":"Sort keys, applied in order. Without `sort` the order is not guaranteed.","items":{"properties":{"direction":{"enum":["asc","desc"],"type":"string"},"key":{"enum":["status_id","status_label","pipeline_id","job_id","start_date","due_date","status_last_change_date","status_completion_date","job_item_count","order_cust_due_date","order_due_date","order_ship_due_date","order_ship_due_date_undated_last","created_at_id"],"type":"string"}},"required":["key","direction"],"type":"object"},"type":"array"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-05T17:00:00+00:00","id":"hpioY1gDBQZdbI","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"hTFITko5Q0R83y","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T15:05:00+00:00"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A task.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Filter tasks","tags":["Tasks"],"x-yoprint-docs":{"errors":[{"fix":"Check each filter against the table.","status":422,"when":"A filter has an unknown `key`, a missing part, or an operator or value its kind doesn't accept; or `filters` is an empty array."}],"group":"Production","notes":["`assigned_users` with `nin` keeps its old meaning on this route: \"has someone assigned who isn't in the list\"."],"permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_work_pipeline_calendar","v2_public_job_work_pipeline_index_for_job","v1_public_status_list_pipeline"]}}},"/v2/api/store/{team_slug}/messages":{"get":{"description":"Lists the messages on your team's sales orders, quotes and purchase orders, newest first: emails and texts you sent to customers and vendors, and the replies they sent back. YoPrint's internal staff notifications are not included.\n\nEach message has its sender, a preview, what it is on, and `delivery_summary`, which tells you whether it reached everyone. The page size is your team's list size setting (50 unless changed); use `page` to read further. To filter, use `POST /v2/api/store/{team_slug}/messages/filter`.","operationId":"v2_public_messages_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The page to read, from 1.","in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"actor_name":"Alex Rivera","actor_type":"user","attachments":[],"contact":null,"contact_id":null,"created_at":"2026-11-03T09:30:00+00:00","customer":{"id":2001,"name":"Northwind Apparel"},"delivery_summary":{"accepted":0,"complete":true,"delivered":0,"failed":1,"reason":null,"retryable":true,"skipped":0,"state":"failed","submitting":0,"total":1,"unknown":0,"waiting":0},"email":"alex@example.com","has_message":true,"has_original_message":true,"id":"u7HKhdhT6tkEUy","is_order_rush":0,"mode":"view","name":"Alex Rivera","order_id":"V4keXwwxMQyXw7","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","participant":null,"preview_message":"Your order is ready for pickup.","purchase_order_id":null,"purchase_scoped_id":"","recipients":[{"can_receive_mail":true,"can_receive_sms":false,"contact":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"63KcENAAsKuipY","default_receive_sms":false,"email":"jordan@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Jordan","id":"uTCR3hxPDePBUK","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"contact_id":"uTCR3hxPDePBUK","delivery_channel":"email","delivery_created_at":"2026-11-03T09:30:00+00:00","delivery_destination":"jordan@example.com","delivery_destination_name":"Jordan Lee","delivery_id":"XWwTVKIZSuUOcX","delivery_latest_error_reason":"The server was unable to deliver your message (ex: unknown user, mailbox not found).","delivery_message_id":"u7HKhdhT6tkEUy","delivery_participant_id":"vKNPqQz8fsYDuT","delivery_state":"failed","delivery_status":"delivery_failed","delivery_updated_at":"2026-11-03T09:31:00+00:00","email":"jordan@example.com","id":"vKNPqQz8fsYDuT","name":"Jordan Lee","order_id":"V4keXwwxMQyXw7","phone":"+1 201 555 0123","purchase_order_id":null,"status":"all","trashed":false,"type":"contact"}],"rendered_attachments":[],"status":"delivery_failed","status_id":null,"system":false,"type":"outbound","user":{"avatar_url":"https://example.com/avatar.png","email":"alex@example.com","ga_id":"u1001","has_affiliate_account":false,"hs_id":1001,"id":"VG7s3tFzyQbO2N","last_trial":null,"name":"Alex Rivera","onboarded":true,"preference":null,"sso":false,"timezone":"America/New_York","trial_used":false},"user_id":"VG7s3tFzyQbO2N","vendor":null}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"actor_name":{"description":"The writer's name, by `actor_type`: your team's name for `system`, the team member, the contact, the order's customer, the purchase order's vendor, the participant, or the name a `guest` gave. Null when YoPrint can't find the writer's record.","type":["string","null"]},"actor_type":{"description":"Who wrote it: `user`, `customer`, `vendor`, `contact` (written in the customer or vendor portal), `participant`, `guest` (someone who is not a contact) or `system`.","type":"string"},"attachments":{"description":"Files attached to it, in the same shape as an upload (`id`, `name`, `file_name`, `mime_type`, `size`, `url`).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"contact":{"additionalProperties":true,"description":"The contact who wrote it, when `contact_id` is set: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"customer":{"description":"The order's customer. Null without an order.","properties":{"id":{"description":"A plain number, not a hash id; no operation takes it.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]},"delivery_summary":{"description":"Outbound messages: how delivery went across all recipients. Null for inbound messages.","properties":{"accepted":{"type":"integer"},"complete":{"type":"boolean"},"delivered":{"type":"integer"},"failed":{"type":"integer"},"reason":{"description":"Why the state is not final, or why nothing was sent, for example `no_recipients` or `delivery_evidence_unavailable`. Usually null.","type":["string","null"]},"retryable":{"description":"True when the retry operation accepts this message. When false, it answers 422.","type":"boolean"},"skipped":{"type":"integer"},"state":{"description":"`sent`: the provider took it, delivery not confirmed yet. `partial`: recipients are in different states. `not_sent`: there were no recipients.","enum":["pending","sending","sent","delivered","failed","partial","unknown","not_sent"],"type":"string"},"submitting":{"type":"integer"},"total":{"type":"integer"},"unknown":{"type":"integer"},"waiting":{"type":"integer"}},"type":["object","null"]},"email":{"description":"The sender's email address.","type":["string","null"]},"has_message":{"type":"boolean"},"has_original_message":{"type":"boolean"},"id":{"type":"string"},"is_order_rush":{"description":"`1` for a rush order, `0` otherwise (a number, not a boolean); null for a message without an order.","enum":[0,1,null],"type":["integer","null"]},"mode":{"description":"The order's state in the web app: `view` once it is created, `create` while it is a draft, `edit` while someone is editing it. `false` (not null) without an order.","type":["string","boolean"]},"name":{"description":"The sender's name.","type":["string","null"]},"order_id":{"description":"The sales order or quote it is on.","type":["string","null"]},"order_object_type":{"description":"`sales_order` or `quote`. Null without an order.","type":["string","null"]},"order_quote":{"type":["boolean","null"]},"order_scoped_id":{"description":"The order's number, such as `SO1001`. Null without an order.","type":["string","null"]},"participant":{"additionalProperties":true,"description":"The author, as a message participant, when `message_participant_id` is set. Its `delivery_*` fields are null.","properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact":{"additionalProperties":true,"description":"The contact, for `type` `contact`: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"delivery_channel":{"enum":["email","sms",null],"type":["string","null"]},"delivery_created_at":{"format":"date-time","type":["string","null"]},"delivery_destination":{"description":"The email address or phone number it went to.","type":["string","null"]},"delivery_destination_name":{"type":["string","null"]},"delivery_id":{"description":"The recipient id: the id the recipient operations take. Null on `participant`.","type":["string","null"]},"delivery_latest_error_reason":{"type":["string","null"]},"delivery_message_id":{"type":["string","null"]},"delivery_participant_id":{"type":["string","null"]},"delivery_state":{"description":"From the provider's report. Null for older messages and on `participant`.","enum":["pending","sending","sent","delivered","failed","unknown",null],"type":["string","null"]},"delivery_status":{"enum":["pending","dispatched","dispatch_failed","delivered","delivery_failed",null],"type":["string","null"]},"delivery_updated_at":{"format":"date-time","type":["string","null"]},"email":{"type":["string","null"]},"id":{"description":"The participant id. The recipient operations take `delivery_id`, not this.","type":"string"},"name":{"type":["string","null"]},"order_id":{"type":["string","null"]},"phone":{"type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"status":{"description":"What they receive: `message`, `notification`, `all` or `disabled`.","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"`user`: a team member. `contact`: one of the customer's or vendor's contacts. `guest`: just a name and email.","enum":["user","contact","guest"],"type":"string"}},"type":["object","null"]},"preview_message":{"description":"A short plain-text preview.","type":["string","null"]},"purchase_order_id":{"description":"The purchase order it is on.","type":["string","null"]},"purchase_scoped_id":{"description":"The purchase order's number. An empty string `\"\"` (not null) when it is not on a purchase order.","type":["string","null"]},"recipients":{"description":"Who it was sent to: each participant with its delivery (`delivery_status`, `delivery_channel`, `delivery_destination`). `delivery_id` is the id the recipient operations take.","items":{"additionalProperties":true,"properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact":{"additionalProperties":true,"description":"The contact, for `type` `contact`: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"delivery_channel":{"enum":["email","sms",null],"type":["string","null"]},"delivery_created_at":{"format":"date-time","type":["string","null"]},"delivery_destination":{"description":"The email address or phone number it went to.","type":["string","null"]},"delivery_destination_name":{"type":["string","null"]},"delivery_id":{"description":"The recipient id: the id the recipient operations take. Null on `participant`.","type":["string","null"]},"delivery_latest_error_reason":{"type":["string","null"]},"delivery_message_id":{"type":["string","null"]},"delivery_participant_id":{"type":["string","null"]},"delivery_state":{"description":"From the provider's report. Null for older messages and on `participant`.","enum":["pending","sending","sent","delivered","failed","unknown",null],"type":["string","null"]},"delivery_status":{"enum":["pending","dispatched","dispatch_failed","delivered","delivery_failed",null],"type":["string","null"]},"delivery_updated_at":{"format":"date-time","type":["string","null"]},"email":{"type":["string","null"]},"id":{"description":"The participant id. The recipient operations take `delivery_id`, not this.","type":"string"},"name":{"type":["string","null"]},"order_id":{"type":["string","null"]},"phone":{"type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"status":{"description":"What they receive: `message`, `notification`, `all` or `disabled`.","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"`user`: a team member. `contact`: one of the customer's or vendor's contacts. `guest`: just a name and email.","enum":["user","contact","guest"],"type":"string"}},"type":"object"},"type":"array"},"rendered_attachments":{"description":"Everything attached when it was sent: the files (`attachment_type` `media`, upload shape) and generated documents such as the order PDF (`attachment_type` `internal_attachment`, with `name` and `url`).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"status":{"description":"Older delivery status word, such as `pending`, `dispatched`, `partial_delivered`, `delivery_failed`, `delivered`, or `received` for a reply. Prefer `delivery_summary`.","type":["string","null"]},"status_id":{"description":"Your team's message status (for example \"Needs reply\"), set with the status operation. Null when none is set.","type":["string","null"]},"system":{"description":"True for messages YoPrint sent automatically.","type":"boolean"},"type":{"description":"`outbound`: sent by your team. `inbound`: a reply received.","enum":["outbound","inbound"],"type":"string"},"user":{"additionalProperties":true,"description":"The team member who wrote it, when `user_id` is set. The list sends their whole account profile; rely only on `id`, `name`, `email`, `avatar_url` and `timezone`, which the single message also has.","type":["object","null"]},"user_id":{"type":["string","null"]},"vendor":{"description":"The purchase order's vendor. Null without a purchase order.","properties":{"id":{"description":"A plain number, not a hash id; no operation takes it.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List messages","tags":["Messages"],"x-yoprint-docs":{"group":"Messages and activity","notes":["To read one message in full, with its body, use `GET /v2/api/store/{team_slug}/messages/{hash_id}`.","`customer.id` and `vendor.id` here are plain numbers, not the hash ids other operations take. Read the order or purchase order to reach them."],"permission":"Any member can read purchase order messages. For sales order and quote messages you need permission to message all orders, or only the orders you created or are assigned to. The team owner sees everything. Without either permission you see only purchase order messages.","related":["v2_public_messages_filter","v2_public_messages_show","v2_public_order_message_index"]}}},"/v2/api/store/{team_slug}/messages/filter":{"post":{"description":"Lists messages like `GET /v2/api/store/{team_slug}/messages`, narrowed by direction or status, with an optional sort. For example, replies that still have no status: `type` `in` `[\"inbound\"]` and `is_status_null` `eq` `true`.\n\nEach filter is `{key, operator, value}`. Several filters must all match. Send `page` in the body or the query string.","operationId":"v2_public_messages_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"filters":[{"key":"type","operator":"in","value":["inbound"]},{"key":"is_status_null","operator":"eq","value":true}],"sort":[{"direction":"desc","key":"created_at"}]},"schema":{"properties":{"filters":{"items":{"properties":{"key":{"description":"`type`: `outbound` or `inbound`. `status`: the older delivery status word (`delivered`, `delivery_failed`, `received`, ...). `status_id`: your team's message status ids. `is_status_null`: whether a status is set.","enum":["type","status","status_id","is_status_null"],"type":"string"},"operator":{"description":"`in` or `nin` with a list, for `type`, `status` and `status_id`. `eq` (or `neq`, which is accepted and acts the same) with `true` or `false`, for `is_status_null`.","enum":["in","nin","eq","neq"],"type":"string"},"value":{"items":{"type":"string"},"type":["array","boolean"]}},"required":["key","operator","value"],"type":"object"},"minItems":1,"type":"array"},"page":{"minimum":1,"type":"integer"},"sort":{"items":{"properties":{"direction":{"enum":["asc","desc"],"type":"string"},"key":{"enum":["id","order_id","purchase_order_id","type","actor_type","created_at","status"],"type":"string"}},"required":["key","direction"],"type":"object"},"type":"array"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"actor_name":"Alex Rivera","actor_type":"user","attachments":[],"contact":null,"contact_id":null,"created_at":"2026-11-03T09:30:00+00:00","customer":{"id":2001,"name":"Northwind Apparel"},"delivery_summary":{"accepted":0,"complete":true,"delivered":0,"failed":1,"reason":null,"retryable":true,"skipped":0,"state":"failed","submitting":0,"total":1,"unknown":0,"waiting":0},"email":"alex@example.com","has_message":true,"has_original_message":true,"id":"u7HKhdhT6tkEUy","is_order_rush":0,"mode":"view","name":"Alex Rivera","order_id":"V4keXwwxMQyXw7","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","participant":null,"preview_message":"Your order is ready for pickup.","purchase_order_id":null,"purchase_scoped_id":"","recipients":[{"can_receive_mail":true,"can_receive_sms":false,"contact":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"63KcENAAsKuipY","default_receive_sms":false,"email":"jordan@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Jordan","id":"uTCR3hxPDePBUK","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"contact_id":"uTCR3hxPDePBUK","delivery_channel":"email","delivery_created_at":"2026-11-03T09:30:00+00:00","delivery_destination":"jordan@example.com","delivery_destination_name":"Jordan Lee","delivery_id":"XWwTVKIZSuUOcX","delivery_latest_error_reason":"The server was unable to deliver your message (ex: unknown user, mailbox not found).","delivery_message_id":"u7HKhdhT6tkEUy","delivery_participant_id":"vKNPqQz8fsYDuT","delivery_state":"failed","delivery_status":"delivery_failed","delivery_updated_at":"2026-11-03T09:31:00+00:00","email":"jordan@example.com","id":"vKNPqQz8fsYDuT","name":"Jordan Lee","order_id":"V4keXwwxMQyXw7","phone":"+1 201 555 0123","purchase_order_id":null,"status":"all","trashed":false,"type":"contact"}],"rendered_attachments":[],"status":"delivery_failed","status_id":null,"system":false,"type":"outbound","user":{"avatar_url":"https://example.com/avatar.png","email":"alex@example.com","ga_id":"u1001","has_affiliate_account":false,"hs_id":1001,"id":"VG7s3tFzyQbO2N","last_trial":null,"name":"Alex Rivera","onboarded":true,"preference":null,"sso":false,"timezone":"America/New_York","trial_used":false},"user_id":"VG7s3tFzyQbO2N","vendor":null}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"actor_name":{"description":"The writer's name, by `actor_type`: your team's name for `system`, the team member, the contact, the order's customer, the purchase order's vendor, the participant, or the name a `guest` gave. Null when YoPrint can't find the writer's record.","type":["string","null"]},"actor_type":{"description":"Who wrote it: `user`, `customer`, `vendor`, `contact` (written in the customer or vendor portal), `participant`, `guest` (someone who is not a contact) or `system`.","type":"string"},"attachments":{"description":"Files attached to it, in the same shape as an upload (`id`, `name`, `file_name`, `mime_type`, `size`, `url`).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"contact":{"additionalProperties":true,"description":"The contact who wrote it, when `contact_id` is set: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"customer":{"description":"The order's customer. Null without an order.","properties":{"id":{"description":"A plain number, not a hash id; no operation takes it.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]},"delivery_summary":{"description":"Outbound messages: how delivery went across all recipients. Null for inbound messages.","properties":{"accepted":{"type":"integer"},"complete":{"type":"boolean"},"delivered":{"type":"integer"},"failed":{"type":"integer"},"reason":{"description":"Why the state is not final, or why nothing was sent, for example `no_recipients` or `delivery_evidence_unavailable`. Usually null.","type":["string","null"]},"retryable":{"description":"True when the retry operation accepts this message. When false, it answers 422.","type":"boolean"},"skipped":{"type":"integer"},"state":{"description":"`sent`: the provider took it, delivery not confirmed yet. `partial`: recipients are in different states. `not_sent`: there were no recipients.","enum":["pending","sending","sent","delivered","failed","partial","unknown","not_sent"],"type":"string"},"submitting":{"type":"integer"},"total":{"type":"integer"},"unknown":{"type":"integer"},"waiting":{"type":"integer"}},"type":["object","null"]},"email":{"description":"The sender's email address.","type":["string","null"]},"has_message":{"type":"boolean"},"has_original_message":{"type":"boolean"},"id":{"type":"string"},"is_order_rush":{"description":"`1` for a rush order, `0` otherwise (a number, not a boolean); null for a message without an order.","enum":[0,1,null],"type":["integer","null"]},"mode":{"description":"The order's state in the web app: `view` once it is created, `create` while it is a draft, `edit` while someone is editing it. `false` (not null) without an order.","type":["string","boolean"]},"name":{"description":"The sender's name.","type":["string","null"]},"order_id":{"description":"The sales order or quote it is on.","type":["string","null"]},"order_object_type":{"description":"`sales_order` or `quote`. Null without an order.","type":["string","null"]},"order_quote":{"type":["boolean","null"]},"order_scoped_id":{"description":"The order's number, such as `SO1001`. Null without an order.","type":["string","null"]},"participant":{"additionalProperties":true,"description":"The author, as a message participant, when `message_participant_id` is set. Its `delivery_*` fields are null.","properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact":{"additionalProperties":true,"description":"The contact, for `type` `contact`: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"delivery_channel":{"enum":["email","sms",null],"type":["string","null"]},"delivery_created_at":{"format":"date-time","type":["string","null"]},"delivery_destination":{"description":"The email address or phone number it went to.","type":["string","null"]},"delivery_destination_name":{"type":["string","null"]},"delivery_id":{"description":"The recipient id: the id the recipient operations take. Null on `participant`.","type":["string","null"]},"delivery_latest_error_reason":{"type":["string","null"]},"delivery_message_id":{"type":["string","null"]},"delivery_participant_id":{"type":["string","null"]},"delivery_state":{"description":"From the provider's report. Null for older messages and on `participant`.","enum":["pending","sending","sent","delivered","failed","unknown",null],"type":["string","null"]},"delivery_status":{"enum":["pending","dispatched","dispatch_failed","delivered","delivery_failed",null],"type":["string","null"]},"delivery_updated_at":{"format":"date-time","type":["string","null"]},"email":{"type":["string","null"]},"id":{"description":"The participant id. The recipient operations take `delivery_id`, not this.","type":"string"},"name":{"type":["string","null"]},"order_id":{"type":["string","null"]},"phone":{"type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"status":{"description":"What they receive: `message`, `notification`, `all` or `disabled`.","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"`user`: a team member. `contact`: one of the customer's or vendor's contacts. `guest`: just a name and email.","enum":["user","contact","guest"],"type":"string"}},"type":["object","null"]},"preview_message":{"description":"A short plain-text preview.","type":["string","null"]},"purchase_order_id":{"description":"The purchase order it is on.","type":["string","null"]},"purchase_scoped_id":{"description":"The purchase order's number. An empty string `\"\"` (not null) when it is not on a purchase order.","type":["string","null"]},"recipients":{"description":"Who it was sent to: each participant with its delivery (`delivery_status`, `delivery_channel`, `delivery_destination`). `delivery_id` is the id the recipient operations take.","items":{"additionalProperties":true,"properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact":{"additionalProperties":true,"description":"The contact, for `type` `contact`: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"delivery_channel":{"enum":["email","sms",null],"type":["string","null"]},"delivery_created_at":{"format":"date-time","type":["string","null"]},"delivery_destination":{"description":"The email address or phone number it went to.","type":["string","null"]},"delivery_destination_name":{"type":["string","null"]},"delivery_id":{"description":"The recipient id: the id the recipient operations take. Null on `participant`.","type":["string","null"]},"delivery_latest_error_reason":{"type":["string","null"]},"delivery_message_id":{"type":["string","null"]},"delivery_participant_id":{"type":["string","null"]},"delivery_state":{"description":"From the provider's report. Null for older messages and on `participant`.","enum":["pending","sending","sent","delivered","failed","unknown",null],"type":["string","null"]},"delivery_status":{"enum":["pending","dispatched","dispatch_failed","delivered","delivery_failed",null],"type":["string","null"]},"delivery_updated_at":{"format":"date-time","type":["string","null"]},"email":{"type":["string","null"]},"id":{"description":"The participant id. The recipient operations take `delivery_id`, not this.","type":"string"},"name":{"type":["string","null"]},"order_id":{"type":["string","null"]},"phone":{"type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"status":{"description":"What they receive: `message`, `notification`, `all` or `disabled`.","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"`user`: a team member. `contact`: one of the customer's or vendor's contacts. `guest`: just a name and email.","enum":["user","contact","guest"],"type":"string"}},"type":"object"},"type":"array"},"rendered_attachments":{"description":"Everything attached when it was sent: the files (`attachment_type` `media`, upload shape) and generated documents such as the order PDF (`attachment_type` `internal_attachment`, with `name` and `url`).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"status":{"description":"Older delivery status word, such as `pending`, `dispatched`, `partial_delivered`, `delivery_failed`, `delivered`, or `received` for a reply. Prefer `delivery_summary`.","type":["string","null"]},"status_id":{"description":"Your team's message status (for example \"Needs reply\"), set with the status operation. Null when none is set.","type":["string","null"]},"system":{"description":"True for messages YoPrint sent automatically.","type":"boolean"},"type":{"description":"`outbound`: sent by your team. `inbound`: a reply received.","enum":["outbound","inbound"],"type":"string"},"user":{"additionalProperties":true,"description":"The team member who wrote it, when `user_id` is set. The list sends their whole account profile; rely only on `id`, `name`, `email`, `avatar_url` and `timezone`, which the single message also has.","type":["object","null"]},"user_id":{"type":["string","null"]},"vendor":{"description":"The purchase order's vendor. Null without a purchase order.","properties":{"id":{"description":"A plain number, not a hash id; no operation takes it.","type":"integer"},"name":{"type":"string"}},"type":["object","null"]}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Filter messages","tags":["Messages"],"x-yoprint-docs":{"errors":[{"fix":"Use the keys and operators listed here, or leave `filters` out.","status":422,"when":"`filters` is an empty list, or a key, operator or value is not allowed (`validation_failed`, with the problem under `error.fields`)."}],"group":"Messages and activity","notes":["Without `sort`, the order of results is not defined. Send `created_at` `desc` when you page.","`is_status_null` only reads `value`: `true` finds messages without a status and `false` those with one, whatever the operator.","Get `status_id` values from your team's message statuses (`GET /v1/api/store/{team_slug}/setting/status/customer_message`)."],"permission":"Any member can read purchase order messages. For sales order and quote messages you need permission to message all orders, or only the orders you created or are assigned to. The team owner sees everything.","related":["v2_public_messages_index","v1_public_status_list_customer_message"],"rules":["`filters` is optional. If you send it, it can't be empty. Leaving it out returns every message you can see. Keys: `type`, `status`, `status_id`, `is_status_null`.","For `type`, `status` and `status_id`, `value` is a list and `operator` is `in` or `nin`. For `is_status_null`, `value` is `true` or `false` (JSON booleans) and `operator` is `eq` or `neq`.","Values of `type` and `status` are not checked: a word no message has just matches nothing.","Sort keys: `id`, `order_id`, `purchase_order_id`, `type`, `actor_type`, `created_at`, `status`."]}}},"/v2/api/store/{team_slug}/messages/{hash_id}":{"get":{"description":"Returns one message in full: the message as written (`message`), the whole message as HTML (`original_message`), attachments, recipients with their delivery status, its team status, and `retryable`, which says whether a failed delivery can be sent again.\n\nIt has fields the list doesn't (`display_type`, `message_participant_id`, `driver`, `message`, `original_message`, `retryable`, `message_status`) and lacks some the list has (`customer`, `vendor`, `is_order_rush`, `mode`).","operationId":"v2_public_messages_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message's `id`, from the message list. A hash id; unique keys and document numbers are refused with 404.","example":"u7HKhdhT6tkEUy","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"actor_name":"Alex Rivera","actor_type":"user","attachments":[],"contact":null,"contact_id":null,"created_at":"2026-11-03T09:30:00+00:00","delivery_summary":{"accepted":0,"complete":true,"delivered":0,"failed":1,"reason":null,"retryable":true,"skipped":0,"state":"failed","submitting":0,"total":1,"unknown":0,"waiting":0},"display_type":"default_v2","driver":"email","email":"alex@example.com","has_message":true,"has_original_message":true,"id":"u7HKhdhT6tkEUy","message":"<p>Your order is ready for pickup.</p>","message_participant_id":null,"message_status":null,"name":"Alex Rivera","order_id":"V4keXwwxMQyXw7","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","original_message":"<html><body><p>Your order is ready for pickup.</p></body></html>","participant":null,"preview_message":"Your order is ready for pickup.","purchase_order_id":null,"purchase_scoped_id":null,"recipients":[{"can_receive_mail":true,"can_receive_sms":false,"contact":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"63KcENAAsKuipY","default_receive_sms":false,"email":"jordan@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Jordan","id":"uTCR3hxPDePBUK","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"contact_id":"uTCR3hxPDePBUK","delivery_channel":"email","delivery_created_at":"2026-11-03T09:30:00+00:00","delivery_destination":"jordan@example.com","delivery_destination_name":"Jordan Lee","delivery_id":"XWwTVKIZSuUOcX","delivery_latest_error_reason":"The server was unable to deliver your message (ex: unknown user, mailbox not found).","delivery_message_id":"u7HKhdhT6tkEUy","delivery_participant_id":"vKNPqQz8fsYDuT","delivery_state":"failed","delivery_status":"delivery_failed","delivery_updated_at":"2026-11-03T09:31:00+00:00","email":"jordan@example.com","id":"vKNPqQz8fsYDuT","name":"Jordan Lee","order_id":"V4keXwwxMQyXw7","phone":"+1 201 555 0123","purchase_order_id":null,"status":"all","trashed":false,"type":"contact"}],"rendered_attachments":[],"retryable":true,"status":"delivery_failed","status_id":null,"system":false,"type":"outbound","user":{"avatar_url":"https://example.com/avatar.png","email":"alex@example.com","id":"VG7s3tFzyQbO2N","name":"Alex Rivera","timezone":"America/New_York"},"user_id":"VG7s3tFzyQbO2N"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"actor_name":{"description":"The writer's name, by `actor_type`: your team's name for `system`, the team member, the contact, the order's customer, the purchase order's vendor, the participant, or the name a `guest` gave. Null when YoPrint can't find the writer's record.","type":["string","null"]},"actor_type":{"description":"Who wrote it: `user`, `customer`, `vendor`, `contact` (written in the customer or vendor portal), `participant`, `guest` (someone who is not a contact) or `system`.","type":"string"},"attachments":{"description":"Files attached to it, in the same shape as an upload (`id`, `name`, `file_name`, `mime_type`, `size`, `url`).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"contact":{"additionalProperties":true,"description":"The contact who wrote it, when `contact_id` is set: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"delivery_summary":{"description":"Outbound messages: how delivery went across all recipients. Null for inbound messages.","properties":{"accepted":{"type":"integer"},"complete":{"type":"boolean"},"delivered":{"type":"integer"},"failed":{"type":"integer"},"reason":{"description":"Why the state is not final, or why nothing was sent, for example `no_recipients` or `delivery_evidence_unavailable`. Usually null.","type":["string","null"]},"retryable":{"description":"True when the retry operation accepts this message. When false, it answers 422.","type":"boolean"},"skipped":{"type":"integer"},"state":{"description":"`sent`: the provider took it, delivery not confirmed yet. `partial`: recipients are in different states. `not_sent`: there were no recipients.","enum":["pending","sending","sent","delivered","failed","partial","unknown","not_sent"],"type":"string"},"submitting":{"type":"integer"},"total":{"type":"integer"},"unknown":{"type":"integer"},"waiting":{"type":"integer"}},"type":["object","null"]},"display_type":{"description":"How the web app draws it, for example `default_v2`, or `system_v2` for automatic messages.","type":"string"},"driver":{"description":"`email`, `sms`, or `web` for a message written in YoPrint.","type":["string","null"]},"email":{"description":"The sender's email address.","type":["string","null"]},"has_message":{"type":"boolean"},"has_original_message":{"type":"boolean"},"id":{"type":"string"},"message":{"description":"The message as it was written, without the email layout.","type":["string","null"]},"message_participant_id":{"description":"The author, as a message participant.","type":["string","null"]},"message_status":{"additionalProperties":true,"description":"The status named by `status_id`: `id`, `role` (`customer_message`), `type`, `label`, `customer_label`, `color`, `position`, `trashed`.","type":["object","null"]},"name":{"description":"The sender's name.","type":["string","null"]},"order_id":{"description":"The sales order or quote it is on.","type":["string","null"]},"order_object_type":{"description":"`sales_order` or `quote`. Null without an order.","type":["string","null"]},"order_quote":{"type":["boolean","null"]},"order_scoped_id":{"description":"The order's number, such as `SO1001`. An empty string `\"\"` (not null) without an order.","type":["string","null"]},"original_message":{"description":"The whole message as HTML: for a reply, the email as it arrived, with any quoted text; for a message you sent, the full message YoPrint rendered.","type":["string","null"]},"participant":{"additionalProperties":true,"description":"The author, as a message participant, when `message_participant_id` is set. Its `delivery_*` fields are null.","properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact":{"additionalProperties":true,"description":"The contact, for `type` `contact`: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"delivery_channel":{"enum":["email","sms",null],"type":["string","null"]},"delivery_created_at":{"format":"date-time","type":["string","null"]},"delivery_destination":{"description":"The email address or phone number it went to.","type":["string","null"]},"delivery_destination_name":{"type":["string","null"]},"delivery_id":{"description":"The recipient id: the id the recipient operations take. Null on `participant`.","type":["string","null"]},"delivery_latest_error_reason":{"type":["string","null"]},"delivery_message_id":{"type":["string","null"]},"delivery_participant_id":{"type":["string","null"]},"delivery_state":{"description":"From the provider's report. Null for older messages and on `participant`.","enum":["pending","sending","sent","delivered","failed","unknown",null],"type":["string","null"]},"delivery_status":{"enum":["pending","dispatched","dispatch_failed","delivered","delivery_failed",null],"type":["string","null"]},"delivery_updated_at":{"format":"date-time","type":["string","null"]},"email":{"type":["string","null"]},"id":{"description":"The participant id. The recipient operations take `delivery_id`, not this.","type":"string"},"name":{"type":["string","null"]},"order_id":{"type":["string","null"]},"phone":{"type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"status":{"description":"What they receive: `message`, `notification`, `all` or `disabled`.","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"`user`: a team member. `contact`: one of the customer's or vendor's contacts. `guest`: just a name and email.","enum":["user","contact","guest"],"type":"string"}},"type":["object","null"]},"preview_message":{"description":"A short plain-text preview.","type":["string","null"]},"purchase_order_id":{"description":"The purchase order it is on.","type":["string","null"]},"purchase_scoped_id":{"description":"The purchase order's number. Null when it is not on a purchase order.","type":["string","null"]},"recipients":{"description":"Who it was sent to: each participant with its delivery (`delivery_status`, `delivery_channel`, `delivery_destination`). `delivery_id` is the id the recipient operations take.","items":{"additionalProperties":true,"properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact":{"additionalProperties":true,"description":"The contact, for `type` `contact`: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"delivery_channel":{"enum":["email","sms",null],"type":["string","null"]},"delivery_created_at":{"format":"date-time","type":["string","null"]},"delivery_destination":{"description":"The email address or phone number it went to.","type":["string","null"]},"delivery_destination_name":{"type":["string","null"]},"delivery_id":{"description":"The recipient id: the id the recipient operations take. Null on `participant`.","type":["string","null"]},"delivery_latest_error_reason":{"type":["string","null"]},"delivery_message_id":{"type":["string","null"]},"delivery_participant_id":{"type":["string","null"]},"delivery_state":{"description":"From the provider's report. Null for older messages and on `participant`.","enum":["pending","sending","sent","delivered","failed","unknown",null],"type":["string","null"]},"delivery_status":{"enum":["pending","dispatched","dispatch_failed","delivered","delivery_failed",null],"type":["string","null"]},"delivery_updated_at":{"format":"date-time","type":["string","null"]},"email":{"type":["string","null"]},"id":{"description":"The participant id. The recipient operations take `delivery_id`, not this.","type":"string"},"name":{"type":["string","null"]},"order_id":{"type":["string","null"]},"phone":{"type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"status":{"description":"What they receive: `message`, `notification`, `all` or `disabled`.","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"`user`: a team member. `contact`: one of the customer's or vendor's contacts. `guest`: just a name and email.","enum":["user","contact","guest"],"type":"string"}},"type":"object"},"type":"array"},"rendered_attachments":{"description":"Everything attached when it was sent: the files (`attachment_type` `media`, upload shape) and generated documents such as the order PDF (`attachment_type` `internal_attachment`, with `name` and `url`).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"retryable":{"description":"For outbound messages, the same as `delivery_summary.retryable`.","type":"boolean"},"status":{"description":"Older delivery status word, such as `pending`, `dispatched`, `partial_delivered`, `delivery_failed`, `delivered`, or `received` for a reply. Prefer `delivery_summary`.","type":["string","null"]},"status_id":{"description":"Your team's message status (for example \"Needs reply\"), set with the status operation. Null when none is set.","type":["string","null"]},"system":{"description":"True for messages YoPrint sent automatically.","type":"boolean"},"type":{"description":"`outbound`: sent by your team. `inbound`: a reply received.","enum":["outbound","inbound"],"type":"string"},"user":{"description":"The team member who wrote it, when `user_id` is set.","properties":{"avatar_url":{"type":["string","null"]},"email":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"timezone":{"type":["string","null"]}},"type":["object","null"]},"user_id":{"type":["string","null"]}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a message","tags":["Messages"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team admin for permission to message that order.","status":403,"when":"The message is on a sales order or quote you can't message (`user_is_not_authorized`)."},{"fix":"Use an `id` from the message list.","status":404,"when":"No message of this team has this id, or it is an internal notification."}],"group":"Messages and activity","permission":"Any member can read purchase order messages. For sales order and quote messages you need permission to message all orders, or only the orders you created or are assigned to. The team owner sees everything.","related":["v2_public_messages_recipients_index","v2_public_messages_retry","v2_public_messages_status"]}}},"/v2/api/store/{team_slug}/messages/{hash_id}/recipients":{"get":{"description":"Lists everyone a message was sent to, with how delivery went for each: the address or number it went to at the time, the channel (`email` or `sms`), the status, and the provider's error when it failed. All of them, not paged.","operationId":"v2_public_messages_recipients_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message's `id`, from the message list. A hash id; unique keys and document numbers are refused with 404.","example":"u7HKhdhT6tkEUy","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"callback_error_code":"HardBounce","callback_error_message":"The mailbox does not exist.","channel":"email","delivery_state":"failed","destination":"jordan@example.com","destination_name":"Jordan Lee","id":"XWwTVKIZSuUOcX","latest_error_reason":"The server was unable to deliver your message (ex: unknown user, mailbox not found).","participant":{"can_receive_mail":true,"can_receive_sms":false,"contact":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"63KcENAAsKuipY","default_receive_sms":false,"email":"jordan@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Jordan","id":"uTCR3hxPDePBUK","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"contact_id":"uTCR3hxPDePBUK","delivery_channel":null,"delivery_created_at":null,"delivery_destination":null,"delivery_destination_name":null,"delivery_id":null,"delivery_latest_error_reason":null,"delivery_message_id":null,"delivery_participant_id":null,"delivery_state":null,"delivery_status":null,"delivery_updated_at":null,"email":"jordan@example.com","id":"vKNPqQz8fsYDuT","name":"Jordan Lee","order_id":"V4keXwwxMQyXw7","phone":"+1 201 555 0123","purchase_order_id":null,"status":"all","trashed":false,"type":"contact"},"recipient_email":"jordan@example.com","recipient_phone":null,"status":"delivery_failed","version":2}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"callback_error_code":{"description":"The provider's error code, when delivery failed: for emails the bounce type, such as `HardBounce`; for texts Twilio's error code.","type":["string","null"]},"callback_error_message":{"description":"The provider's details.","type":["string","null"]},"channel":{"enum":["email","sms",null],"type":["string","null"]},"delivery_state":{"description":"From the provider's report. Null for older messages.","enum":["pending","sending","sent","delivered","failed","unknown",null],"type":["string","null"]},"destination":{"description":"Where it was sent: the email address or phone number at sending time.","type":["string","null"]},"destination_name":{"type":["string","null"]},"id":{"description":"The recipient (delivery) id.","type":"string"},"latest_error_reason":{"description":"Why it failed, in words: the provider's description, or YoPrint's own reason, such as `missing_delivery_destination`, `mailable_serialization_failed` or `postmark_retry_mailable_unavailable` (see the retry operations).","type":["string","null"]},"participant":{"additionalProperties":true,"description":"The participant it went to. Its `delivery_*` fields are null; read them from this recipient.","properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact":{"additionalProperties":true,"description":"The contact, for `type` `contact`: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"delivery_channel":{"enum":["email","sms",null],"type":["string","null"]},"delivery_created_at":{"format":"date-time","type":["string","null"]},"delivery_destination":{"description":"The email address or phone number it went to.","type":["string","null"]},"delivery_destination_name":{"type":["string","null"]},"delivery_id":{"description":"The recipient id: the id the recipient operations take. Null on `participant`.","type":["string","null"]},"delivery_latest_error_reason":{"type":["string","null"]},"delivery_message_id":{"type":["string","null"]},"delivery_participant_id":{"type":["string","null"]},"delivery_state":{"description":"From the provider's report. Null for older messages and on `participant`.","enum":["pending","sending","sent","delivered","failed","unknown",null],"type":["string","null"]},"delivery_status":{"enum":["pending","dispatched","dispatch_failed","delivered","delivery_failed",null],"type":["string","null"]},"delivery_updated_at":{"format":"date-time","type":["string","null"]},"email":{"type":["string","null"]},"id":{"description":"The participant id. The recipient operations take `delivery_id`, not this.","type":"string"},"name":{"type":["string","null"]},"order_id":{"type":["string","null"]},"phone":{"type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"status":{"description":"What they receive: `message`, `notification`, `all` or `disabled`.","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"`user`: a team member. `contact`: one of the customer's or vendor's contacts. `guest`: just a name and email.","enum":["user","contact","guest"],"type":"string"}},"type":["object","null"]},"recipient_email":{"description":"The address, for an email recipient.","type":["string","null"]},"recipient_phone":{"description":"The number, for a text recipient.","type":["string","null"]},"status":{"description":"`pending` also while a retry is in progress.","enum":["pending","dispatched","dispatch_failed","delivered","delivery_failed"],"type":"string"},"version":{"description":"The record's tracking format: `1`, then `2` once the email or text provider has reported on it. Not the message's version.","type":"integer"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a message's recipients","tags":["Messages"],"x-yoprint-docs":{"errors":[{"fix":"Use an `id` from the message list.","status":404,"when":"No message of this team has this id."},{"fix":"Ask a team admin for permission to message that order.","status":403,"when":"The message is on a sales order or quote you can't message (`user_is_not_authorized`)."}],"group":"Messages and activity","permission":"Any member can read purchase order messages. For sales order and quote messages you need permission to message all orders, or only the orders you created or are assigned to. The team owner sees everything.","related":["v2_public_messages_recipients_show","v2_public_messages_recipients_retry"]}}},"/v2/api/store/{team_slug}/messages/{hash_id}/recipients/{id}":{"get":{"description":"Returns one recipient's delivery: where it was sent, the channel, the status and any provider error. The id is the recipient id from the recipient list (`delivery_id` on the message's `recipients`), not the participant id.","operationId":"v2_public_messages_recipients_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message's `id`, from the message list. A hash id; unique keys and document numbers are refused with 404.","example":"u7HKhdhT6tkEUy","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}},{"description":"The recipient's `id`, from the recipient list (`delivery_id` on the message's `recipients`), not the participant id. A hash id; unique keys and document numbers are refused with 404.","example":"XWwTVKIZSuUOcX","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"callback_error_code":"HardBounce","callback_error_message":"The mailbox does not exist.","channel":"email","delivery_state":"failed","destination":"jordan@example.com","destination_name":"Jordan Lee","id":"XWwTVKIZSuUOcX","latest_error_reason":"The server was unable to deliver your message (ex: unknown user, mailbox not found).","participant":{"can_receive_mail":true,"can_receive_sms":false,"contact":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"63KcENAAsKuipY","default_receive_sms":false,"email":"jordan@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Jordan","id":"uTCR3hxPDePBUK","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"contact_id":"uTCR3hxPDePBUK","delivery_channel":null,"delivery_created_at":null,"delivery_destination":null,"delivery_destination_name":null,"delivery_id":null,"delivery_latest_error_reason":null,"delivery_message_id":null,"delivery_participant_id":null,"delivery_state":null,"delivery_status":null,"delivery_updated_at":null,"email":"jordan@example.com","id":"vKNPqQz8fsYDuT","name":"Jordan Lee","order_id":"V4keXwwxMQyXw7","phone":"+1 201 555 0123","purchase_order_id":null,"status":"all","trashed":false,"type":"contact"},"recipient_email":"jordan@example.com","recipient_phone":null,"status":"delivery_failed","version":2},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"callback_error_code":{"description":"The provider's error code, when delivery failed: for emails the bounce type, such as `HardBounce`; for texts Twilio's error code.","type":["string","null"]},"callback_error_message":{"description":"The provider's details.","type":["string","null"]},"channel":{"enum":["email","sms",null],"type":["string","null"]},"delivery_state":{"description":"From the provider's report. Null for older messages.","enum":["pending","sending","sent","delivered","failed","unknown",null],"type":["string","null"]},"destination":{"description":"Where it was sent: the email address or phone number at sending time.","type":["string","null"]},"destination_name":{"type":["string","null"]},"id":{"description":"The recipient (delivery) id.","type":"string"},"latest_error_reason":{"description":"Why it failed, in words: the provider's description, or YoPrint's own reason, such as `missing_delivery_destination`, `mailable_serialization_failed` or `postmark_retry_mailable_unavailable` (see the retry operations).","type":["string","null"]},"participant":{"additionalProperties":true,"description":"The participant it went to. Its `delivery_*` fields are null; read them from this recipient.","properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact":{"additionalProperties":true,"description":"The contact, for `type` `contact`: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"delivery_channel":{"enum":["email","sms",null],"type":["string","null"]},"delivery_created_at":{"format":"date-time","type":["string","null"]},"delivery_destination":{"description":"The email address or phone number it went to.","type":["string","null"]},"delivery_destination_name":{"type":["string","null"]},"delivery_id":{"description":"The recipient id: the id the recipient operations take. Null on `participant`.","type":["string","null"]},"delivery_latest_error_reason":{"type":["string","null"]},"delivery_message_id":{"type":["string","null"]},"delivery_participant_id":{"type":["string","null"]},"delivery_state":{"description":"From the provider's report. Null for older messages and on `participant`.","enum":["pending","sending","sent","delivered","failed","unknown",null],"type":["string","null"]},"delivery_status":{"enum":["pending","dispatched","dispatch_failed","delivered","delivery_failed",null],"type":["string","null"]},"delivery_updated_at":{"format":"date-time","type":["string","null"]},"email":{"type":["string","null"]},"id":{"description":"The participant id. The recipient operations take `delivery_id`, not this.","type":"string"},"name":{"type":["string","null"]},"order_id":{"type":["string","null"]},"phone":{"type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"status":{"description":"What they receive: `message`, `notification`, `all` or `disabled`.","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"`user`: a team member. `contact`: one of the customer's or vendor's contacts. `guest`: just a name and email.","enum":["user","contact","guest"],"type":"string"}},"type":["object","null"]},"recipient_email":{"description":"The address, for an email recipient.","type":["string","null"]},"recipient_phone":{"description":"The number, for a text recipient.","type":["string","null"]},"status":{"description":"`pending` also while a retry is in progress.","enum":["pending","dispatched","dispatch_failed","delivered","delivery_failed"],"type":"string"},"version":{"description":"The record's tracking format: `1`, then `2` once the email or text provider has reported on it. Not the message's version.","type":"integer"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get one recipient of a message","tags":["Messages"],"x-yoprint-docs":{"errors":[{"fix":"Use a recipient `id` from the recipient list.","status":404,"when":"The message, or this recipient on it, does not exist."},{"fix":"Ask a team admin for permission to message that order.","status":403,"when":"The message is on a sales order or quote you can't message (`user_is_not_authorized`)."}],"group":"Messages and activity","permission":"Any member can read purchase order messages. For sales order and quote messages you need permission to message all orders, or only the orders you created or are assigned to. The team owner sees everything.","related":["v2_public_messages_recipients_index"]}}},"/v2/api/store/{team_slug}/messages/{hash_id}/recipients/{id}/retry":{"put":{"description":"Sends the message again to one recipient whose delivery failed. The resend is queued: the response is empty, and the recipient's status updates as delivery happens.","operationId":"v2_public_messages_recipients_retry","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message's `id`, from the message list. A hash id; unique keys and document numbers are refused with 404.","example":"u7HKhdhT6tkEUy","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}},{"description":"The recipient's `id`, from the recipient list, not the participant id. A hash id; unique keys and document numbers are refused with 404.","example":"XWwTVKIZSuUOcX","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{},"schema":{"properties":{"external_integration_id":{"description":"Optional. A texting integration id of your team. It does not change which account sends today: texts go through the message's own or your team's active Twilio integration.","type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Retry delivery to one recipient","tags":["Messages"],"x-yoprint-docs":{"errors":[{"fix":"Leave it out.","status":422,"when":"`external_integration_id` is not a valid id (`validation_failed`; `error.fields` names the field). Checked first."},{"fix":"Send a new message instead.","status":422,"when":"This recipient can't be retried: it did not fail, a retry is in progress, the email is past the 7 days, or YoPrint no longer keeps the original (`message_not_retryable`, \"Message is not retryable\")."},{"fix":"Connect Twilio again in the web app, then retry.","status":500,"when":"It is a text message and your team has no active Twilio integration: a server error, not a 422. Nothing is queued."},{"fix":"Use a recipient `id` from the recipient list.","status":404,"when":"The message or the recipient does not exist on this team, or `external_integration_id` matches no integration of your team."},{"fix":"Ask a team admin for permission to message that order.","status":403,"when":"The message is on a sales order or quote you can't message (`user_is_not_authorized`)."}],"group":"Messages and activity","notes":["A `200` means the resend was queued, not that it was delivered. Read the recipient again to see the outcome.","If YoPrint can no longer read its stored copy of the message, the call still answers `200`, but nothing is sent and the recipients stay failed. Instead, `latest_error_reason` changes on every failed recipient (on the one-recipient retry, on that recipient only): to `postmark_retry_mailable_unavailable` for an email sent through YoPrint's tracked email delivery (a message of version 3 or with a dispatch id, or, on the one-recipient retry, a recipient with a tracked send attempt), otherwise to `mailable_serialization_failed`, for example for older emails and for texts. Read the recipients after a retry."],"permission":"Any member can read purchase order messages. For sales order and quote messages you need permission to message all orders, or only the orders you created or are assigned to. The team owner sees everything.","related":["v2_public_messages_retry","v2_public_messages_recipients_show"],"rules":["The recipient's delivery must have failed (`dispatch_failed` or `delivery_failed`). While a retry is in progress its status is `pending`, and a second retry is refused.","Emails can be retried only while YoPrint still keeps the original send, normally 7 days. A text needs the phone number it was sent to.","It works on a recipient of a message that otherwise can't be retried as a whole."],"side_effects":["Sends the email, or the text through your team's Twilio account, to the same address or number as before.","When an email sent through YoPrint's tracked email delivery fails again, the creator of the order or purchase order gets another delivery failure email."]}}},"/v2/api/store/{team_slug}/messages/{hash_id}/retry":{"put":{"description":"Sends an outbound message again to the recipients it **failed** to reach. Recipients who already got it are not sent it again. The resend is queued: the response is empty, and each recipient's status updates as delivery happens.\n\nCheck `delivery_summary.retryable` (or `retryable`) first. To retry one recipient only, use the recipient retry operation.","operationId":"v2_public_messages_retry","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message's `id`, from the message list. A hash id; unique keys and document numbers are refused with 404.","example":"u7HKhdhT6tkEUy","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{},"schema":{"properties":{"external_integration_id":{"description":"Optional. A texting integration id of your team. It does not change which account sends today: texts go through the message's own or your team's active Twilio integration.","type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Retry a message's failed deliveries","tags":["Messages"],"x-yoprint-docs":{"errors":[{"fix":"Leave it out.","status":422,"when":"`external_integration_id` is not a valid id (`validation_failed`; `error.fields` names the field). Checked first."},{"fix":"Retry single recipients, or send a new message.","status":422,"when":"The message can't be retried: it is inbound, nothing failed, a failed email is past the 7 days, YoPrint no longer keeps the original, or a failed recipient can't be retried (`message_not_retryable`, \"Message is not retryable\"). Same answer as `delivery_summary.retryable` `false`."},{"fix":"Connect Twilio again in the web app, then retry.","status":500,"when":"It is a text message and your team has no active Twilio integration: a server error, not a 422. Nothing is queued."},{"fix":"Use ids from the API.","status":404,"when":"No message of this team has this id, or `external_integration_id` matches no integration of your team."},{"fix":"Ask a team admin for permission to message that order.","status":403,"when":"The message is on a sales order or quote you can't message (`user_is_not_authorized`)."}],"group":"Messages and activity","notes":["A `200` means the resend was queued, not that it was delivered. Read the message or its recipients again to see the outcome.","If YoPrint can no longer read its stored copy of the message, the call still answers `200`, but nothing is sent and the recipients stay failed. Instead, `latest_error_reason` changes on every failed recipient (on the one-recipient retry, on that recipient only): to `postmark_retry_mailable_unavailable` for an email sent through YoPrint's tracked email delivery (a message of version 3 or with a dispatch id, or, on the one-recipient retry, a recipient with a tracked send attempt), otherwise to `mailable_serialization_failed`, for example for older emails and for texts. Read the recipients after a retry."],"permission":"Any member can read purchase order messages. For sales order and quote messages you need permission to message all orders, or only the orders you created or are assigned to. The team owner sees everything.","related":["v2_public_messages_recipients_retry","v2_public_messages_show"],"rules":["Only outbound messages whose delivery failed or partly failed can be retried.","Emails can be retried only while YoPrint still keeps the original send, normally 7 days.","On texts, and on emails sent by YoPrint's current email sending, every failed recipient must still be retryable: if one is not (for example its email is past the 7 days), the whole call answers 422. Retry the others one at a time with the recipient retry operation.","Each recipient is sent to the same address or number as the first time, even if the contact changed since."],"side_effects":["Sends the email again (through YoPrint's email provider) or the text again, through your team's Twilio account, which Twilio charges you for.","When an email sent through YoPrint's tracked email delivery fails again, the creator of the order or purchase order gets another delivery failure email.","People with the message open see the delivery status update live."]}}},"/v2/api/store/{team_slug}/messages/{hash_id}/status":{"put":{"description":"Sets your team's own status on a message, such as \"Need to Respond\" or \"Completed\", for sorting your inbox. It does not change delivery and does not notify the customer.\n\nUse a status id from your team's message statuses (`GET /v1/api/store/{team_slug}/setting/status/customer_message`). Returns the message with `previous_status_id` and `previous_message_status`.","operationId":"v2_public_messages_status","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message's `id`, from the message list. A hash id; unique keys and document numbers are refused with 404.","example":"u7HKhdhT6tkEUy","in":"path","name":"hash_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"status_id":"aEVC1y7DeLogrF"},"schema":{"properties":{"notify_customer":{"description":"Accepted but ignored: no notification is sent.","type":"boolean"},"status_id":{"description":"One of your team's message status ids.","type":"string"}},"required":["status_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"actor_name":"Alex Rivera","actor_type":"user","attachments":[],"contact":null,"contact_id":null,"created_at":"2026-11-03T09:30:00+00:00","delivery_summary":{"accepted":0,"complete":true,"delivered":0,"failed":1,"reason":null,"retryable":true,"skipped":0,"state":"failed","submitting":0,"total":1,"unknown":0,"waiting":0},"display_type":"default_v2","driver":"email","email":"alex@example.com","has_message":true,"has_original_message":true,"id":"u7HKhdhT6tkEUy","message":"<p>Your order is ready for pickup.</p>","message_participant_id":null,"message_status":{"color":"#c6ff00","customer_label":"In Progress","id":"aEVC1y7DeLogrF","label":"Need to Respond","position":1,"role":"customer_message","trashed":false,"type":"in_progress"},"name":"Alex Rivera","order_id":"V4keXwwxMQyXw7","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","original_message":"<html><body><p>Your order is ready for pickup.</p></body></html>","participant":null,"preview_message":"Your order is ready for pickup.","previous_message_status":null,"previous_status_id":null,"purchase_order_id":null,"purchase_scoped_id":null,"recipients":[{"can_receive_mail":true,"can_receive_sms":false,"contact":{"created_at":"2026-11-01T09:00:00+00:00","customer_id":"63KcENAAsKuipY","default_receive_sms":false,"email":"jordan@example.com","external_type":null,"fax":null,"fax_country":null,"first_name":"Jordan","id":"uTCR3hxPDePBUK","is_external":false,"is_primary":true,"last_name":"Lee","phone":"+1 201 555 0123","phone_country":"US","send_invoice":true,"trashed":false,"updated_at":"2026-11-01T09:00:00+00:00"},"contact_id":"uTCR3hxPDePBUK","delivery_channel":"email","delivery_created_at":"2026-11-03T09:30:00+00:00","delivery_destination":"jordan@example.com","delivery_destination_name":"Jordan Lee","delivery_id":"XWwTVKIZSuUOcX","delivery_latest_error_reason":"The server was unable to deliver your message (ex: unknown user, mailbox not found).","delivery_message_id":"u7HKhdhT6tkEUy","delivery_participant_id":"vKNPqQz8fsYDuT","delivery_state":"failed","delivery_status":"delivery_failed","delivery_updated_at":"2026-11-03T09:31:00+00:00","email":"jordan@example.com","id":"vKNPqQz8fsYDuT","name":"Jordan Lee","order_id":"V4keXwwxMQyXw7","phone":"+1 201 555 0123","purchase_order_id":null,"status":"all","trashed":false,"type":"contact"}],"rendered_attachments":[],"retryable":true,"status":"delivery_failed","status_id":"aEVC1y7DeLogrF","system":false,"type":"outbound","user":{"avatar_url":"https://example.com/avatar.png","email":"alex@example.com","id":"VG7s3tFzyQbO2N","name":"Alex Rivera","timezone":"America/New_York"},"user_id":"VG7s3tFzyQbO2N"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"actor_name":{"description":"The writer's name, by `actor_type`: your team's name for `system`, the team member, the contact, the order's customer, the purchase order's vendor, the participant, or the name a `guest` gave. Null when YoPrint can't find the writer's record.","type":["string","null"]},"actor_type":{"description":"Who wrote it: `user`, `customer`, `vendor`, `contact` (written in the customer or vendor portal), `participant`, `guest` (someone who is not a contact) or `system`.","type":"string"},"attachments":{"description":"Files attached to it, in the same shape as an upload (`id`, `name`, `file_name`, `mime_type`, `size`, `url`).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"contact":{"additionalProperties":true,"description":"The contact who wrote it, when `contact_id` is set: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"delivery_summary":{"description":"Outbound messages: how delivery went across all recipients. Null for inbound messages.","properties":{"accepted":{"type":"integer"},"complete":{"type":"boolean"},"delivered":{"type":"integer"},"failed":{"type":"integer"},"reason":{"description":"Why the state is not final, or why nothing was sent, for example `no_recipients` or `delivery_evidence_unavailable`. Usually null.","type":["string","null"]},"retryable":{"description":"True when the retry operation accepts this message. When false, it answers 422.","type":"boolean"},"skipped":{"type":"integer"},"state":{"description":"`sent`: the provider took it, delivery not confirmed yet. `partial`: recipients are in different states. `not_sent`: there were no recipients.","enum":["pending","sending","sent","delivered","failed","partial","unknown","not_sent"],"type":"string"},"submitting":{"type":"integer"},"total":{"type":"integer"},"unknown":{"type":"integer"},"waiting":{"type":"integer"}},"type":["object","null"]},"display_type":{"description":"How the web app draws it, for example `default_v2`, or `system_v2` for automatic messages.","type":"string"},"driver":{"description":"`email`, `sms`, or `web` for a message written in YoPrint.","type":["string","null"]},"email":{"description":"The sender's email address.","type":["string","null"]},"has_message":{"type":"boolean"},"has_original_message":{"type":"boolean"},"id":{"type":"string"},"message":{"description":"The message as it was written, without the email layout.","type":["string","null"]},"message_participant_id":{"description":"The author, as a message participant.","type":["string","null"]},"message_status":{"additionalProperties":true,"description":"The status named by `status_id`: `id`, `role` (`customer_message`), `type`, `label`, `customer_label`, `color`, `position`, `trashed`.","type":["object","null"]},"name":{"description":"The sender's name.","type":["string","null"]},"order_id":{"description":"The sales order or quote it is on.","type":["string","null"]},"order_object_type":{"description":"`sales_order` or `quote`. Null without an order.","type":["string","null"]},"order_quote":{"type":["boolean","null"]},"order_scoped_id":{"description":"The order's number, such as `SO1001`. An empty string `\"\"` (not null) without an order.","type":["string","null"]},"original_message":{"description":"The whole message as HTML: for a reply, the email as it arrived, with any quoted text; for a message you sent, the full message YoPrint rendered.","type":["string","null"]},"participant":{"additionalProperties":true,"description":"The author, as a message participant, when `message_participant_id` is set. Its `delivery_*` fields are null.","properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact":{"additionalProperties":true,"description":"The contact, for `type` `contact`: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"delivery_channel":{"enum":["email","sms",null],"type":["string","null"]},"delivery_created_at":{"format":"date-time","type":["string","null"]},"delivery_destination":{"description":"The email address or phone number it went to.","type":["string","null"]},"delivery_destination_name":{"type":["string","null"]},"delivery_id":{"description":"The recipient id: the id the recipient operations take. Null on `participant`.","type":["string","null"]},"delivery_latest_error_reason":{"type":["string","null"]},"delivery_message_id":{"type":["string","null"]},"delivery_participant_id":{"type":["string","null"]},"delivery_state":{"description":"From the provider's report. Null for older messages and on `participant`.","enum":["pending","sending","sent","delivered","failed","unknown",null],"type":["string","null"]},"delivery_status":{"enum":["pending","dispatched","dispatch_failed","delivered","delivery_failed",null],"type":["string","null"]},"delivery_updated_at":{"format":"date-time","type":["string","null"]},"email":{"type":["string","null"]},"id":{"description":"The participant id. The recipient operations take `delivery_id`, not this.","type":"string"},"name":{"type":["string","null"]},"order_id":{"type":["string","null"]},"phone":{"type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"status":{"description":"What they receive: `message`, `notification`, `all` or `disabled`.","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"`user`: a team member. `contact`: one of the customer's or vendor's contacts. `guest`: just a name and email.","enum":["user","contact","guest"],"type":"string"}},"type":["object","null"]},"preview_message":{"description":"A short plain-text preview.","type":["string","null"]},"previous_message_status":{"additionalProperties":true,"description":"That status, in the same shape as `message_status`: `id`, `role`, `type`, `label`, `customer_label`, `color`, `position`, `trashed`.","type":["object","null"]},"previous_status_id":{"description":"The status before this change. Null when none was set.","type":["string","null"]},"purchase_order_id":{"description":"The purchase order it is on.","type":["string","null"]},"purchase_scoped_id":{"description":"The purchase order's number. Null when it is not on a purchase order.","type":["string","null"]},"recipients":{"description":"Who it was sent to: each participant with its delivery (`delivery_status`, `delivery_channel`, `delivery_destination`). `delivery_id` is the id the recipient operations take.","items":{"additionalProperties":true,"properties":{"can_receive_mail":{"type":"boolean"},"can_receive_sms":{"type":"boolean"},"contact":{"additionalProperties":true,"description":"The contact, for `type` `contact`: `first_name`, `last_name`, `email`, `phone` and more.","type":["object","null"]},"contact_id":{"type":["string","null"]},"delivery_channel":{"enum":["email","sms",null],"type":["string","null"]},"delivery_created_at":{"format":"date-time","type":["string","null"]},"delivery_destination":{"description":"The email address or phone number it went to.","type":["string","null"]},"delivery_destination_name":{"type":["string","null"]},"delivery_id":{"description":"The recipient id: the id the recipient operations take. Null on `participant`.","type":["string","null"]},"delivery_latest_error_reason":{"type":["string","null"]},"delivery_message_id":{"type":["string","null"]},"delivery_participant_id":{"type":["string","null"]},"delivery_state":{"description":"From the provider's report. Null for older messages and on `participant`.","enum":["pending","sending","sent","delivered","failed","unknown",null],"type":["string","null"]},"delivery_status":{"enum":["pending","dispatched","dispatch_failed","delivered","delivery_failed",null],"type":["string","null"]},"delivery_updated_at":{"format":"date-time","type":["string","null"]},"email":{"type":["string","null"]},"id":{"description":"The participant id. The recipient operations take `delivery_id`, not this.","type":"string"},"name":{"type":["string","null"]},"order_id":{"type":["string","null"]},"phone":{"type":["string","null"]},"purchase_order_id":{"type":["string","null"]},"status":{"description":"What they receive: `message`, `notification`, `all` or `disabled`.","type":"string"},"trashed":{"type":"boolean"},"type":{"description":"`user`: a team member. `contact`: one of the customer's or vendor's contacts. `guest`: just a name and email.","enum":["user","contact","guest"],"type":"string"}},"type":"object"},"type":"array"},"rendered_attachments":{"description":"Everything attached when it was sent: the files (`attachment_type` `media`, upload shape) and generated documents such as the order PDF (`attachment_type` `internal_attachment`, with `name` and `url`).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"retryable":{"description":"For outbound messages, the same as `delivery_summary.retryable`.","type":"boolean"},"status":{"description":"Older delivery status word, such as `pending`, `dispatched`, `partial_delivered`, `delivery_failed`, `delivered`, or `received` for a reply. Prefer `delivery_summary`.","type":["string","null"]},"status_id":{"description":"Your team's message status (for example \"Needs reply\"), set with the status operation. Null when none is set.","type":["string","null"]},"system":{"description":"True for messages YoPrint sent automatically.","type":"boolean"},"type":{"description":"`outbound`: sent by your team. `inbound`: a reply received.","enum":["outbound","inbound"],"type":"string"},"user":{"description":"The team member who wrote it, when `user_id` is set.","properties":{"avatar_url":{"type":["string","null"]},"email":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"timezone":{"type":["string","null"]}},"type":["object","null"]},"user_id":{"type":["string","null"]}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set a message's status","tags":["Messages"],"x-yoprint-docs":{"errors":[{"fix":"Send a status id.","status":422,"when":"`status_id` is missing or not an id, or `notify_customer` is not a boolean (`validation_failed`; `error.fields` names the field)."},{"fix":"Use ids from the API.","status":404,"when":"The message or the status does not exist on this team."},{"fix":"Ask a team admin for permission to message that order.","status":403,"when":"The message is on a sales order or quote you can't message (`user_is_not_authorized`)."}],"group":"Messages and activity","permission":"Any member can read purchase order messages. For sales order and quote messages you need permission to message all orders, or only the orders you created or are assigned to. The team owner sees everything.","related":["v1_public_status_list_customer_message","v2_public_messages_filter"],"rules":["`status_id` is required and must be one of your team's statuses. Use a message status: other kinds of status are accepted too, but they are not meant for messages."],"side_effects":["Fires the `message.status_changed` webhook, every time, even if the status was already set to this value.","Records the change in the status history when the message had a different status before.","People with the inbox open see the change live."]}}},"/v2/api/store/{team_slug}/search/orders":{"get":{"description":"Finds sales orders and quotes by a word or number, for a search box or a picker. It returns at most 30 matches, with no paging, highest order number first.\n\nThe text in `q` matches anywhere inside (\"contains\") any of: the order number, the order name, the customer PO number, the customer's name, and every part of the shipping and billing addresses (label, street lines, city, state, country, postcode). Several words also match when each word is found in a different field, so `northwind 1188` finds Northwind Apparel's order with PO number `PO-1188`. Without `q`, you get the first 30 in the same order.\n\nSend the same fields as query parameters with `GET`, or as a JSON body with `POST`. **To search quotes only**, send `quote=1` in the query string (`GET .../search/orders?q=northwind&quote=1`) or `\"quote\": true` in a `POST` body; `quote=0` or `false` gives sales orders only. `quote=true` in a query string is refused with 422.\n\nEach result is the same order or quote object Get a sales order or quote returns, without `items`. Amounts come in two encodings:\n- Thousandths, an older encoding: `calc_subtotal`, `calc_tax`, `calc_total`, and `paid_amount` (`270000` is 270.00). The `calc_*` fields count only invoiced amounts, so they are `0` on an order with no invoice.\n- Decimal pairs: `order_item_cart_total` (the lines' value), `order_balance_due`, and `invoiced_total`. The amount is `value` ÷ 10^`dp` (`{\"value\": 2700000, \"dp\": 4}` is 270.00). Read `dp` every time.\n\nFor more than 30 results, or for filters, use the sales order and quote list operations.","operationId":"v2_public_search_orders_get","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"What to look for. Leave it out to list orders by order number.","example":"northwind","in":"query","name":"q","required":false,"schema":{"maxLength":255,"type":"string"}},{"description":"Another name for `q`. `q` wins when both are sent.","in":"query","name":"query","required":false,"schema":{"maxLength":255,"type":"string"}},{"description":"Only this customer's orders. A customer id.","in":"query","name":"customer_id","required":false,"schema":{"type":"string"}},{"description":"`1` for quotes only, `0` for sales orders only. Leave it out for both. In the query string `true` and `false` are refused with 422; with `POST`, a JSON `true` or `false` works.","example":1,"in":"query","name":"quote","required":false,"schema":{"enum":[0,1],"type":"integer"}},{"description":"Does not hide drafts, despite its name. Don't use it; check `internal_status` in the results instead. Like `quote`, it takes `1` or `0` in the query string.","in":"query","name":"hide_draft","required":false,"schema":{"enum":[0,1],"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"approval_status":null,"billing_address":null,"calc_subtotal":125000,"calc_tax":10000,"calc_total":135000,"created_at":"2026-11-03T09:30:00+00:00","customer":{"id":"63KcENAAsKuipY","is_external":false,"name":"Northwind Apparel","tax_exempt":false},"customer_id":"63KcENAAsKuipY","customer_po_number":"PO-1188","due_date":"2026-11-14T00:00:00+00:00","id":"V4keXwwxMQyXw7","internal_status":"published","invoiced_total":{"dp":4,"value":1350000},"is_draft":false,"is_quote":false,"is_rush":false,"issue_date":"2026-11-03T00:00:00+00:00","mode":"view","name":"Spring team shirts","object_type":"sales_order","order_balance_due":{"dp":4,"value":850000},"order_item_cart_total":{"dp":4,"value":1250000},"paid_amount":50000,"scoped_id":"SO1001","shipping_address":{"address1":"100 Example Street","city":"Springfield","country_code":"US","id":"RNG2OuYC20YzXs","label":"Head office","postcode":"62701","state_code":"IL"},"status":{"color":"#2196f3","customer_label":"In Progress","id":"52CuV8sWcDZLPm","label":"In production","position":2,"role":"order","trashed":false,"type":"in_progress"},"status_id":"52CuV8sWcDZLPm","trashed":false,"type":"order","unique_key":"ord_EXAMPLEuniqueKey"}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"At most 30 orders and quotes. Each is the same object Get a sales order or quote returns, without `items`; the main fields are listed here.","items":{"additionalProperties":true,"properties":{"approval_status":{"type":["string","null"]},"billing_address":{"additionalProperties":true,"type":["object","null"]},"calc_subtotal":{"description":"Invoiced subtotal: what has been invoiced so far, `0` until the order is invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_tax":{"description":"Invoiced tax, `0` until the order is invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_total":{"description":"Invoiced total, `0` until the order is invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). For the value of the order's lines, read `order_item_cart_total`.","type":["integer","number","string","null"]},"created_at":{"format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"The customer, with `id` and `name`.","type":["object","null"]},"customer_id":{"type":["string","null"]},"customer_po_number":{"type":["string","null"]},"due_date":{"description":"Production due date.","format":"date-time","type":["string","null"]},"id":{"description":"The order's id. Use it in the order operations.","type":"string"},"internal_status":{"description":"`draft` or `published`. Null on orders from before drafts existed.","enum":["draft","published",null],"type":["string","null"]},"invoiced_total":{"description":"Total of the order's invoices. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1350000, \"dp\": 4 }` is 135.00). Read `dp` every time: it can differ between fields and records.","properties":{"dp":{"type":"integer"},"value":{"type":["integer","string","null"]}},"type":"object"},"is_draft":{"description":"True when `mode` is `create`. Older field; prefer `internal_status`.","type":"boolean"},"is_quote":{"description":"True for a quote. Same as `object_type` `quote`.","type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"format":"date-time","type":["string","null"]},"mode":{"description":"`create`: a draft. `edit`: being edited. `view`: saved.","enum":["create","edit","view"],"type":"string"},"name":{"type":["string","null"]},"object_type":{"description":"What it is. Prefer this field.","enum":["sales_order","quote"],"type":"string"},"order_balance_due":{"description":"Invoiced total minus payments. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 850000, \"dp\": 4 }` is 85.00). Read `dp` every time: it can differ between fields and records.","properties":{"dp":{"type":"integer"},"value":{"type":["integer","string","null"]}},"type":"object"},"order_item_cart_total":{"description":"The value of the order's lines, invoiced or not. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 2500000, \"dp\": 4 }` is 250.00). Read `dp` every time: it can differ between fields and records. Stored amounts usually have 4 decimal places; an order with no amount yet can come as `{ \"value\": 0, \"dp\": 0 }`.","properties":{"dp":{"type":"integer"},"value":{"type":["integer","string","null"]}},"type":"object"},"paid_amount":{"description":"Payments received. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"scoped_id":{"description":"The order or quote number people see, such as `SO1001`. Not an id.","type":"string"},"shipping_address":{"additionalProperties":true,"type":["object","null"]},"status":{"additionalProperties":true,"description":"That status, with its `label`.","type":["object","null"]},"status_id":{"description":"The order's status id in your team's statuses.","type":["string","null"]},"trashed":{"type":"boolean"},"type":{"description":"The same thing in older words: `order` for a sales order.","enum":["order","quote"],"type":"string"},"unique_key":{"description":"The order's unique key (`ord_...`), for the operations that take one.","type":"string"}},"type":"object"},"maxItems":30,"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Search sales orders and quotes","tags":["Search"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team admin for permission to view orders.","status":403,"when":"Your role can't view orders (`unauthorized`)."},{"fix":"In the query string send `quote=1` (quotes) or `quote=0` (sales orders). In a `POST` body, JSON `true` or `false` work.","status":422,"when":"`q` is longer than 255 characters, `customer_id` is not a valid id, or `quote` or `hide_draft` is not a boolean. In a `GET` query string, `quote=true` is refused this way (`validation_failed`; `error.fields` names the field)."}],"group":"Sales","notes":["Results have no relevance ranking: every match counts the same, sorted by order number as text, highest first. Past 9,999 orders that text order is uneven (`SO9999` comes before `SO010000`). Narrow the text if what you want is not in the first 30.","Draft orders are included. Deleted orders are not.","Quotes are searched with your order permissions.","The whole text is matched as one phrase, and the first 5 different words are also matched one by one; words after the fifth are not.","`hide_draft` does not hide drafts. It compares the order's status with one fixed status record that belongs to at most one team, so for almost every team it changes nothing. To leave drafts out, skip results whose `internal_status` is `draft` (or `mode` is `create`).","Search results, Get order and the order lists share field names: `object_type` (`sales_order` or `quote`) is the same fact as `type` (`order` or `quote`) and `is_quote`."],"permission":"Needs permission to view orders. With \"view all orders\" you search every order; with \"view own orders\" only the orders you created or are assigned to.","rules":["`q` and `query` are at most 255 characters.","`customer_id` must be a customer id of this team.","Searching is \"contains\" and ignores case. `%` and `_` are matched as plain characters."]}},"post":{"description":"Finds sales orders and quotes by a word or number, for a search box or a picker. It returns at most 30 matches, with no paging, highest order number first.\n\nThe text in `q` matches anywhere inside (\"contains\") any of: the order number, the order name, the customer PO number, the customer's name, and every part of the shipping and billing addresses (label, street lines, city, state, country, postcode). Several words also match when each word is found in a different field, so `northwind 1188` finds Northwind Apparel's order with PO number `PO-1188`. Without `q`, you get the first 30 in the same order.\n\nSend the same fields as query parameters with `GET`, or as a JSON body with `POST`. **To search quotes only**, send `quote=1` in the query string (`GET .../search/orders?q=northwind&quote=1`) or `\"quote\": true` in a `POST` body; `quote=0` or `false` gives sales orders only. `quote=true` in a query string is refused with 422.\n\nEach result is the same order or quote object Get a sales order or quote returns, without `items`. Amounts come in two encodings:\n- Thousandths, an older encoding: `calc_subtotal`, `calc_tax`, `calc_total`, and `paid_amount` (`270000` is 270.00). The `calc_*` fields count only invoiced amounts, so they are `0` on an order with no invoice.\n- Decimal pairs: `order_item_cart_total` (the lines' value), `order_balance_due`, and `invoiced_total`. The amount is `value` ÷ 10^`dp` (`{\"value\": 2700000, \"dp\": 4}` is 270.00). Read `dp` every time.\n\nFor more than 30 results, or for filters, use the sales order and quote list operations.","operationId":"v2_public_search_orders_post","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"q":"northwind","quote":false},"schema":{"properties":{"customer_id":{"description":"Only this customer's orders. A customer id.","type":["string","null"]},"hide_draft":{"description":"Does not hide drafts, despite its name. Don't use it; check `internal_status` in the results instead.","type":["boolean","null"]},"q":{"description":"What to look for. Leave it out to list orders by order number.","maxLength":255,"type":["string","null"]},"query":{"description":"Another name for `q`. `q` wins when both are sent.","maxLength":255,"type":["string","null"]},"quote":{"description":"`true` (or `1`) for quotes only, `false` (or `0`) for sales orders only. Leave it out for both.","enum":[true,false,1,0,null],"type":["boolean","integer","null"]}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"approval_status":null,"billing_address":null,"calc_subtotal":125000,"calc_tax":10000,"calc_total":135000,"created_at":"2026-11-03T09:30:00+00:00","customer":{"id":"63KcENAAsKuipY","is_external":false,"name":"Northwind Apparel","tax_exempt":false},"customer_id":"63KcENAAsKuipY","customer_po_number":"PO-1188","due_date":"2026-11-14T00:00:00+00:00","id":"V4keXwwxMQyXw7","internal_status":"published","invoiced_total":{"dp":4,"value":1350000},"is_draft":false,"is_quote":false,"is_rush":false,"issue_date":"2026-11-03T00:00:00+00:00","mode":"view","name":"Spring team shirts","object_type":"sales_order","order_balance_due":{"dp":4,"value":850000},"order_item_cart_total":{"dp":4,"value":1250000},"paid_amount":50000,"scoped_id":"SO1001","shipping_address":{"address1":"100 Example Street","city":"Springfield","country_code":"US","id":"RNG2OuYC20YzXs","label":"Head office","postcode":"62701","state_code":"IL"},"status":{"color":"#2196f3","customer_label":"In Progress","id":"52CuV8sWcDZLPm","label":"In production","position":2,"role":"order","trashed":false,"type":"in_progress"},"status_id":"52CuV8sWcDZLPm","trashed":false,"type":"order","unique_key":"ord_EXAMPLEuniqueKey"}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"At most 30 orders and quotes. Each is the same object Get a sales order or quote returns, without `items`; the main fields are listed here.","items":{"additionalProperties":true,"properties":{"approval_status":{"type":["string","null"]},"billing_address":{"additionalProperties":true,"type":["object","null"]},"calc_subtotal":{"description":"Invoiced subtotal: what has been invoiced so far, `0` until the order is invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_tax":{"description":"Invoiced tax, `0` until the order is invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_total":{"description":"Invoiced total, `0` until the order is invoiced. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). For the value of the order's lines, read `order_item_cart_total`.","type":["integer","number","string","null"]},"created_at":{"format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"The customer, with `id` and `name`.","type":["object","null"]},"customer_id":{"type":["string","null"]},"customer_po_number":{"type":["string","null"]},"due_date":{"description":"Production due date.","format":"date-time","type":["string","null"]},"id":{"description":"The order's id. Use it in the order operations.","type":"string"},"internal_status":{"description":"`draft` or `published`. Null on orders from before drafts existed.","enum":["draft","published",null],"type":["string","null"]},"invoiced_total":{"description":"Total of the order's invoices. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1350000, \"dp\": 4 }` is 135.00). Read `dp` every time: it can differ between fields and records.","properties":{"dp":{"type":"integer"},"value":{"type":["integer","string","null"]}},"type":"object"},"is_draft":{"description":"True when `mode` is `create`. Older field; prefer `internal_status`.","type":"boolean"},"is_quote":{"description":"True for a quote. Same as `object_type` `quote`.","type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"format":"date-time","type":["string","null"]},"mode":{"description":"`create`: a draft. `edit`: being edited. `view`: saved.","enum":["create","edit","view"],"type":"string"},"name":{"type":["string","null"]},"object_type":{"description":"What it is. Prefer this field.","enum":["sales_order","quote"],"type":"string"},"order_balance_due":{"description":"Invoiced total minus payments. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 850000, \"dp\": 4 }` is 85.00). Read `dp` every time: it can differ between fields and records.","properties":{"dp":{"type":"integer"},"value":{"type":["integer","string","null"]}},"type":"object"},"order_item_cart_total":{"description":"The value of the order's lines, invoiced or not. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 2500000, \"dp\": 4 }` is 250.00). Read `dp` every time: it can differ between fields and records. Stored amounts usually have 4 decimal places; an order with no amount yet can come as `{ \"value\": 0, \"dp\": 0 }`.","properties":{"dp":{"type":"integer"},"value":{"type":["integer","string","null"]}},"type":"object"},"paid_amount":{"description":"Payments received. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"scoped_id":{"description":"The order or quote number people see, such as `SO1001`. Not an id.","type":"string"},"shipping_address":{"additionalProperties":true,"type":["object","null"]},"status":{"additionalProperties":true,"description":"That status, with its `label`.","type":["object","null"]},"status_id":{"description":"The order's status id in your team's statuses.","type":["string","null"]},"trashed":{"type":"boolean"},"type":{"description":"The same thing in older words: `order` for a sales order.","enum":["order","quote"],"type":"string"},"unique_key":{"description":"The order's unique key (`ord_...`), for the operations that take one.","type":"string"}},"type":"object"},"maxItems":30,"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Search sales orders and quotes","tags":["Search"],"x-yoprint-docs":{"errors":[{"fix":"Ask a team admin for permission to view orders.","status":403,"when":"Your role can't view orders (`unauthorized`)."},{"fix":"In the query string send `quote=1` (quotes) or `quote=0` (sales orders). In a `POST` body, JSON `true` or `false` work.","status":422,"when":"`q` is longer than 255 characters, `customer_id` is not a valid id, or `quote` or `hide_draft` is not a boolean. In a `GET` query string, `quote=true` is refused this way (`validation_failed`; `error.fields` names the field)."}],"group":"Sales","notes":["Results have no relevance ranking: every match counts the same, sorted by order number as text, highest first. Past 9,999 orders that text order is uneven (`SO9999` comes before `SO010000`). Narrow the text if what you want is not in the first 30.","Draft orders are included. Deleted orders are not.","Quotes are searched with your order permissions.","The whole text is matched as one phrase, and the first 5 different words are also matched one by one; words after the fifth are not.","`hide_draft` does not hide drafts. It compares the order's status with one fixed status record that belongs to at most one team, so for almost every team it changes nothing. To leave drafts out, skip results whose `internal_status` is `draft` (or `mode` is `create`).","Search results, Get order and the order lists share field names: `object_type` (`sales_order` or `quote`) is the same fact as `type` (`order` or `quote`) and `is_quote`."],"permission":"Needs permission to view orders. With \"view all orders\" you search every order; with \"view own orders\" only the orders you created or are assigned to.","rules":["`q` and `query` are at most 255 characters.","`customer_id` must be a customer id of this team.","Searching is \"contains\" and ignores case. `%` and `_` are matched as plain characters."]}}},"/v2/api/store/{team_slug}/setting/message_template":{"get":{"description":"Returns all of the team's message templates: the system ones (the emails YoPrint sends for new sales orders, quotes and purchase orders) and the ones your team saved, with their raw subject and body, placeholders and attachments.\n\nPeople pick saved templates when they message a customer or vendor from a sales order, quote or purchase order; system templates are used for the document emails.\n\n| `type` | What it is | Placeholders |\n| --- | --- | --- |\n| `new_sales_order_message` | System: the \"New Sales Order Detail\" email | sales order |\n| `new_quote_message` | System: the \"New Quote Detail\" email | quote |\n| `purchase_order` | System: the \"New Purchase Order Detail\" email to a vendor | purchase order |\n| `sales_order_message` | Your saved email for a sales order | sales order |\n| `sales_order_text_message` | Your saved text message for a sales order | sales order |\n| `quote_message` | Your saved email for a quote | quote |\n| `quote_text_message` | Your saved text message for a quote | quote |\n| `purchase_order_message` | Your saved email to a vendor about a purchase order | purchase order |\n| `purchase_order_text_message` | Your saved text message to a vendor | purchase order |\n","operationId":"v2_public_message_template_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"body":"<p>Your order #{{order_number}} is ready for pickup at 100 Example Street.</p>","can_create":true,"can_delete":true,"can_update":true,"created_at":"2026-10-01T09:00:00+00:00","id":"DVubREua5aJkwh","internal_attachments":[],"name":"Ready for pickup","subject":null,"support_attachments":true,"support_subject":false,"supported_attachments":["media","reference_media","order","order_compact","so_jobs_with_mockup","so_jobs_without_mockup","so_invoices","so_compact_invoices"],"supported_placeholder":[{"label":"Order Number","value":"order_number"},{"label":"Customer Name","value":"customer_name"}],"system":false,"type":"sales_order_message","updated_at":"2026-10-01T09:00:00+00:00"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"properties":{"body":{"description":"Liquid: HTML for emails, plain text for text messages.","type":"string"},"can_create":{"type":"boolean"},"can_delete":{"type":"boolean"},"can_update":{"type":"boolean"},"created_at":{"format":"date-time","type":"string"},"id":{"example":"DVubREua5aJkwh","type":"string"},"internal_attachments":{"description":"Its attachments, as the attachment operations return them.","items":{"additionalProperties":false,"properties":{"created_at":{"format":"date-time","type":"string"},"detail":{"description":"For a document attachment, defaults to its kind, such as `Sales Order/Quote (PDF)`.","type":["string","null"]},"id":{"example":"80qLp4P9l2ftvL","type":"string"},"media":{"additionalProperties":true,"description":"For a `media` or `reference_media` attachment, the file: `id`, `name`, `file_name`, `mime_type`, `size`, a download `url`, a signed `view_url` and more. Null for document attachments.","type":["object","null"]},"media_id":{"type":["string","null"]},"name":{"type":["string","null"]},"options":{"description":"The attachment's options as a JSON-encoded string, not an object: `\"[]\"`, or for job sheets `\"{\\\"show_mockup\\\":true}\"`. `\"null\"` for a `media` or `reference_media` file. Decode it before use.","type":["string","null"]},"order_id":{"type":["string","null"]},"order_scoped_id":{"type":["string","integer","null"]},"purchase_order_id":{"type":["string","null"]},"purchase_order_scoped_id":{"type":["string","integer","null"]},"type":{"example":"order","type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","order_id","order_scoped_id","purchase_order_id","purchase_order_scoped_id","name","detail","media_id","options","created_at","updated_at","media"],"type":"object"},"type":"array"},"name":{"example":"Ready for pickup","type":"string"},"subject":{"description":"Liquid, as saved; null when none was saved. Only the three system types use a subject (`support_subject: true`).","type":["string","null"]},"support_attachments":{"description":"True for every type, text messages included.","type":"boolean"},"support_subject":{"description":"True for the three system types only. The six saved types have no subject line of their own.","type":"boolean"},"supported_attachments":{"description":"The attachment `type` values this template can carry.","items":{"type":"string"},"type":"array"},"supported_placeholder":{"items":{"additionalProperties":false,"properties":{"label":{"example":"Order Number","type":"string"},"value":{"description":"Write it in the template as `{{value}}`.","example":"order_number","type":"string"}},"required":["label","value"],"type":"object"},"type":"array"},"system":{"description":"A system template: YoPrint's own email for new documents. It can be edited but not created or deleted.","type":"boolean"},"type":{"enum":["new_sales_order_message","new_quote_message","purchase_order","sales_order_message","sales_order_text_message","quote_message","quote_text_message","purchase_order_message","purchase_order_text_message"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","name","subject","body","system","support_subject","support_attachments","supported_placeholder","supported_attachments","can_create","can_update","can_delete","created_at","updated_at","internal_attachments"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List message templates","tags":["Message templates"],"x-yoprint-docs":{"group":"Team settings","permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v2_public_message_template_show","v2_public_message_template_store","v2_public_message_template_send"]}},"post":{"description":"Saves a new email or text message template for sales orders, quotes or purchase orders. You can add its attachments in the same request.\n\nOnly the six saved types can be created: `sales_order_message`, `sales_order_text_message`, `quote_message`, `quote_text_message`, `purchase_order_message` and `purchase_order_text_message`. The system types are set up with each new team; edit them instead.\n\n**Placeholders.** `subject` and `body` are Liquid: write `{{order_number}}` and YoPrint fills it in from the record when the message is made.\n\n- Sales orders and quotes: `order_number` (`quote_number` on quote templates), `order_label`, `order_link`, `issue_date`, `cust_due_date`, `client_note`, `total`, `download_url`, `creator.name`, `customer_name`, `customer_id`, `customer_portal_url`, `deposit_remaining`, `balance_remaining`, `package_tracking`, `customer_po_number`.\n- Purchase orders: `order_label`, `order_number`, `issue_date`, `due_date`, `note`, `total`, `download_url`, `creator.name`, `creator.email`.\n\nEach template's `supported_placeholder` lists its own, with labels. The body is HTML for emails and plain text for text messages.\n\nAttachment `type` values: `order` (the sales order or quote PDF), `order_compact` (its compact PDF), `so_jobs_with_mockup` and `so_jobs_without_mockup` (job sheets), `so_invoices` and `so_compact_invoices` (its invoices), `purchase_order` (the purchase order PDF), and `media` or `reference_media` (a file, by `media_id`). A template accepts only the values in its `supported_attachments`: purchase order templates take `purchase_order`, `media` and `reference_media`.","operationId":"v2_public_message_template_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"body":"<p>Hi {{customer_name}}, your order #{{order_number}} is ready for pickup at 100 Example Street.</p>","internal_attachments":[{"name":"Sales order PDF","type":"order"}],"name":"Ready for pickup","type":"sales_order_message"},"schema":{"additionalProperties":false,"properties":{"body":{"description":"Liquid. Must be valid Liquid. HTML for emails, plain text for text messages.","type":"string"},"internal_attachments":{"description":"Document attachments to add with the template. A `media` or `reference_media` attachment can't be added here: this call doesn't decode `media_id`, so it fails validation. Add files afterwards with \"Add an attachment to a template\".","items":{"additionalProperties":false,"properties":{"detail":{"type":"string"},"media_id":{"description":"Required for `media`: the id of a file you uploaded. `reference_media` also needs an existing file.","type":"string"},"name":{"description":"A name for the attachment.","type":"string"},"options":{"additionalProperties":true,"properties":{"show_mockup":{"description":"For `so_jobs_with_mockup` and `so_jobs_without_mockup`: `true` puts each job's mockup pages in the job sheets, `false` leaves them out. It overrides the type's own choice. Text such as `\"true\"` or `\"off\"` is accepted too; any other value is refused with 422 `validation_failed`. Other types ignore it.","type":"boolean"}},"type":"object"},"type":{"description":"What to attach. Must be in the template's `supported_attachments`.","enum":["order","order_compact","so_jobs_with_mockup","so_jobs_without_mockup","so_invoices","so_compact_invoices","purchase_order","media","reference_media"],"type":"string"}},"required":["type"],"type":"object"},"type":"array"},"name":{"description":"What people pick from.","type":"string"},"options":{"additionalProperties":false,"description":"Email button settings. Accepted but, in practice, not saved: YoPrint keeps them only on a template that already has button settings, and templates made through the API or by YoPrint have none. They are not returned when you read a template. Preview does use them.","properties":{"button_label":{"description":"Required when `enable_button` is true.","type":"string"},"button_link":{"description":"Required when `enable_button` is true.","type":"string"},"enable_button":{"type":"boolean"}},"type":"object"},"subject":{"description":"Liquid; must be valid Liquid. These six types have no subject line of their own: a subject is saved, but compile, preview and send don't use it.","type":"string"},"type":{"enum":["sales_order_message","sales_order_text_message","quote_message","quote_text_message","purchase_order_message","purchase_order_text_message"],"type":"string"}},"required":["type","name","body"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"body":"<p>Hi {{customer_name}}, your order #{{order_number}} is ready for pickup at 100 Example Street.</p>","can_create":true,"can_delete":true,"can_update":true,"created_at":"2026-10-01T09:00:00+00:00","id":"DVubREua5aJkwh","internal_attachments":[{"created_at":"2026-10-01T09:00:00+00:00","detail":"Sales Order/Quote (PDF)","id":"80qLp4P9l2ftvL","media":null,"media_id":null,"name":"Sales order PDF","options":"[]","order_id":null,"order_scoped_id":"","purchase_order_id":null,"purchase_order_scoped_id":"","type":"order","updated_at":"2026-10-01T09:00:00+00:00"}],"name":"Ready for pickup","subject":null,"support_attachments":true,"support_subject":false,"supported_attachments":["media","reference_media","order","order_compact","so_jobs_with_mockup","so_jobs_without_mockup","so_invoices","so_compact_invoices"],"supported_placeholder":[{"label":"Order Number","value":"order_number"},{"label":"Customer Name","value":"customer_name"}],"system":false,"type":"sales_order_message","updated_at":"2026-10-01T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"body":{"description":"Liquid: HTML for emails, plain text for text messages.","type":"string"},"can_create":{"type":"boolean"},"can_delete":{"type":"boolean"},"can_update":{"type":"boolean"},"created_at":{"format":"date-time","type":"string"},"id":{"example":"DVubREua5aJkwh","type":"string"},"internal_attachments":{"description":"Its attachments, as the attachment operations return them.","items":{"additionalProperties":false,"properties":{"created_at":{"format":"date-time","type":"string"},"detail":{"description":"For a document attachment, defaults to its kind, such as `Sales Order/Quote (PDF)`.","type":["string","null"]},"id":{"example":"80qLp4P9l2ftvL","type":"string"},"media":{"additionalProperties":true,"description":"For a `media` or `reference_media` attachment, the file: `id`, `name`, `file_name`, `mime_type`, `size`, a download `url`, a signed `view_url` and more. Null for document attachments.","type":["object","null"]},"media_id":{"type":["string","null"]},"name":{"type":["string","null"]},"options":{"description":"The attachment's options as a JSON-encoded string, not an object: `\"[]\"`, or for job sheets `\"{\\\"show_mockup\\\":true}\"`. `\"null\"` for a `media` or `reference_media` file. Decode it before use.","type":["string","null"]},"order_id":{"type":["string","null"]},"order_scoped_id":{"type":["string","integer","null"]},"purchase_order_id":{"type":["string","null"]},"purchase_order_scoped_id":{"type":["string","integer","null"]},"type":{"example":"order","type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","order_id","order_scoped_id","purchase_order_id","purchase_order_scoped_id","name","detail","media_id","options","created_at","updated_at","media"],"type":"object"},"type":"array"},"name":{"example":"Ready for pickup","type":"string"},"subject":{"description":"Liquid, as saved; null when none was saved. Only the three system types use a subject (`support_subject: true`).","type":["string","null"]},"support_attachments":{"description":"True for every type, text messages included.","type":"boolean"},"support_subject":{"description":"True for the three system types only. The six saved types have no subject line of their own.","type":"boolean"},"supported_attachments":{"description":"The attachment `type` values this template can carry.","items":{"type":"string"},"type":"array"},"supported_placeholder":{"items":{"additionalProperties":false,"properties":{"label":{"example":"Order Number","type":"string"},"value":{"description":"Write it in the template as `{{value}}`.","example":"order_number","type":"string"}},"required":["label","value"],"type":"object"},"type":"array"},"system":{"description":"A system template: YoPrint's own email for new documents. It can be edited but not created or deleted.","type":"boolean"},"type":{"enum":["new_sales_order_message","new_quote_message","purchase_order","sales_order_message","sales_order_text_message","quote_message","quote_text_message","purchase_order_message","purchase_order_text_message"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","name","subject","body","system","support_subject","support_attachments","supported_placeholder","supported_attachments","can_create","can_update","can_delete","created_at","updated_at","internal_attachments"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a message template","tags":["Message templates"],"x-yoprint-docs":{"errors":[{"fix":"Fix the field named in `error.fields`; add files with the attachment operation.","status":422,"when":"`type`, `name` or `body` is missing, the Liquid is invalid, or an inline attachment has a `media_id` (`validation_failed`)."},{"fix":"Use a document type from `supported_attachments`; add files with the attachment operation.","status":422,"when":"An attachment type is not supported (`type_not_supported`), or a `media` or `reference_media` attachment is sent without `media_id` (`media_not_found`). Nothing is saved."},{"fix":"Edit the existing system template instead.","status":422,"when":"The type is a system type: `error.code` `system_template`."},{"fix":"Use one of the six saved types.","status":500,"when":"`type` is not a known template type. The body is `{\"message\": \"Server Error\"}`, without the error envelope."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v2_public_message_template_config_index","v2_public_message_template_preview","v2_public_message_template_internal_attachment_store"],"rules":["System types can't be created (422 `system_template`).","Inline attachments take document types only; add `media` and `reference_media` files with \"Add an attachment to a template\".","`subject` and `body` must be valid Liquid; a syntax error is refused with 422.","Each attachment `type` must be one the template supports. The template and its attachments are saved together or not at all."],"side_effects":["Team members who have YoPrint open see the new template at once."]}}},"/v2/api/store/{team_slug}/setting/message_template/compile":{"post":{"description":"Fills a saved template's placeholders from one record and returns the finished `subject` and `body`, with the template's attachments. Use it to show someone the message before sending it. Nothing is sent.\n\n`object_id` is a sales order or quote for sales order and quote templates, and a purchase order for purchase order templates.","operationId":"v2_public_message_template_compile","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"id":"DVubREua5aJkwh","object_id":"zGZRXNGeh5cs6M"},"schema":{"additionalProperties":false,"properties":{"id":{"description":"The saved template's id.","type":"string"},"object_id":{"description":"The record it is about: a sales order or quote id for sales order and quote templates, a purchase order id for purchase order templates.","type":"string"}},"required":["id","object_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"body":"<p>Your order #1001 is ready for pickup at 100 Example Street.</p>","internal_attachments":[{"created_at":"2026-10-01T09:00:00+00:00","detail":"Sales Order/Quote (PDF)","id":"80qLp4P9l2ftvL","media":null,"media_id":null,"name":"Sales order PDF","options":"[]","order_id":null,"order_scoped_id":"","purchase_order_id":null,"purchase_order_scoped_id":"","type":"order","updated_at":"2026-10-01T09:00:00+00:00"}],"subject":""},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"body":{"type":"string"},"internal_attachments":{"description":"The template's attachments, as the attachment operations return them, except that a `media` attachment reads `type: reference_media` here.","items":{"additionalProperties":false,"properties":{"created_at":{"format":"date-time","type":"string"},"detail":{"description":"For a document attachment, defaults to its kind, such as `Sales Order/Quote (PDF)`.","type":["string","null"]},"id":{"example":"80qLp4P9l2ftvL","type":"string"},"media":{"additionalProperties":true,"description":"For a `media` or `reference_media` attachment, the file: `id`, `name`, `file_name`, `mime_type`, `size`, a download `url`, a signed `view_url` and more. Null for document attachments.","type":["object","null"]},"media_id":{"type":["string","null"]},"name":{"type":["string","null"]},"options":{"description":"The attachment's options as a JSON-encoded string, not an object: `\"[]\"`, or for job sheets `\"{\\\"show_mockup\\\":true}\"`. `\"null\"` for a `media` or `reference_media` file. Decode it before use.","type":["string","null"]},"order_id":{"type":["string","null"]},"order_scoped_id":{"type":["string","integer","null"]},"purchase_order_id":{"type":["string","null"]},"purchase_order_scoped_id":{"type":["string","integer","null"]},"type":{"example":"order","type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","order_id","order_scoped_id","purchase_order_id","purchase_order_scoped_id","name","detail","media_id","options","created_at","updated_at","media"],"type":"object"},"type":"array"},"subject":{"description":"The filled-in subject. An empty string for types without a subject line (all but the three system types).","type":"string"}},"required":["subject","body","internal_attachments"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Fill in a template for a record","tags":["Message templates"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the template list.","status":404,"when":"No template of your team has this `id`."},{"fix":"Send the record's id.","status":422,"when":"`object_id` is missing (`validation_failed`)."},{"fix":"Send a sales order or quote id for those templates, a purchase order id for purchase order templates.","status":422,"when":"`object_id` is not a record of your team of the right kind: `error.code` `compile_failed`."}],"group":"Team settings","permission":"Any member of the team: with a personal API key, no permission on the record is checked. AI apps need permission to view that record, and its sign-in and file links read as placeholders for them.","related":["v2_public_message_template_send","v2_public_message_template_preview"]}}},"/v2/api/store/{team_slug}/setting/message_template/config":{"get":{"description":"Returns every kind of message template YoPrint supports, with its default name, subject and body, its placeholders and the attachments it can carry. It is the same for every team. Use it to see which `type` to create and which placeholders it understands.\n\n| `type` | What it is | Placeholders |\n| --- | --- | --- |\n| `new_sales_order_message` | System: the \"New Sales Order Detail\" email | sales order |\n| `new_quote_message` | System: the \"New Quote Detail\" email | quote |\n| `purchase_order` | System: the \"New Purchase Order Detail\" email to a vendor | purchase order |\n| `sales_order_message` | Your saved email for a sales order | sales order |\n| `sales_order_text_message` | Your saved text message for a sales order | sales order |\n| `quote_message` | Your saved email for a quote | quote |\n| `quote_text_message` | Your saved text message for a quote | quote |\n| `purchase_order_message` | Your saved email to a vendor about a purchase order | purchase order |\n| `purchase_order_text_message` | Your saved text message to a vendor | purchase order |\n\nSystem types (`system: true`, `can_create: false`) are set up with each new team: edit them, don't create them.","operationId":"v2_public_message_template_config_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"body":"<p>Your Sales Order #{{order_number}} is ready for collection.</p>","can_create":true,"can_delete":true,"can_update":true,"name":"Ready For Collection (Example)","subject":null,"support_attachments":true,"support_subject":false,"supported_attachments":["media","reference_media","order","order_compact","so_jobs_with_mockup","so_jobs_without_mockup","so_invoices","so_compact_invoices"],"supported_placeholder":[{"label":"Order Number","value":"order_number"},{"label":"Customer Name","value":"customer_name"}],"system":false,"type":"sales_order_message"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"body":{"description":"Liquid: HTML for emails, plain text for text messages.","type":"string"},"can_create":{"type":"boolean"},"can_delete":{"type":"boolean"},"can_update":{"type":"boolean"},"name":{"description":"The default name of a new template of this type.","example":"Ready for pickup","type":"string"},"subject":{"description":"The default subject, for the three system types; null for the others.","type":["string","null"]},"support_attachments":{"description":"True for every type, text messages included.","type":"boolean"},"support_subject":{"description":"True for the three system types only. The six saved types have no subject line of their own.","type":"boolean"},"supported_attachments":{"description":"The attachment `type` values this template can carry.","items":{"type":"string"},"type":"array"},"supported_placeholder":{"items":{"additionalProperties":false,"properties":{"label":{"example":"Order Number","type":"string"},"value":{"description":"Write it in the template as `{{value}}`.","example":"order_number","type":"string"}},"required":["label","value"],"type":"object"},"type":"array"},"system":{"description":"A system template: YoPrint's own email for new documents. It can be edited but not created or deleted.","type":"boolean"},"type":{"enum":["new_sales_order_message","new_quote_message","purchase_order","sales_order_message","sales_order_text_message","quote_message","quote_text_message","purchase_order_message","purchase_order_text_message"],"type":"string"}},"required":["type","name","subject","body","system","support_subject","support_attachments","supported_placeholder","supported_attachments","can_create","can_update","can_delete"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List message template types","tags":["Message templates"],"x-yoprint-docs":{"group":"Team settings","permission":"Any member of the team.","related":["v2_public_message_template_config_show","v2_public_message_template_store"]}}},"/v2/api/store/{team_slug}/setting/message_template/config/{type}":{"get":{"description":"Returns one template type, by its `type` value (for example `sales_order_message`): its default name, subject and body, placeholders and supported attachments. An unknown type returns 404 `template_not_found`.","operationId":"v2_public_message_template_config_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The template type.","example":"sales_order_message","in":"path","name":"type","required":true,"schema":{"enum":["new_sales_order_message","new_quote_message","purchase_order","sales_order_message","sales_order_text_message","quote_message","quote_text_message","purchase_order_message","purchase_order_text_message"],"example":"sales_order_message","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"body":"<p>Your Sales Order #{{order_number}} is ready for collection.</p>","can_create":true,"can_delete":true,"can_update":true,"name":"Ready For Collection (Example)","subject":null,"support_attachments":true,"support_subject":false,"supported_attachments":["media","reference_media","order","order_compact","so_jobs_with_mockup","so_jobs_without_mockup","so_invoices","so_compact_invoices"],"supported_placeholder":[{"label":"Order Number","value":"order_number"},{"label":"Customer Name","value":"customer_name"}],"system":false,"type":"sales_order_message"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"body":{"description":"Liquid: HTML for emails, plain text for text messages.","type":"string"},"can_create":{"type":"boolean"},"can_delete":{"type":"boolean"},"can_update":{"type":"boolean"},"name":{"description":"The default name of a new template of this type.","example":"Ready for pickup","type":"string"},"subject":{"description":"The default subject, for the three system types; null for the others.","type":["string","null"]},"support_attachments":{"description":"True for every type, text messages included.","type":"boolean"},"support_subject":{"description":"True for the three system types only. The six saved types have no subject line of their own.","type":"boolean"},"supported_attachments":{"description":"The attachment `type` values this template can carry.","items":{"type":"string"},"type":"array"},"supported_placeholder":{"items":{"additionalProperties":false,"properties":{"label":{"example":"Order Number","type":"string"},"value":{"description":"Write it in the template as `{{value}}`.","example":"order_number","type":"string"}},"required":["label","value"],"type":"object"},"type":"array"},"system":{"description":"A system template: YoPrint's own email for new documents. It can be edited but not created or deleted.","type":"boolean"},"type":{"enum":["new_sales_order_message","new_quote_message","purchase_order","sales_order_message","sales_order_text_message","quote_message","quote_text_message","purchase_order_message","purchase_order_text_message"],"type":"string"}},"required":["type","name","subject","body","system","support_subject","support_attachments","supported_placeholder","supported_attachments","can_create","can_update","can_delete"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a message template type","tags":["Message templates"],"x-yoprint-docs":{"errors":[{"fix":"Use a type from the list of template types.","status":404,"when":"The type is unknown: `error.code` `template_not_found`."}],"group":"Team settings","permission":"Any member of the team.","related":["v2_public_message_template_config_index"]}}},"/v2/api/store/{team_slug}/setting/message_template/preview":{"post":{"description":"Renders template text you are writing, before you save it: send the `type`, `body` and optional `subject`. Returns the finished message (`data`): HTML for email types, plain text for the three text-message types, plus the filled-in `subject` and `body`. `subject` is an empty string for every type but the three system ones.\n\nWithout `object_id`, YoPrint fills the placeholders with made-up sample data. With `object_id`, it uses that sales order, quote or purchase order.\n\nNothing is saved and nothing is sent.","operationId":"v2_public_message_template_preview","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"body":"<p>Hi {{customer_name}}, your order #{{order_number}} is ready.</p>","type":"sales_order_message"},"schema":{"additionalProperties":false,"properties":{"body":{"description":"Liquid.","type":"string"},"object_id":{"description":"Optional: a record of your team to fill the placeholders from. Without it, sample data is used.","type":"string"},"options":{"additionalProperties":false,"description":"Email button settings. Accepted but, in practice, not saved: YoPrint keeps them only on a template that already has button settings, and templates made through the API or by YoPrint have none. They are not returned when you read a template. Preview does use them.","properties":{"button_label":{"description":"Required when `enable_button` is true.","type":"string"},"button_link":{"description":"Required when `enable_button` is true.","type":"string"},"enable_button":{"type":"boolean"}},"type":"object"},"subject":{"description":"Liquid.","type":"string"},"type":{"enum":["new_sales_order_message","new_quote_message","purchase_order","sales_order_message","sales_order_text_message","quote_message","quote_text_message","purchase_order_message","purchase_order_text_message"],"type":"string"}},"required":["type","body"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"body":"<p>Hi Alex Rivera, your order #1001 is ready.</p>","data":"<html><body><p>Hi Alex Rivera, your order #1001 is ready.</p></body></html>","subject":""},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"body":{"type":"string"},"data":{"description":"The whole message: HTML for email types, plain text for text-message types.","type":"string"},"subject":{"description":"The filled-in subject. An empty string for types without a subject line (all but the three system types).","type":"string"}},"required":["data","subject","body"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Preview template text","tags":["Message templates"],"x-yoprint-docs":{"errors":[{"fix":"Check the type, the template text and the record id.","status":422,"when":"`body` or `type` is missing or the Liquid is invalid (`validation_failed`); `type` is unknown (`invalid_type`); or `object_id` is not a record of your team (`preview_failed`)."}],"group":"Team settings","permission":"Any member of the team. With `object_id`, no permission on that record is checked. AI apps can't send `object_id` (they preview on sample data only), and their Liquid is checked first.","related":["v2_public_message_template_compile","v2_public_message_template_store"]}}},"/v2/api/store/{team_slug}/setting/message_template/send":{"post":{"description":"Fills a saved template from one record and sends it now. **It reaches a real customer or vendor and can't be recalled.**\n\n- Email templates send an email, with the template's attachments.\n- Text message templates send a text through your Twilio integration.\n\nWho gets it: for an email, the record's message participants who receive mail and messages, or the record's contact if there are none. For a text, the participants who receive texts; with none, nobody is texted.\n\nEmail limit: if your team goes over the daily email limit for its plan (60 a day on a free plan or trial, more on paid plans), YoPrint blocks email sending for your whole team until YoPrint support lifts the block. Space out bulk sends.\n\nThe six saved email types have no subject line of their own: their compiled `subject` is empty.\n\nCompile it first to check the result. The response has no data.","operationId":"v2_public_message_template_send","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"id":"DVubREua5aJkwh","object_id":"zGZRXNGeh5cs6M"},"schema":{"additionalProperties":false,"properties":{"id":{"description":"The saved template's id.","type":"string"},"object_id":{"description":"The record it is about: a sales order or quote id for sales order and quote templates, a purchase order id for purchase order templates.","type":"string"}},"required":["id","object_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Send a template for a record","tags":["Message templates"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the template list.","status":404,"when":"No template of your team has this `id`."},{"fix":"Send the record's id.","status":422,"when":"`object_id` is missing (`validation_failed`)."},{"fix":"Send a sales order or quote id for those templates, a purchase order id for purchase order templates.","status":422,"when":"`object_id` is not a record of your team of the right kind: `error.code` `send_failed`. Nothing is sent."},{"fix":"Read `error.message`; contact YoPrint support if sending is blocked.","status":422,"when":"Your plan doesn't allow purchase order emails (`plan_limitation`), the trial doesn't allow email (`email_feature_not_enabled_in_trial`), or the team is over its daily email limit (`validation_error`, \"You are sending too many emails...\")."}],"group":"Team settings","permission":"With a personal API key, any member of the team: no permission on the record is checked, even for members who can't see that order. AI apps need permission to message about that record.","related":["v2_public_message_template_compile","v2_public_message_template_index"],"rules":["Purchase order templates need the \"send purchase order email\" feature in your plan (422 `plan_limitation`).","A team on a trial can send only when YoPrint has turned on email for its trial, and a paid team needs an active subscription (otherwise 422 `email_feature_not_enabled_in_trial`).","Every team has a daily email limit. Going over it blocks the team's email sending until YoPrint support lifts the block."],"side_effects":["Sends an email or a text message to the customer or vendor, and saves it with the record's messages.","Document attachments (such as the order PDF) are made from the record at the time of sending.","A text message is sent through your Twilio account and costs what Twilio charges."]}}},"/v2/api/store/{team_slug}/setting/message_template/{hash_id}":{"delete":{"description":"Deletes one of your saved templates for good. System templates can't be deleted: the call answers 500 `delete_fail` and changes nothing.","operationId":"v2_public_message_template_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message template. Its hash id from an earlier answer; there is no unique key for it.","example":"DVubREua5aJkwh","in":"path","name":"hash_id","required":true,"schema":{"example":"DVubREua5aJkwh","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a message template","tags":["Message templates"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the list.","status":404,"when":"No template of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Edit it instead.","status":500,"when":"It is a system template: `error.code` `delete_fail`, `error.message` null. Nothing is deleted."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v2_public_message_template_index"],"side_effects":["Team members who have YoPrint open see it disappear at once."]}},"get":{"description":"Returns one message template with its raw subject and body (placeholders not filled in), its placeholders and its attachments. To see it filled in for a record, compile it.","operationId":"v2_public_message_template_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message template. Its hash id from an earlier answer; there is no unique key for it.","example":"DVubREua5aJkwh","in":"path","name":"hash_id","required":true,"schema":{"example":"DVubREua5aJkwh","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"body":"<p>Your order #{{order_number}} is ready for pickup at 100 Example Street.</p>","can_create":true,"can_delete":true,"can_update":true,"created_at":"2026-10-01T09:00:00+00:00","id":"DVubREua5aJkwh","internal_attachments":[],"name":"Ready for pickup","subject":null,"support_attachments":true,"support_subject":false,"supported_attachments":["media","reference_media","order","order_compact","so_jobs_with_mockup","so_jobs_without_mockup","so_invoices","so_compact_invoices"],"supported_placeholder":[{"label":"Order Number","value":"order_number"},{"label":"Customer Name","value":"customer_name"}],"system":false,"type":"sales_order_message","updated_at":"2026-10-01T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"body":{"description":"Liquid: HTML for emails, plain text for text messages.","type":"string"},"can_create":{"type":"boolean"},"can_delete":{"type":"boolean"},"can_update":{"type":"boolean"},"created_at":{"format":"date-time","type":"string"},"id":{"example":"DVubREua5aJkwh","type":"string"},"internal_attachments":{"description":"Its attachments, as the attachment operations return them.","items":{"additionalProperties":false,"properties":{"created_at":{"format":"date-time","type":"string"},"detail":{"description":"For a document attachment, defaults to its kind, such as `Sales Order/Quote (PDF)`.","type":["string","null"]},"id":{"example":"80qLp4P9l2ftvL","type":"string"},"media":{"additionalProperties":true,"description":"For a `media` or `reference_media` attachment, the file: `id`, `name`, `file_name`, `mime_type`, `size`, a download `url`, a signed `view_url` and more. Null for document attachments.","type":["object","null"]},"media_id":{"type":["string","null"]},"name":{"type":["string","null"]},"options":{"description":"The attachment's options as a JSON-encoded string, not an object: `\"[]\"`, or for job sheets `\"{\\\"show_mockup\\\":true}\"`. `\"null\"` for a `media` or `reference_media` file. Decode it before use.","type":["string","null"]},"order_id":{"type":["string","null"]},"order_scoped_id":{"type":["string","integer","null"]},"purchase_order_id":{"type":["string","null"]},"purchase_order_scoped_id":{"type":["string","integer","null"]},"type":{"example":"order","type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","order_id","order_scoped_id","purchase_order_id","purchase_order_scoped_id","name","detail","media_id","options","created_at","updated_at","media"],"type":"object"},"type":"array"},"name":{"example":"Ready for pickup","type":"string"},"subject":{"description":"Liquid, as saved; null when none was saved. Only the three system types use a subject (`support_subject: true`).","type":["string","null"]},"support_attachments":{"description":"True for every type, text messages included.","type":"boolean"},"support_subject":{"description":"True for the three system types only. The six saved types have no subject line of their own.","type":"boolean"},"supported_attachments":{"description":"The attachment `type` values this template can carry.","items":{"type":"string"},"type":"array"},"supported_placeholder":{"items":{"additionalProperties":false,"properties":{"label":{"example":"Order Number","type":"string"},"value":{"description":"Write it in the template as `{{value}}`.","example":"order_number","type":"string"}},"required":["label","value"],"type":"object"},"type":"array"},"system":{"description":"A system template: YoPrint's own email for new documents. It can be edited but not created or deleted.","type":"boolean"},"type":{"enum":["new_sales_order_message","new_quote_message","purchase_order","sales_order_message","sales_order_text_message","quote_message","quote_text_message","purchase_order_message","purchase_order_text_message"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","name","subject","body","system","support_subject","support_attachments","supported_placeholder","supported_attachments","can_create","can_update","can_delete","created_at","updated_at","internal_attachments"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a message template","tags":["Message templates"],"x-yoprint-docs":{"group":"Team settings","permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v2_public_message_template_update_patch","v2_public_message_template_compile"]}},"patch":{"description":"Use PUT to change a message template. PATCH changes only `options`, which in practice are not saved. See Update a message template (PUT) for the fields.","operationId":"v2_public_message_template_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message template. Its hash id from an earlier answer; there is no unique key for it.","example":"DVubREua5aJkwh","in":"path","name":"hash_id","required":true,"schema":{"example":"DVubREua5aJkwh","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"body":"<p>Hi {{customer_name}}, order #{{order_number}} is ready. Total: {{total}}.</p>","name":"Ready for pickup"},"schema":{"additionalProperties":false,"properties":{"body":{"description":"Liquid.","type":"string"},"name":{"type":"string"},"options":{"additionalProperties":false,"description":"Email button settings. Accepted but, in practice, not saved: YoPrint keeps them only on a template that already has button settings, and templates made through the API or by YoPrint have none. They are not returned when you read a template. Preview does use them.","properties":{"button_label":{"description":"Required when `enable_button` is true.","type":"string"},"button_link":{"description":"Required when `enable_button` is true.","type":"string"},"enable_button":{"type":"boolean"}},"type":"object"},"subject":{"description":"Liquid.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"body":"<p>Hi {{customer_name}}, order #{{order_number}} is ready. Total: {{total}}.</p>","can_create":true,"can_delete":true,"can_update":true,"created_at":"2026-10-01T09:00:00+00:00","id":"DVubREua5aJkwh","internal_attachments":[],"name":"Ready for pickup","subject":null,"support_attachments":true,"support_subject":false,"supported_attachments":["media","reference_media","order","order_compact","so_jobs_with_mockup","so_jobs_without_mockup","so_invoices","so_compact_invoices"],"supported_placeholder":[{"label":"Order Number","value":"order_number"},{"label":"Customer Name","value":"customer_name"}],"system":false,"type":"sales_order_message","updated_at":"2026-11-03T10:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"body":{"description":"Liquid: HTML for emails, plain text for text messages.","type":"string"},"can_create":{"type":"boolean"},"can_delete":{"type":"boolean"},"can_update":{"type":"boolean"},"created_at":{"format":"date-time","type":"string"},"id":{"example":"DVubREua5aJkwh","type":"string"},"internal_attachments":{"description":"Its attachments, as the attachment operations return them.","items":{"additionalProperties":false,"properties":{"created_at":{"format":"date-time","type":"string"},"detail":{"description":"For a document attachment, defaults to its kind, such as `Sales Order/Quote (PDF)`.","type":["string","null"]},"id":{"example":"80qLp4P9l2ftvL","type":"string"},"media":{"additionalProperties":true,"description":"For a `media` or `reference_media` attachment, the file: `id`, `name`, `file_name`, `mime_type`, `size`, a download `url`, a signed `view_url` and more. Null for document attachments.","type":["object","null"]},"media_id":{"type":["string","null"]},"name":{"type":["string","null"]},"options":{"description":"The attachment's options as a JSON-encoded string, not an object: `\"[]\"`, or for job sheets `\"{\\\"show_mockup\\\":true}\"`. `\"null\"` for a `media` or `reference_media` file. Decode it before use.","type":["string","null"]},"order_id":{"type":["string","null"]},"order_scoped_id":{"type":["string","integer","null"]},"purchase_order_id":{"type":["string","null"]},"purchase_order_scoped_id":{"type":["string","integer","null"]},"type":{"example":"order","type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","order_id","order_scoped_id","purchase_order_id","purchase_order_scoped_id","name","detail","media_id","options","created_at","updated_at","media"],"type":"object"},"type":"array"},"name":{"example":"Ready for pickup","type":"string"},"subject":{"description":"Liquid, as saved; null when none was saved. Only the three system types use a subject (`support_subject: true`).","type":["string","null"]},"support_attachments":{"description":"True for every type, text messages included.","type":"boolean"},"support_subject":{"description":"True for the three system types only. The six saved types have no subject line of their own.","type":"boolean"},"supported_attachments":{"description":"The attachment `type` values this template can carry.","items":{"type":"string"},"type":"array"},"supported_placeholder":{"items":{"additionalProperties":false,"properties":{"label":{"example":"Order Number","type":"string"},"value":{"description":"Write it in the template as `{{value}}`.","example":"order_number","type":"string"}},"required":["label","value"],"type":"object"},"type":"array"},"system":{"description":"A system template: YoPrint's own email for new documents. It can be edited but not created or deleted.","type":"boolean"},"type":{"enum":["new_sales_order_message","new_quote_message","purchase_order","sales_order_message","sales_order_text_message","quote_message","quote_text_message","purchase_order_message","purchase_order_text_message"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","name","subject","body","system","support_subject","support_attachments","supported_placeholder","supported_attachments","can_create","can_update","can_delete","created_at","updated_at","internal_attachments"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Touch a message template","tags":["Message templates"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the list.","status":404,"when":"No template of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Fix the template text.","status":422,"when":"`subject` or `body` is not valid Liquid, or a button is enabled without a label and link (`validation_failed`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v2_public_message_template_show","v2_public_message_template_preview"],"side_effects":["Team members who have YoPrint open see the change at once."]}},"put":{"description":"Changes a template's name, subject, body or button settings. Send only what changes. System templates can be edited too.\n\nUse PUT. PATCH runs no rules and changes only `options`, which in practice aren't saved (see `options`).\n\nAttachments are changed with the attachment operations. The type can't change.\n\n**Placeholders.** `subject` and `body` are Liquid: write `{{order_number}}` and YoPrint fills it in from the record when the message is made.\n\n- Sales orders and quotes: `order_number` (`quote_number` on quote templates), `order_label`, `order_link`, `issue_date`, `cust_due_date`, `client_note`, `total`, `download_url`, `creator.name`, `customer_name`, `customer_id`, `customer_portal_url`, `deposit_remaining`, `balance_remaining`, `package_tracking`, `customer_po_number`.\n- Purchase orders: `order_label`, `order_number`, `issue_date`, `due_date`, `note`, `total`, `download_url`, `creator.name`, `creator.email`.\n\nEach template's `supported_placeholder` lists its own, with labels. The body is HTML for emails and plain text for text messages.","operationId":"v2_public_message_template_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message template. Its hash id from an earlier answer; there is no unique key for it.","example":"DVubREua5aJkwh","in":"path","name":"hash_id","required":true,"schema":{"example":"DVubREua5aJkwh","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"body":"<p>Hi {{customer_name}}, order #{{order_number}} is ready. Total: {{total}}.</p>","name":"Ready for pickup"},"schema":{"additionalProperties":false,"properties":{"body":{"description":"Liquid.","type":"string"},"name":{"type":"string"},"options":{"additionalProperties":false,"description":"Email button settings. Accepted but, in practice, not saved: YoPrint keeps them only on a template that already has button settings, and templates made through the API or by YoPrint have none. They are not returned when you read a template. Preview does use them.","properties":{"button_label":{"description":"Required when `enable_button` is true.","type":"string"},"button_link":{"description":"Required when `enable_button` is true.","type":"string"},"enable_button":{"type":"boolean"}},"type":"object"},"subject":{"description":"Liquid.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"body":"<p>Hi {{customer_name}}, order #{{order_number}} is ready. Total: {{total}}.</p>","can_create":true,"can_delete":true,"can_update":true,"created_at":"2026-10-01T09:00:00+00:00","id":"DVubREua5aJkwh","internal_attachments":[],"name":"Ready for pickup","subject":null,"support_attachments":true,"support_subject":false,"supported_attachments":["media","reference_media","order","order_compact","so_jobs_with_mockup","so_jobs_without_mockup","so_invoices","so_compact_invoices"],"supported_placeholder":[{"label":"Order Number","value":"order_number"},{"label":"Customer Name","value":"customer_name"}],"system":false,"type":"sales_order_message","updated_at":"2026-11-03T10:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"body":{"description":"Liquid: HTML for emails, plain text for text messages.","type":"string"},"can_create":{"type":"boolean"},"can_delete":{"type":"boolean"},"can_update":{"type":"boolean"},"created_at":{"format":"date-time","type":"string"},"id":{"example":"DVubREua5aJkwh","type":"string"},"internal_attachments":{"description":"Its attachments, as the attachment operations return them.","items":{"additionalProperties":false,"properties":{"created_at":{"format":"date-time","type":"string"},"detail":{"description":"For a document attachment, defaults to its kind, such as `Sales Order/Quote (PDF)`.","type":["string","null"]},"id":{"example":"80qLp4P9l2ftvL","type":"string"},"media":{"additionalProperties":true,"description":"For a `media` or `reference_media` attachment, the file: `id`, `name`, `file_name`, `mime_type`, `size`, a download `url`, a signed `view_url` and more. Null for document attachments.","type":["object","null"]},"media_id":{"type":["string","null"]},"name":{"type":["string","null"]},"options":{"description":"The attachment's options as a JSON-encoded string, not an object: `\"[]\"`, or for job sheets `\"{\\\"show_mockup\\\":true}\"`. `\"null\"` for a `media` or `reference_media` file. Decode it before use.","type":["string","null"]},"order_id":{"type":["string","null"]},"order_scoped_id":{"type":["string","integer","null"]},"purchase_order_id":{"type":["string","null"]},"purchase_order_scoped_id":{"type":["string","integer","null"]},"type":{"example":"order","type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","order_id","order_scoped_id","purchase_order_id","purchase_order_scoped_id","name","detail","media_id","options","created_at","updated_at","media"],"type":"object"},"type":"array"},"name":{"example":"Ready for pickup","type":"string"},"subject":{"description":"Liquid, as saved; null when none was saved. Only the three system types use a subject (`support_subject: true`).","type":["string","null"]},"support_attachments":{"description":"True for every type, text messages included.","type":"boolean"},"support_subject":{"description":"True for the three system types only. The six saved types have no subject line of their own.","type":"boolean"},"supported_attachments":{"description":"The attachment `type` values this template can carry.","items":{"type":"string"},"type":"array"},"supported_placeholder":{"items":{"additionalProperties":false,"properties":{"label":{"example":"Order Number","type":"string"},"value":{"description":"Write it in the template as `{{value}}`.","example":"order_number","type":"string"}},"required":["label","value"],"type":"object"},"type":"array"},"system":{"description":"A system template: YoPrint's own email for new documents. It can be edited but not created or deleted.","type":"boolean"},"type":{"enum":["new_sales_order_message","new_quote_message","purchase_order","sales_order_message","sales_order_text_message","quote_message","quote_text_message","purchase_order_message","purchase_order_text_message"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","name","subject","body","system","support_subject","support_attachments","supported_placeholder","supported_attachments","can_create","can_update","can_delete","created_at","updated_at","internal_attachments"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a message template","tags":["Message templates"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the list.","status":404,"when":"No template of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Fix the template text.","status":422,"when":"`subject` or `body` is not valid Liquid, or a button is enabled without a label and link (`validation_failed`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v2_public_message_template_show","v2_public_message_template_preview"],"side_effects":["Team members who have YoPrint open see the change at once."]}}},"/v2/api/store/{team_slug}/setting/message_template/{hash_id}/internal_attachment":{"get":{"description":"Returns the attachments a message template adds when it is sent. The path takes the template's id. Attachment `type` values: `order` (the sales order or quote PDF), `order_compact` (its compact PDF), `so_jobs_with_mockup` and `so_jobs_without_mockup` (job sheets), `so_invoices` and `so_compact_invoices` (its invoices), `purchase_order` (the purchase order PDF), and `media` or `reference_media` (a file, by `media_id`). A template accepts only the values in its `supported_attachments`: purchase order templates take `purchase_order`, `media` and `reference_media`.","operationId":"v2_public_message_template_internal_attachment_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message template. Its hash id from an earlier answer; there is no unique key for it.","example":"DVubREua5aJkwh","in":"path","name":"hash_id","required":true,"schema":{"example":"DVubREua5aJkwh","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"created_at":"2026-10-01T09:00:00+00:00","detail":"Sales Order/Quote (PDF)","id":"80qLp4P9l2ftvL","media":null,"media_id":null,"name":"Sales order PDF","options":"[]","order_id":null,"order_scoped_id":"","purchase_order_id":null,"purchase_order_scoped_id":"","type":"order","updated_at":"2026-10-01T09:00:00+00:00"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":false,"properties":{"created_at":{"format":"date-time","type":"string"},"detail":{"description":"For a document attachment, defaults to its kind, such as `Sales Order/Quote (PDF)`.","type":["string","null"]},"id":{"example":"80qLp4P9l2ftvL","type":"string"},"media":{"additionalProperties":true,"description":"For a `media` or `reference_media` attachment, the file: `id`, `name`, `file_name`, `mime_type`, `size`, a download `url`, a signed `view_url` and more. Null for document attachments.","type":["object","null"]},"media_id":{"type":["string","null"]},"name":{"type":["string","null"]},"options":{"description":"The attachment's options as a JSON-encoded string, not an object: `\"[]\"`, or for job sheets `\"{\\\"show_mockup\\\":true}\"`. `\"null\"` for a `media` or `reference_media` file. Decode it before use.","type":["string","null"]},"order_id":{"type":["string","null"]},"order_scoped_id":{"type":["string","integer","null"]},"purchase_order_id":{"type":["string","null"]},"purchase_order_scoped_id":{"type":["string","integer","null"]},"type":{"example":"order","type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","order_id","order_scoped_id","purchase_order_id","purchase_order_scoped_id","name","detail","media_id","options","created_at","updated_at","media"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List a template's attachments","tags":["Message template attachments"],"x-yoprint-docs":{"group":"Team settings","permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v2_public_message_template_internal_attachment_store","v2_public_message_template_show"]}},"post":{"description":"Adds an attachment to a message template. Document attachments, such as `order`, are made fresh from the record each time the template is sent; without a `name` they get a default such as `Details {{order_number}}.pdf`. A `media` attachment is a file you uploaded, by its `media_id`.\n\nAttachment `type` values: `order` (the sales order or quote PDF), `order_compact` (its compact PDF), `so_jobs_with_mockup` and `so_jobs_without_mockup` (job sheets), `so_invoices` and `so_compact_invoices` (its invoices), `purchase_order` (the purchase order PDF), and `media` or `reference_media` (a file, by `media_id`). A template accepts only the values in its `supported_attachments`: purchase order templates take `purchase_order`, `media` and `reference_media`.","operationId":"v2_public_message_template_internal_attachment_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message template. Its hash id from an earlier answer; there is no unique key for it.","example":"DVubREua5aJkwh","in":"path","name":"hash_id","required":true,"schema":{"example":"DVubREua5aJkwh","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"document":{"summary":"The sales order PDF","value":{"name":"Sales order PDF","type":"order"}},"file":{"summary":"An uploaded file","value":{"media_id":"ckQVnRGLx1GTIn","name":"Care instructions","type":"media"}}},"schema":{"additionalProperties":false,"properties":{"detail":{"type":"string"},"media_id":{"description":"Required for `media`: the id of a file you uploaded. `reference_media` also needs an existing file.","type":"string"},"name":{"description":"A name for the attachment.","type":"string"},"options":{"additionalProperties":true,"properties":{"show_mockup":{"description":"For `so_jobs_with_mockup` and `so_jobs_without_mockup`: `true` puts each job's mockup pages in the job sheets, `false` leaves them out. It overrides the type's own choice. Text such as `\"true\"` or `\"off\"` is accepted too; any other value is refused with 422 `validation_failed`. Other types ignore it.","type":"boolean"}},"type":"object"},"type":{"description":"What to attach. Must be in the template's `supported_attachments`.","enum":["order","order_compact","so_jobs_with_mockup","so_jobs_without_mockup","so_invoices","so_compact_invoices","purchase_order","media","reference_media"],"type":"string"}},"required":["type"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-10-01T09:00:00+00:00","detail":"Sales Order/Quote (PDF)","id":"80qLp4P9l2ftvL","media":null,"media_id":null,"name":"Sales order PDF","options":"[]","order_id":null,"order_scoped_id":"","purchase_order_id":null,"purchase_order_scoped_id":"","type":"order","updated_at":"2026-10-01T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"created_at":{"format":"date-time","type":"string"},"detail":{"description":"For a document attachment, defaults to its kind, such as `Sales Order/Quote (PDF)`.","type":["string","null"]},"id":{"example":"80qLp4P9l2ftvL","type":"string"},"media":{"additionalProperties":true,"description":"For a `media` or `reference_media` attachment, the file: `id`, `name`, `file_name`, `mime_type`, `size`, a download `url`, a signed `view_url` and more. Null for document attachments.","type":["object","null"]},"media_id":{"type":["string","null"]},"name":{"type":["string","null"]},"options":{"description":"The attachment's options as a JSON-encoded string, not an object: `\"[]\"`, or for job sheets `\"{\\\"show_mockup\\\":true}\"`. `\"null\"` for a `media` or `reference_media` file. Decode it before use.","type":["string","null"]},"order_id":{"type":["string","null"]},"order_scoped_id":{"type":["string","integer","null"]},"purchase_order_id":{"type":["string","null"]},"purchase_order_scoped_id":{"type":["string","integer","null"]},"type":{"example":"order","type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","order_id","order_scoped_id","purchase_order_id","purchase_order_scoped_id","name","detail","media_id","options","created_at","updated_at","media"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add an attachment to a template","tags":["Message template attachments"],"x-yoprint-docs":{"errors":[{"fix":"Use a template id from the list.","status":404,"when":"No template of your team has this id. `error.code` is null; `error.message` names the record type."},{"fix":"Use a type from the template's `supported_attachments` and an uploaded file's id.","status":422,"when":"`type` is missing, or `media_id` is missing for `media` (`validation_failed`); the template doesn't support this `type` (`type_not_supported`); or the file is not found (`media_not_found`)."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v2_public_message_template_internal_attachment_index"]}}},"/v2/api/store/{team_slug}/setting/message_template/{hash_id}/internal_attachment/{id}":{"delete":{"description":"Removes an attachment from a message template; later messages from it are sent without it. **For a file attachment (`media` or `reference_media`), the file its `media_id` names is deleted too**, even when it belongs to another record.","operationId":"v2_public_message_template_internal_attachment_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message template. Its hash id from an earlier answer; there is no unique key for it.","example":"DVubREua5aJkwh","in":"path","name":"hash_id","required":true,"schema":{"example":"DVubREua5aJkwh","type":"string"}},{"description":"The attachment, from the template's attachment list. Its hash id from an earlier answer; there is no unique key for it.","example":"80qLp4P9l2ftvL","in":"path","name":"id","required":true,"schema":{"example":"80qLp4P9l2ftvL","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove a template attachment","tags":["Message template attachments"],"x-yoprint-docs":{"errors":[{"fix":"Use ids from the attachment list.","status":404,"when":"The template or the attachment is not found."},{"fix":"Read the attachments again, then retry.","status":500,"when":"The delete failed: `error.code` `delete_fail`."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v2_public_message_template_internal_attachment_index"],"side_effects":["Deletes the file a `media` or `reference_media` attachment names."]}},"get":{"description":"Returns one attachment of a message template. The path takes the template's id, then the attachment's id.","operationId":"v2_public_message_template_internal_attachment_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message template. Its hash id from an earlier answer; there is no unique key for it.","example":"DVubREua5aJkwh","in":"path","name":"hash_id","required":true,"schema":{"example":"DVubREua5aJkwh","type":"string"}},{"description":"The attachment, from the template's attachment list. Its hash id from an earlier answer; there is no unique key for it.","example":"80qLp4P9l2ftvL","in":"path","name":"id","required":true,"schema":{"example":"80qLp4P9l2ftvL","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-10-01T09:00:00+00:00","detail":"Sales Order/Quote (PDF)","id":"80qLp4P9l2ftvL","media":null,"media_id":null,"name":"Sales order PDF","options":"[]","order_id":null,"order_scoped_id":"","purchase_order_id":null,"purchase_order_scoped_id":"","type":"order","updated_at":"2026-10-01T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"created_at":{"format":"date-time","type":"string"},"detail":{"description":"For a document attachment, defaults to its kind, such as `Sales Order/Quote (PDF)`.","type":["string","null"]},"id":{"example":"80qLp4P9l2ftvL","type":"string"},"media":{"additionalProperties":true,"description":"For a `media` or `reference_media` attachment, the file: `id`, `name`, `file_name`, `mime_type`, `size`, a download `url`, a signed `view_url` and more. Null for document attachments.","type":["object","null"]},"media_id":{"type":["string","null"]},"name":{"type":["string","null"]},"options":{"description":"The attachment's options as a JSON-encoded string, not an object: `\"[]\"`, or for job sheets `\"{\\\"show_mockup\\\":true}\"`. `\"null\"` for a `media` or `reference_media` file. Decode it before use.","type":["string","null"]},"order_id":{"type":["string","null"]},"order_scoped_id":{"type":["string","integer","null"]},"purchase_order_id":{"type":["string","null"]},"purchase_order_scoped_id":{"type":["string","integer","null"]},"type":{"example":"order","type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","order_id","order_scoped_id","purchase_order_id","purchase_order_scoped_id","name","detail","media_id","options","created_at","updated_at","media"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a template attachment","tags":["Message template attachments"],"x-yoprint-docs":{"group":"Team settings","permission":"Any member of the team, whatever their role. This is wider than the web app, whose Settings pages need Manage Settings: on the API only changes need it.","related":["v2_public_message_template_internal_attachment_update_patch"]}},"patch":{"description":"Use PUT to change a template attachment. PATCH always fails with a server error.","operationId":"v2_public_message_template_internal_attachment_update_patch","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message template. Its hash id from an earlier answer; there is no unique key for it.","example":"DVubREua5aJkwh","in":"path","name":"hash_id","required":true,"schema":{"example":"DVubREua5aJkwh","type":"string"}},{"description":"The attachment, from the template's attachment list. Its hash id from an earlier answer; there is no unique key for it.","example":"80qLp4P9l2ftvL","in":"path","name":"id","required":true,"schema":{"example":"80qLp4P9l2ftvL","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"name":"Order PDF"},"schema":{"additionalProperties":false,"properties":{"detail":{"type":"string"},"name":{"type":"string"},"options":{"additionalProperties":true,"properties":{"show_mockup":{"description":"For `so_jobs_with_mockup` and `so_jobs_without_mockup`: `true` puts each job's mockup pages in the job sheets, `false` leaves them out. It overrides the type's own choice. Text such as `\"true\"` or `\"off\"` is accepted too; any other value is refused with 422 `validation_failed`. Other types ignore it.","type":"boolean"}},"type":"object"}},"type":"object"}}},"required":true},"responses":{"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change a template attachment with PATCH","tags":["Message template attachments"],"x-yoprint-docs":{"errors":[{"fix":"Use PUT.","status":500,"when":"You called it with PATCH. The body is `{\"message\": \"Server Error\"}`, without the error envelope."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v2_public_message_template_internal_attachment_show"]}},"put":{"description":"Changes an attachment's `name`, `detail` or `options`. `options` are merged into the saved ones. The type and file can't change: delete it and add a new one.\n\nUse PUT. PATCH has no rules and fails with 500.","operationId":"v2_public_message_template_internal_attachment_update_put","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The message template. Its hash id from an earlier answer; there is no unique key for it.","example":"DVubREua5aJkwh","in":"path","name":"hash_id","required":true,"schema":{"example":"DVubREua5aJkwh","type":"string"}},{"description":"The attachment, from the template's attachment list. Its hash id from an earlier answer; there is no unique key for it.","example":"80qLp4P9l2ftvL","in":"path","name":"id","required":true,"schema":{"example":"80qLp4P9l2ftvL","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"name":"Order PDF"},"schema":{"additionalProperties":false,"properties":{"detail":{"type":"string"},"name":{"type":"string"},"options":{"additionalProperties":true,"properties":{"show_mockup":{"description":"For `so_jobs_with_mockup` and `so_jobs_without_mockup`: `true` puts each job's mockup pages in the job sheets, `false` leaves them out. It overrides the type's own choice. Text such as `\"true\"` or `\"off\"` is accepted too; any other value is refused with 422 `validation_failed`. Other types ignore it.","type":"boolean"}},"type":"object"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-10-01T09:00:00+00:00","detail":"Sales Order/Quote (PDF)","id":"80qLp4P9l2ftvL","media":null,"media_id":null,"name":"Order PDF","options":"[]","order_id":null,"order_scoped_id":"","purchase_order_id":null,"purchase_order_scoped_id":"","type":"order","updated_at":"2026-11-03T10:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":false,"properties":{"created_at":{"format":"date-time","type":"string"},"detail":{"description":"For a document attachment, defaults to its kind, such as `Sales Order/Quote (PDF)`.","type":["string","null"]},"id":{"example":"80qLp4P9l2ftvL","type":"string"},"media":{"additionalProperties":true,"description":"For a `media` or `reference_media` attachment, the file: `id`, `name`, `file_name`, `mime_type`, `size`, a download `url`, a signed `view_url` and more. Null for document attachments.","type":["object","null"]},"media_id":{"type":["string","null"]},"name":{"type":["string","null"]},"options":{"description":"The attachment's options as a JSON-encoded string, not an object: `\"[]\"`, or for job sheets `\"{\\\"show_mockup\\\":true}\"`. `\"null\"` for a `media` or `reference_media` file. Decode it before use.","type":["string","null"]},"order_id":{"type":["string","null"]},"order_scoped_id":{"type":["string","integer","null"]},"purchase_order_id":{"type":["string","null"]},"purchase_order_scoped_id":{"type":["string","integer","null"]},"type":{"example":"order","type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","order_id","order_scoped_id","purchase_order_id","purchase_order_scoped_id","name","detail","media_id","options","created_at","updated_at","media"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a template attachment","tags":["Message template attachments"],"x-yoprint-docs":{"errors":[{"fix":"Use ids from the attachment list.","status":404,"when":"The template or the attachment is not found."},{"fix":"Use the key of a member whose role has Manage Settings, or the owner's.","status":403,"when":"Your role lacks Manage Settings. The body is `{\"message\": \"Insufficient Permission\"}`, without the error envelope."}],"group":"Team settings","permission":"Needs the Manage Settings permission. The team owner always has it.","related":["v2_public_message_template_internal_attachment_show"]}}},"/v2/api/store/{team_slug}/v2/carrier_account/goshippo":{"post":{"description":"Lists the carrier accounts in your team's connected Shippo account, with their service levels. Read-only: nothing is bought or saved.\n\nUse an account's `object_id` in `carrier_accounts` when you get rates, to rate only those accounts. A service level `token` (for example `usps_priority`) matches `rates[].servicelevel.token`.\n\nThe reply is a trimmed copy of Shippo's list, without the usual `success`/`data` envelope: `results`, `messages` and `is_live_mode_warning_required` (always false in production, where every call is live).","operationId":"v2_public_shipment_carrier_goshippo","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"carrier":"ups","results":25},"schema":{"properties":{"account_id":{"description":"Only the account with this carrier account number.","maxLength":255,"type":"string"},"carrier":{"description":"Only this carrier, for example `usps` or `ups`. Lower-cased for you.","maxLength":100,"type":"string"},"page":{"description":"Shippo page number.","minimum":1,"type":"integer"},"results":{"description":"Accounts per page.","maximum":100,"minimum":1,"type":"integer"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"is_live_mode_warning_required":false,"messages":[],"results":[{"account_id":"A1B2C3","active":true,"carrier":"ups","carrier_name":"UPS","is_shippo_account":false,"object_id":"carrier_0001","object_owner":"alex@example.com","service_levels":[{"name":"Ground","token":"ups_ground"}]}]},"schema":{"properties":{"is_live_mode_warning_required":{"type":"boolean"},"messages":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"results":{"items":{"additionalProperties":true,"properties":{"account_id":{"type":"string"},"active":{"type":"boolean"},"carrier":{"type":"string"},"carrier_name":{"type":"string"},"is_shippo_account":{"description":"True for Shippo's own discounted account; false for your own carrier account.","type":"boolean"},"object_id":{"description":"Send in `carrier_accounts` when you get rates.","type":"string"},"object_owner":{"description":"The Shippo user who owns the account, as Shippo sends it (empty when Shippo sends none).","type":"string"},"service_levels":{"items":{"properties":{"name":{"type":"string"},"token":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"type":"array"}},"type":"object"}}},"description":"A trimmed copy of Shippo's carrier account list (`results`, `messages`, `is_live_mode_warning_required`), without the YoPrint envelope."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List Shippo carrier accounts","tags":["Shipping rates and estimates"],"x-yoprint-docs":{"errors":[{"fix":"Connect Shippo in the web app first.","status":422,"when":"Shippo isn't connected or is disabled (`goshippo_not_enabled`)."},{"fix":"Fix the field named in the error.","status":422,"when":"`results` is above 100, or a field has the wrong type."},{"fix":"Check the addresses, parcels and ids, then retry once. Do not loop.","status":500,"when":"Shippo refused the request or could not be reached. Shippo errors are not translated into 4xx replies."}],"group":"Shipping","notes":["Shippo's paging fields (`next`, `previous`, `count`) are not passed on. Page with `page` and `results` until `results` comes back short.","Any team member can read the carrier account numbers in `account_id` and the owner in `object_owner`."],"permission":"Any member of the team. No sales order permission is checked. Needs a connected, enabled Shippo integration (Settings > Integrations > Shippo Shipping). Without one the reply is 422 `goshippo_not_enabled` with no message.","related":["v2_public_shipment_rate_goshippo"],"side_effects":["Calls Shippo (read-only; it buys nothing)."]}}},"/v2/api/store/{team_slug}/v2/invoice/filter":{"post":{"description":"Returns one page of your team's invoices that match the filters, newest first unless you sort. Invoices of sales orders and of quotes are both included (filter on `quote`); invoices of deleted, draft or unsaved orders are not.\n\nEach filter needs `key`, `operator` and `value`, and every filter must match. A filter that breaks the table is a 422 whose message is the bare rule name `validation.filter_rule`.\n\n| `key` | `operator` | `value` |\n| --- | --- | --- |\n| `payment_status` | `eq` | `paid` (paid amount at least the total, total above 0), `unpaid` (total above the paid amount, total above 0), or `overdue` (unpaid, the order has a full payment due date set, and that date is before today in UTC). Invoices with a zero total or orders without a due date never match `overdue`. |\n| `quote` | `eq` | `true` for invoices of quotes, `false` for invoices of sales orders. |\n| `order_status_id` | `in`, `nin` | Sales order status hash ids. |\n| `order_customer_id` | `in`, `nin` | Customer hash ids. |\n| `external_type` | `in`, `nin` | `shopify`, `native`. |\n| `order_issue_date`, `order_cust_due_date`, `order_ship_due_date`, `deposit_due`, `full_amount_due` | `eq`, `gte`, `lte` | A whole number of days from today in UTC: 0 today, 7 a week ahead, -7 a week ago. Compared by date. |\n| `created_at` | `gte`, `lte` | Days from today, as above, but compared with the creation time: `gte` N includes that day, `lte` N stops at its first second, and `eq` matches almost nothing. |\n\n`sort` is an array, but only its first entry is used. The page size is the team's list page size setting (50 unless changed); send `page` for later pages. `count_only: true` returns just `pagination` with empty `data`; `with: [\"items\"]` adds each invoice's lines.\n\nThis list covers invoices made in the current invoice system.","operationId":"v2_public_invoice_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"filters":[{"key":"payment_status","operator":"eq","value":"unpaid"},{"key":"quote","operator":"eq","value":false},{"key":"full_amount_due","operator":"lte","value":0}],"page":1,"sort":[{"direction":"asc","key":"full_amount_due"}]},"schema":{"properties":{"count_only":{"default":false,"description":"Return only the count in `pagination`.","type":"boolean"},"filters":{"items":{"properties":{"key":{"enum":["payment_status","quote","order_status_id","order_customer_id","external_type","order_issue_date","order_cust_due_date","order_ship_due_date","deposit_due","full_amount_due","created_at"],"type":"string"},"operator":{"enum":["eq","neq","gte","lte","in","nin"],"type":"string"},"value":{"items":{"type":"string"},"type":["string","number","boolean","array"]}},"required":["key","operator","value"],"type":"object"},"type":"array"},"page":{"default":1,"minimum":1,"type":"integer"},"sort":{"description":"Only the first entry is used. Default: `created_at` `desc`.","items":{"properties":{"direction":{"enum":["asc","desc"],"type":"string"},"key":{"description":"`scoped_id` sorts as text.","enum":["order_id","scoped_id","created_at","order_issue_date","full_amount_due","deposit_due","order_cust_due_date","order_ship_due_date","order_status_id"],"type":"string"}},"required":["key","direction"],"type":"object"},"type":"array"},"with":{"description":"Add each invoice's lines.","items":{"enum":["items"],"type":"string"},"type":"array"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"auto_invoice_managed":false,"bill_to_status":"okay","billing_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"billing_address_id":"117KfwwfreX15N","calc_deposit_total":169880,"cart_item_subtotal":{"dp":4,"value":3150000},"created_at":"2026-11-03T15:00:00+00:00","credit_card_surcharge":{"dp":4,"value":0},"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"deposit_due":"2026-11-05T00:00:00+00:00","deposit_required":true,"discount_subtotal":{"dp":4,"value":0},"external_type":null,"from_legacy":false,"full_amount_due":"2026-11-20T00:00:00+00:00","id":"cBRpSf5nw6upt5","is_external":false,"is_paid":false,"is_valid":true,"issue_date":"2026-11-03T00:00:00+00:00","lock_version":1730000000000000,"order":{"id":"sFbALVSYD55eXe","scoped_id":"SO1001"},"order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","paid_amount":100000,"pdf_url":[{"description":"Invoice pdf","label":"Invoice","object_type":"invoice","url":"https://example.com/pdf/invoice.pdf"}],"scoped_id":"1001","ship_to_status":"okay","shipment_subtotal":{"dp":4,"value":150000},"shipment_tax_subtotal":{"dp":4,"value":0},"shipping_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"shipping_address_id":"117KfwwfreX15N","tax_subtotal":{"dp":4,"value":247500},"total":{"dp":4,"value":3397500},"version":2}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"An invoice. Amounts are decimal pairs at the stored scale (4 decimal places for invoice totals), except `paid_amount` and `calc_deposit_total` (thousandths). The `calc_*` totals are deprecated copies of the decimal-pair ones.","properties":{"auto_invoice_managed":{"description":"YoPrint keeps this invoice in step with the order (Auto Invoice).","type":"boolean"},"bill_to_status":{"description":"How Bill To compares with the order's.","enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"billing_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"billing_address_id":{"description":"Bill To.","example":"117KfwwfreX15N","type":["string","null"]},"calc_delivery_total":{"deprecated":true,"description":"**Deprecated:** use `shipment_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_deposit_total":{"description":"The order's deposit amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `cart_item_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"cart_item_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Billed sales order lines and shipping fees (price × quantity); `shipment_subtotal` is 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 is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Read `dp` every time: it can differ between fields and records."},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"credit_card_surcharge":{"$ref":"#/components/schemas/BigDecimalValue","description":"A 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). Read `dp` every time: it can differ between fields and records."},"customer":{"oneOf":[{"additionalProperties":true,"description":"The customer (the full customer record).","properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":"string"},"name":{"example":"Northwind Apparel","type":"string"}},"type":"object"},{"type":"null"}]},"deposit_due":{"description":"From the order. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"deposit_required":{"description":"From the order.","type":["boolean","integer","null"]},"discount_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Discounts. 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."},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"full_amount_due":{"description":"From the order. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"is_paid":{"description":"Paid amount covers the total (also true for a zero total).","type":"boolean"},"is_valid":{"description":"False when the invoice needs fixing: no lines, lines without a tax line, or a customer that differs from the order's.","type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"lock_version":{"example":1730000000000000,"type":"integer"},"order":{"additionalProperties":true,"description":"The sales order or quote in the v2 order shape: its header fields, with `status` and `assigned_users`, but no `items`.","properties":{"id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"scoped_id":{"example":"SO1001","type":["string","null"]}},"type":"object"},"order_id":{"description":"The sales order or quote it bills.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"order_quote":{"description":"The order is a quote.","type":"boolean"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"paid_amount":{"description":"Allocated payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"pdf_url":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Invoice","type":"string"},"object_type":{"example":"invoice","type":"string"},"url":{"description":"A download link with its own long-lived access token: don't publish it.","example":"https://example.com/pdf/invoice.pdf","type":"string"}},"type":"object"},"type":"array"},"scoped_id":{"description":"The invoice number.","example":"1001","type":["string","null"]},"ship_to_status":{"enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"shipment_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping fees (already in `cart_item_subtotal`). 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."},"shipment_tax_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"The tax on shipping (included in `tax_subtotal`). 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."},"shipping_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"shipping_address_id":{"description":"Ship To.","example":"117KfwwfreX15N","type":["string","null"]},"tax_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Tax. 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."},"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The invoice total. 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."},"version":{"example":2,"type":"integer"}},"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Filter invoices","tags":["Invoices"],"x-yoprint-docs":{"errors":[{"fix":"Check each filter and sort entry against the table.","status":422,"when":"A filter breaks the table (`validation.filter_rule`) or a sort key isn't listed (`validation.filter_sort_rule`)."},{"fix":"Ask the team owner for Manage Sales Orders view access.","status":403,"when":"Your role can't view sales orders."}],"group":"Invoices and payments","permission":"Needs Manage Sales Orders at \"view all\" (every invoice) or \"view assigned\" (invoices of orders you created or are assigned to). Otherwise 403 \"You do not have permission to view this resource\".","related":["v2_public_invoice_show","v1_public_invoice_index","v1_public_invoice_export_pdf"],"rules":["Dates are whole days from today in UTC, never absolute dates; `bt` isn't accepted. The order date keys compare whole days and include day N. `created_at` is compared with the creation time: `gte N` starts at 00:00 UTC of day N and `lte N` stops at 00:00 UTC of day N.","The `quote` filter only supports the `eq` operator. The backend ignores the operator and checks only `value`, so sending `neq` behaves identically to `eq`. Always use `eq` with `true` (for quotes) or `false` (for sales orders)."]}}},"/v2/api/store/{team_slug}/v2/invoice/item/{unique_key}":{"delete":{"description":"Removes one line from an invoice and recalculates it. Returns the action envelope (`DELETED`). Removing a line that is already gone succeeds with `NONE`.","operationId":"v2_public_invoice_item_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The invoice line's `id` (a hash id), as its answers show it. Its unique key (`ordinvitm_...`) also works, but API answers don't include it.","example":"nhsGsn84PyJBvK","in":"path","name":"unique_key","required":true,"schema":{"example":"nhsGsn84PyJBvK","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"action_performed":"DELETED","has_changes":true,"item":{"_meta":{"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000000,"position_hash":"EXAMPLEpositionHash","type":"order_item"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000000,"position":100,"position_hash":"EXAMPLEpositionHash","pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"tax":{"type":"taxable"},"type":"order_item"},"lock_version":{"invoice":{"invoice_item_lock_version":1730000000000000,"invoice_lock_version":1730000000000000},"order":{"invoice_lock_version":1730000000000000,"job_lock_version":1730000000000000,"order_item_lock_version":1730000000000000,"order_lock_version":1730000000000000,"payment_lock_version":1730000000000000,"shipment_lock_version":1730000000000000}},"object_type":"invoice_item"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"What happened, and the line.","properties":{"action_performed":{"description":"`NONE` when nothing changed.","enum":["CREATED","UPDATED","DELETED","NONE"],"type":"string"},"has_changes":{"type":"boolean"},"item":{"additionalProperties":true,"description":"An invoice line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only: `id`, `type`, `invoice_id`, `lock_version`, `from_legacy`, `position_hash`.","type":"object"},"auto_invoice_managed":{"description":"YoPrint manages this line (Auto Invoice).","type":"boolean"},"external_ids":{"description":"Links to external systems; empty for lines made in YoPrint.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The invoice line.","example":"nhsGsn84PyJBvK","type":"string"},"invoice_id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Send it back on Update an invoice line to detect a concurrent change.","example":1730000000000000,"type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"Absent on tax and discount lines. `system` (sales order lines): `_meta.unit_price` is the price copied from the sales order line and `_meta.subtotal` is that price × this line's quantity. `fee` (shipping fees): `product.total` is the fee. Prices come at the stored scale (6 decimal places); `_meta.subtotal` at the combined scale of price × quantity (compacted when large). Always read `dp`.","properties":{"type":{"enum":["system","fee"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details, always an object (with `editable_fields_on_update`); for `order_item`, `parent` describes the sales order line.","type":"object"},"properties":{"additionalProperties":true,"description":"The kind's fields; for `order_item`, `id` is the sales order line. A discount's percentage or amount comes back as `total` (you send it as `rate`).","type":"object"},"type":{"enum":["order_item","shipment_fee","invoice_discount","user_tax","override_tax","auto_tax","invoice_surcharge"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"description":"Absent on tax and discount lines.","properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"tax":{"additionalProperties":true,"description":"Absent 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.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"type":"object"},"type":{"description":"Same as `product.type`.","type":"string"}},"type":"object"},"lock_version":{"additionalProperties":true,"description":"Lock versions after the change.","properties":{"invoice":{"additionalProperties":true,"description":"The invoice's lock versions: `invoice_item_lock_version`, `invoice_lock_version`.","type":"object"},"order":{"additionalProperties":true,"description":"The order's lock versions: `job_lock_version`, `invoice_lock_version`, `order_item_lock_version`, `shipment_lock_version`, `payment_lock_version`, `order_lock_version`.","type":"object"}},"type":"object"},"object_type":{"const":"invoice_item","example":"invoice_item","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove a line from an invoice","tags":["Invoice line items"],"x-yoprint-docs":{"errors":[{"fix":"Change the sales order instead, or turn off Auto Invoice on the invoice in the web app.","status":422,"when":"An Auto Invoice or external line (`validation_error`)."},{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order."},{"fix":"Check the line id.","status":404,"when":"The line isn't your team's."}],"group":"Invoices and payments","permission":"Needs permission to edit the invoice's sales order: the team owner, a role whose Manage Sales Orders permission is \"update all\", or \"update assigned\" when you created the order or are assigned to it, or, on a draft order, its creator when their role can create sales orders. Otherwise 403 `user_is_not_authorized`. Reading needs only team membership.","related":["v2_public_invoice_item_index","v2_public_invoice_item_bulk"],"rules":["On an Auto Invoice invoice you can't remove its sales order lines, shipping fees or discounts (\"You cannot delete order Item for an auto managed invoice\" and similar).","Lines synced from an external system can't be removed: \"Cannot delete external object from API.\""],"side_effects":["Recalculates the invoice: line totals, subtotal, shipping, discounts, tax and total.","Updates the sales order's invoiced totals and each line's invoiced status (not invoiced, partly, fully, or over-invoiced), and automatically redistributes (reallocates) recorded payments across the order's invoices to match updated totals (funds frozen by an open dispute or review stay where they are).","When the team syncs to QuickBooks Online automatically and the order is published, the order is synced again about 3 minutes later (not after a change of `position` only).","Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open. No webhook or email is sent."]}},"get":{"description":"Returns one invoice line: `product` (kind and fields; for `order_item`, `_meta.parent` holds the sales order line), `pricing`, `quantity`, `tax`, `position`, `lock_version` and `auto_invoice_managed`.","operationId":"v2_public_invoice_item_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The invoice line's `id` (a hash id), as its answers show it. Its unique key (`ordinvitm_...`) also works, but API answers don't include it.","example":"nhsGsn84PyJBvK","in":"path","name":"unique_key","required":true,"schema":{"example":"nhsGsn84PyJBvK","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"_meta":{"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000000,"position_hash":"EXAMPLEpositionHash","type":"order_item"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000000,"position":100,"position_hash":"EXAMPLEpositionHash","pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"tax":{"type":"taxable"},"type":"order_item"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"An invoice line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only: `id`, `type`, `invoice_id`, `lock_version`, `from_legacy`, `position_hash`.","type":"object"},"auto_invoice_managed":{"description":"YoPrint manages this line (Auto Invoice).","type":"boolean"},"external_ids":{"description":"Links to external systems; empty for lines made in YoPrint.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The invoice line.","example":"nhsGsn84PyJBvK","type":"string"},"invoice_id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Send it back on Update an invoice line to detect a concurrent change.","example":1730000000000000,"type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"Absent on tax and discount lines. `system` (sales order lines): `_meta.unit_price` is the price copied from the sales order line and `_meta.subtotal` is that price × this line's quantity. `fee` (shipping fees): `product.total` is the fee. Prices come at the stored scale (6 decimal places); `_meta.subtotal` at the combined scale of price × quantity (compacted when large). Always read `dp`.","properties":{"type":{"enum":["system","fee"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details, always an object (with `editable_fields_on_update`); for `order_item`, `parent` describes the sales order line.","type":"object"},"properties":{"additionalProperties":true,"description":"The kind's fields; for `order_item`, `id` is the sales order line. A discount's percentage or amount comes back as `total` (you send it as `rate`).","type":"object"},"type":{"enum":["order_item","shipment_fee","invoice_discount","user_tax","override_tax","auto_tax","invoice_surcharge"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"description":"Absent on tax and discount lines.","properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"tax":{"additionalProperties":true,"description":"Absent 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.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"type":"object"},"type":{"description":"Same as `product.type`.","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get an invoice line","tags":["Invoice line items"],"x-yoprint-docs":{"errors":[{"fix":"Check the line id.","status":404,"when":"The line isn't your team's."}],"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_invoice_item_update","v2_public_invoice_item_destroy"]}},"put":{"description":"Changes one invoice line and recalculates the invoice. Send only what you change; returns the line in an action envelope (`action_performed` `UPDATED`, or `NONE` with `has_changes` false when nothing changed).\n\nWhat you can change:\n\n| Kind | Changeable |\n| --- | --- |\n| `order_item` | `quantity`, `tax.type`, `position`. Not which sales order line it bills. |\n| `shipment_fee` | `name`, `description`, `shipping_taxable`, the `pricing` fee, `position`. |\n| `invoice_discount` | `name`, `description`, `type`, `rate`, `applies_to_shipping`, `position`. |\n| `user_tax` | `id` (switch preset), `description`, `shipping_taxable`, `apply_before_discount`, `refresh_tax_rate`. Always send `properties.id`. When you switch preset or send `refresh_tax_rate`, `shipping_taxable` and `apply_before_discount` are taken from the preset and the values you send are ignored. |\n| `override_tax` | `mode`, `total`, `description`, `shipping_taxable`, `apply_before_discount`. |\n| `auto_tax` | Send the full `properties` again; the rate is fetched again from the provider. |\n\nUpdating an `order_item` line also copies the sales order line's current unit price again. Numbers are `{ value, dp }` pairs: `value` is the number without its decimal point and `dp` the count of decimal places, so 12.50 is `{ \"value\": 1250, \"dp\": 2 }` (or `{ \"value\": 125, \"dp\": 1 }`). `value` is a JSON integer or a digit string, never a float. Quantities take up to 8 decimal places, a discount `rate` 4 and a manual tax `total` 6; more decimals are a 422 `validation_failed`. A shipping fee price is rounded half-up to 6 decimal places (a float `value` there is 422 `amount_out_of_range`). Send very large numbers as strings. Answers send prices at the stored scale (6 decimal places), quantities without trailing zeros, and `_meta.subtotal` (price × quantity) at the combined scale, compacted when it would exceed a safe integer: always read `dp`.","operationId":"v2_public_invoice_item_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The invoice line's `id` (a hash id), as its answers show it. Its unique key (`ordinvitm_...`) also works, but API answers don't include it.","example":"nhsGsn84PyJBvK","in":"path","name":"unique_key","required":true,"schema":{"example":"nhsGsn84PyJBvK","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"discount":{"summary":"Change a discount to 15%","value":{"product":{"properties":{"rate":{"dp":0,"value":15}},"type":"invoice_discount"}}},"quantity":{"summary":"Bill 12 instead","value":{"lock_version":1730000000000000,"quantity":{"total":{"dp":0,"value":12},"type":"unit"}}},"refresh_preset":{"summary":"Reload a tax preset's current rate","value":{"product":{"properties":{"id":"KC48n7qAAfGYMM","refresh_tax_rate":true},"type":"user_tax"}}}},"schema":{"description":"Send only what you change. `product.type`, when sent, must be the line's current kind.","properties":{"lock_version":{"description":"The line's `lock_version` when you read it. If someone saved the line since, the update is refused with 422 `optimistic_lock_conflict`. Omit (or send 0) to skip the check.","type":"integer"},"position":{"description":"Where the line sits on the invoice; lower comes first. Not checked against other lines.","example":100,"type":"integer"},"pricing":{"properties":{"product":{"properties":{"total":{"description":"The fee. Rounded half-up to 6 decimal places.","example":{"dp":2,"value":1500},"properties":{"dp":{"description":"How many of its digits come after the decimal point, 0 to 30.","maximum":30,"minimum":0,"type":"integer"},"value":{"description":"The number without its decimal point, as a JSON integer or a string of digits (an optional leading `-`, no leading zeros, no decimal point).","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"type":{"const":"fee","type":"string"}},"required":["type","product"],"type":"object"},"product":{"properties":{"properties":{"additionalProperties":true,"description":"The fields of that kind you change, as on create. Fields you leave out keep their values.","type":"object"},"type":{"enum":["order_item","shipment_fee","invoice_discount","user_tax","override_tax","auto_tax"],"type":"string"}},"required":["type"],"type":"object"},"quantity":{"description":"How many to bill. Not negative; you may bill more than was ordered.","properties":{"total":{"description":"The quantity, up to 8 decimal places.","example":{"dp":0,"value":24},"properties":{"dp":{"description":"How many of its digits come after the decimal point, 0 to 30.","maximum":30,"minimum":0,"type":"integer"},"value":{"description":"The number without its decimal point, as a JSON integer or a string of digits (an optional leading `-`, no leading zeros, no decimal point).","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type","total"],"type":"object"},"tax":{"description":"Sales order lines (`order_item`) only: whether the line is taxed (default `taxable`). Ignored on other kinds: shipping is taxed by the tax line's `shipping_taxable`.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"required":["type"],"type":"object"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"action_performed":"UPDATED","has_changes":true,"item":{"_meta":{"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000002,"position_hash":"EXAMPLEpositionHash","type":"order_item"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000002,"position":100,"position_hash":"EXAMPLEpositionHash","pricing":{"_meta":{"subtotal":{"dp":0,"value":150},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":12},"type":"unit"},"tax":{"type":"taxable"},"type":"order_item"},"lock_version":{"invoice":{"invoice_item_lock_version":1730000000000000,"invoice_lock_version":1730000000000000},"order":{"invoice_lock_version":1730000000000000,"job_lock_version":1730000000000000,"order_item_lock_version":1730000000000000,"order_lock_version":1730000000000000,"payment_lock_version":1730000000000000,"shipment_lock_version":1730000000000000}},"object_type":"invoice_item"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"What happened, and the line.","properties":{"action_performed":{"description":"`NONE` when nothing changed.","enum":["CREATED","UPDATED","DELETED","NONE"],"type":"string"},"has_changes":{"type":"boolean"},"item":{"additionalProperties":true,"description":"An invoice line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only: `id`, `type`, `invoice_id`, `lock_version`, `from_legacy`, `position_hash`.","type":"object"},"auto_invoice_managed":{"description":"YoPrint manages this line (Auto Invoice).","type":"boolean"},"external_ids":{"description":"Links to external systems; empty for lines made in YoPrint.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The invoice line.","example":"nhsGsn84PyJBvK","type":"string"},"invoice_id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Send it back on Update an invoice line to detect a concurrent change.","example":1730000000000000,"type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"Absent on tax and discount lines. `system` (sales order lines): `_meta.unit_price` is the price copied from the sales order line and `_meta.subtotal` is that price × this line's quantity. `fee` (shipping fees): `product.total` is the fee. Prices come at the stored scale (6 decimal places); `_meta.subtotal` at the combined scale of price × quantity (compacted when large). Always read `dp`.","properties":{"type":{"enum":["system","fee"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details, always an object (with `editable_fields_on_update`); for `order_item`, `parent` describes the sales order line.","type":"object"},"properties":{"additionalProperties":true,"description":"The kind's fields; for `order_item`, `id` is the sales order line. A discount's percentage or amount comes back as `total` (you send it as `rate`).","type":"object"},"type":{"enum":["order_item","shipment_fee","invoice_discount","user_tax","override_tax","auto_tax","invoice_surcharge"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"description":"Absent on tax and discount lines.","properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"tax":{"additionalProperties":true,"description":"Absent 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.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"type":"object"},"type":{"description":"Same as `product.type`.","type":"string"}},"type":"object"},"lock_version":{"additionalProperties":true,"description":"Lock versions after the change.","properties":{"invoice":{"additionalProperties":true,"description":"The invoice's lock versions: `invoice_item_lock_version`, `invoice_lock_version`.","type":"object"},"order":{"additionalProperties":true,"description":"The order's lock versions: `job_lock_version`, `invoice_lock_version`, `order_item_lock_version`, `shipment_lock_version`, `payment_lock_version`, `order_lock_version`.","type":"object"}},"type":"object"},"object_type":{"const":"invoice_item","example":"invoice_item","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update an invoice line","tags":["Invoice line items"],"x-yoprint-docs":{"errors":[{"fix":"Read the line again and resend with its new `lock_version`.","status":422,"when":"Someone saved the line since you read it (`optimistic_lock_conflict`, \"Invoice item was modified in another window. Reload and retry.\")."},{"fix":"Read `error.message` and `error.fields`.","status":422,"when":"Validation or a business rule fails (see Add a line to an invoice)."},{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order."},{"fix":"Check the line id.","status":404,"when":"The line isn't your team's."}],"group":"Invoices and payments","permission":"Needs permission to edit the invoice's sales order: the team owner, a role whose Manage Sales Orders permission is \"update all\", or \"update assigned\" when you created the order or are assigned to it, or, on a draft order, its creator when their role can create sales orders. Otherwise 403 `user_is_not_authorized`. Reading needs only team membership.","related":["v2_public_invoice_item_show","v2_public_invoice_item_bulk"],"rules":["A line's kind can't change: 422 \"Cannot update the product type...\".","On an Auto Invoice invoice (`auto_invoice_managed: true`), YoPrint automatically updates invoice lines to match the sales order's product lines and shipping fees. You cannot add, edit, or delete its order lines, or edit or delete the shipping fees and discounts created by YoPrint. You can still add your own custom discounts and shipping fees; YoPrint always places them after the managed lines regardless of the `position` you send.","Updating a tax line makes it yours: YoPrint stops managing it, even when nothing else changes.","Lines synced from an external system accept only `position`."],"side_effects":["Recalculates the invoice: line totals, subtotal, shipping, discounts, tax and total.","Updates the sales order's invoiced totals and each line's invoiced status (not invoiced, partly, fully, or over-invoiced), and automatically redistributes (reallocates) recorded payments across the order's invoices to match updated totals (funds frozen by an open dispute or review stay where they are).","When the team syncs to QuickBooks Online automatically and the order is published, the order is synced again about 3 minutes later (not after a change of `position` only).","Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open. No webhook or email is sent.","Updating an `auto_tax` line calls the tax provider while you wait."]}}},"/v2/api/store/{team_slug}/v2/invoice/{unique_key}":{"delete":{"description":"Deletes an invoice and its lines. Payments stay recorded on the sales order: the amounts that were allocated to this invoice are automatically redistributed across the order's other invoices, or returned to unallocated balance.\n\nDeleting an invoice that is already deleted succeeds and changes nothing.","operationId":"v2_public_invoice_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"unique_key","required":true,"schema":{"example":"cBRpSf5nw6upt5","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete an invoice","tags":["Invoices"],"x-yoprint-docs":{"errors":[{"fix":"Turn off Auto Invoice, or change the invoice in its source system.","status":422,"when":"An Auto Invoice or external invoice (see rules)."},{"fix":"Check the id.","status":404,"when":"The invoice isn't your team's."}],"group":"Invoices and payments","permission":"Any member of the team. Unlike Update an invoice, this route checks no sales order permission.","related":["v2_public_invoice_show","v2_public_sales_order_invoice_index_for_order"],"rules":["Auto Invoice invoices can't be deleted, nor can an invoice holding lines YoPrint manages: 422 \"You cannot delete an auto managed invoice.\" Turn off Auto Invoice on the order first.","Invoices synced from an external system (Shopify) can't be deleted: 422 \"Cannot delete external object from API.\"","Paid and part-paid invoices can be deleted."],"side_effects":["Removes the invoice's payment allocations and redistributes the order's payments across its remaining invoices.","Recalculates the order's invoiced totals and each line's invoiced status.","May queue a QuickBooks Online sync of the order. Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open."]}},"get":{"description":"An invoice bills some or all of a sales order (or quote). One order can have many invoices; each line of an invoice points at a line of the order, or is a shipping fee, a discount or the tax. Invoices have no status: they are paid or unpaid (`is_paid`) as payments recorded on the order are allocated to them.\n\nReturns the invoice with its lines (`items`), its sales order (`order`), and its billing and shipping addresses. Money comes in two encodings:\n- Decimal pairs (`total`, `cart_item_subtotal`, `shipment_subtotal`, `shipment_tax_subtotal`, `discount_subtotal`, `tax_subtotal`, `credit_card_surcharge`): the amount is `value` ÷ 10^`dp` (`{ \"value\": 3397500, \"dp\": 4 }` is 339.75). Read `dp` every time: invoice totals usually use `dp` 4 and line prices use `dp` 6.\n- Thousandths, an older encoding (`paid_amount`, `calc_deposit_total`): `10000` is 10.00. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/). The `calc_*` totals are deprecated copies of the pairs: use the pairs.\n\n`is_valid` is false when the invoice needs fixing (no lines, lines but no tax line, or a customer that differs from the order's). `pdf_url` holds PDF links that carry their own long-lived access token: don't publish them.\n\nThe path takes the invoice `id` (a hash id).","operationId":"v2_public_invoice_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"unique_key","required":true,"schema":{"example":"cBRpSf5nw6upt5","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"auto_invoice_managed":false,"bill_to_status":"okay","billing_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"billing_address_id":"117KfwwfreX15N","calc_deposit_total":169880,"cart_item_subtotal":{"dp":4,"value":3150000},"created_at":"2026-11-03T15:00:00+00:00","credit_card_surcharge":{"dp":4,"value":0},"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"deposit_due":"2026-11-05T00:00:00+00:00","deposit_required":true,"discount_subtotal":{"dp":4,"value":0},"external_type":null,"from_legacy":false,"full_amount_due":"2026-11-20T00:00:00+00:00","id":"cBRpSf5nw6upt5","is_external":false,"is_paid":false,"is_valid":true,"issue_date":"2026-11-03T00:00:00+00:00","items":[{"_meta":{"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000000,"position_hash":"EXAMPLEpositionHash","type":"order_item"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000000,"position":100,"position_hash":"EXAMPLEpositionHash","pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"tax":{"type":"taxable"},"type":"order_item"},{"_meta":{"from_legacy":false,"id":"E6U0sez7BmPz1t","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000000,"position_hash":"EXAMPLEpositionHash","type":"shipment_fee"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"E6U0sez7BmPz1t","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000000,"position":900,"position_hash":"EXAMPLEpositionHash","pricing":{"product":{"total":{"dp":6,"value":15000000}},"type":"fee"},"product":{"_meta":{"product_hash":"EXAMPLEproductHash","product_name":"Shipping"},"properties":{"description":null,"name":"Shipping","shipping_taxable":0},"type":"shipment_fee"},"quantity":{"total":{"dp":0,"value":1},"type":"unit"},"type":"shipment_fee"},{"_meta":{"from_legacy":false,"id":"WzHB84GM5mzqAw","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000001,"position_hash":"EXAMPLEpositionHash","type":"user_tax"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"WzHB84GM5mzqAw","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000001,"position":2147483647,"position_hash":"EXAMPLEpositionHash","product":{"_meta":{"editable_fields_on_update":["product.properties","product.properties.description","product.properties.id","product.properties.refresh_tax_rate","product.properties.shipping_taxable","product.properties.apply_before_discount"],"product_hash":"EXAMPLEproductHash","product_name":"State sales tax"},"properties":{"apply_before_discount":0,"description":null,"id":"KC48n7qAAfGYMM","invoice_tax_metadata":[{"rate_decimal":3,"rate_value":8250,"tax_id":4021,"tax_last_updated":"2026-10-01T09:00:00.000000Z","tax_name":"State sales tax","tax_type":"simple","total_decimal":2,"total_value":2475}],"name":"State sales tax","rate":{"dp":6,"value":8250000},"shipping_taxable":0,"user_tax_last_updated":"2026-10-01T09:00:00+00:00"},"type":"user_tax"},"type":"user_tax"}],"lock_version":1730000000000000,"order":{"id":"sFbALVSYD55eXe","scoped_id":"SO1001"},"order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","paid_amount":100000,"pdf_url":[{"description":"Invoice pdf","label":"Invoice","object_type":"invoice","url":"https://example.com/pdf/invoice.pdf"}],"scoped_id":"1001","ship_to_status":"okay","shipment_subtotal":{"dp":4,"value":150000},"shipment_tax_subtotal":{"dp":4,"value":0},"shipping_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"shipping_address_id":"117KfwwfreX15N","tax_subtotal":{"dp":4,"value":247500},"total":{"dp":4,"value":3397500},"version":2},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"An invoice. Amounts are decimal pairs at the stored scale (4 decimal places for invoice totals), except `paid_amount` and `calc_deposit_total` (thousandths). The `calc_*` totals are deprecated copies of the decimal-pair ones.","properties":{"auto_invoice_managed":{"description":"YoPrint keeps this invoice in step with the order (Auto Invoice).","type":"boolean"},"bill_to_status":{"description":"How Bill To compares with the order's.","enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"billing_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"billing_address_id":{"description":"Bill To.","example":"117KfwwfreX15N","type":["string","null"]},"calc_delivery_total":{"deprecated":true,"description":"**Deprecated:** use `shipment_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_deposit_total":{"description":"The order's deposit amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `cart_item_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"cart_item_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Billed sales order lines and shipping fees (price × quantity); `shipment_subtotal` is 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 is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Read `dp` every time: it can differ between fields and records."},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"credit_card_surcharge":{"$ref":"#/components/schemas/BigDecimalValue","description":"A 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). Read `dp` every time: it can differ between fields and records."},"customer":{"oneOf":[{"additionalProperties":true,"description":"The customer (the full customer record).","properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":"string"},"name":{"example":"Northwind Apparel","type":"string"}},"type":"object"},{"type":"null"}]},"deposit_due":{"description":"From the order. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"deposit_required":{"description":"From the order.","type":["boolean","integer","null"]},"discount_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Discounts. 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."},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"full_amount_due":{"description":"From the order. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"is_paid":{"description":"Paid amount covers the total (also true for a zero total).","type":"boolean"},"is_valid":{"description":"False when the invoice needs fixing: no lines, lines without a tax line, or a customer that differs from the order's.","type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"items":{"description":"The lines. Sort by `position`.","items":{"additionalProperties":true,"description":"An invoice line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only: `id`, `type`, `invoice_id`, `lock_version`, `from_legacy`, `position_hash`.","type":"object"},"auto_invoice_managed":{"description":"YoPrint manages this line (Auto Invoice).","type":"boolean"},"external_ids":{"description":"Links to external systems; empty for lines made in YoPrint.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The invoice line.","example":"nhsGsn84PyJBvK","type":"string"},"invoice_id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Send it back on Update an invoice line to detect a concurrent change.","example":1730000000000000,"type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"Absent on tax and discount lines. `system` (sales order lines): `_meta.unit_price` is the price copied from the sales order line and `_meta.subtotal` is that price × this line's quantity. `fee` (shipping fees): `product.total` is the fee. Prices come at the stored scale (6 decimal places); `_meta.subtotal` at the combined scale of price × quantity (compacted when large). Always read `dp`.","properties":{"type":{"enum":["system","fee"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details, always an object (with `editable_fields_on_update`); for `order_item`, `parent` describes the sales order line.","type":"object"},"properties":{"additionalProperties":true,"description":"The kind's fields; for `order_item`, `id` is the sales order line. A discount's percentage or amount comes back as `total` (you send it as `rate`).","type":"object"},"type":{"enum":["order_item","shipment_fee","invoice_discount","user_tax","override_tax","auto_tax","invoice_surcharge"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"description":"Absent on tax and discount lines.","properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"tax":{"additionalProperties":true,"description":"Absent 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.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"type":"object"},"type":{"description":"Same as `product.type`.","type":"string"}},"type":"object"},"type":"array"},"lock_version":{"example":1730000000000000,"type":"integer"},"order":{"additionalProperties":true,"description":"The sales order or quote in the v2 order shape: its header fields, with `status` and `assigned_users`, but no `items`.","properties":{"id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"scoped_id":{"example":"SO1001","type":["string","null"]}},"type":"object"},"order_id":{"description":"The sales order or quote it bills.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"order_quote":{"description":"The order is a quote.","type":"boolean"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"paid_amount":{"description":"Allocated payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"pdf_url":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Invoice","type":"string"},"object_type":{"example":"invoice","type":"string"},"url":{"description":"A download link with its own long-lived access token: don't publish it.","example":"https://example.com/pdf/invoice.pdf","type":"string"}},"type":"object"},"type":"array"},"scoped_id":{"description":"The invoice number.","example":"1001","type":["string","null"]},"ship_to_status":{"enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"shipment_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping fees (already in `cart_item_subtotal`). 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."},"shipment_tax_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"The tax on shipping (included in `tax_subtotal`). 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."},"shipping_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"shipping_address_id":{"description":"Ship To.","example":"117KfwwfreX15N","type":["string","null"]},"tax_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Tax. 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."},"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The invoice total. 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."},"version":{"example":2,"type":"integer"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get an invoice","tags":["Invoices"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from Filter invoices or the order's invoice list.","status":404,"when":"The invoice isn't your team's, or was deleted."}],"group":"Invoices and payments","notes":["Send the header `X-Yoprint-Decimal-Format: exact-v1` so large amounts come back exactly (as digit strings when needed)."],"permission":"Any member of the team.","related":["v2_public_invoice_update","v2_public_invoice_item_index","v2_public_sales_order_invoice_index_for_order","v2_public_invoice_filter"]}},"put":{"description":"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.\n\n- `item_actions` adds, 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; a `delete` of the tax line removes it (except on Auto Invoice invoices).\n- `tax_selection` sets, changes or removes the one tax line, as in Change the tax on an invoice.\n- `resort_items: true` spaces out the line positions again, keeping their order.\n\nReturns the invoice; its `items` are included when you sent `item_actions`, `tax_selection` or `resort_items`.\n\nAddress 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).","operationId":"v2_public_invoice_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"unique_key","required":true,"schema":{"example":"cBRpSf5nw6upt5","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"issue_date":"2026-11-03T00:00:00Z","item_actions":[{"action":"create","bid":"row-1","payload":{"product":{"type":"order_item","properties":{"id":"ZJTJ2uF5dMiArL"}},"quantity":{"type":"unit","total":{"value":24,"dp":0}},"position":100}}],"resort_items":false,"tax_selection":{"desired_tax":{"properties":{"id":"KC48n7qAAfGYMM"},"type":"user_tax"},"expected_tax":null}},"schema":{"properties":{"billing_address_id":{"description":"Bill To address hash id. Null clears it.","type":["string","null"]},"issue_date":{"description":"The issue date (ISO 8601).","format":"date-time","type":"string"},"item_actions":{"description":"Line changes, applied in the same save. Tax lines can't be created or updated here (use `tax_selection`).","items":{"properties":{"action":{"enum":["update","create","delete"],"type":"string"},"bid":{"description":"Your label for this row, echoed in errors.","type":"string"},"cart_item_id":{"description":"The invoice line. Required for `update` and `delete`.","example":"V4keXwwxMQyXw7","type":"string"},"payload":{"additionalProperties":true,"description":"Required for `create` and `update`: the line body, as in Add a line to an invoice or Update an invoice line.","type":"object"}},"required":["bid","action"],"type":"object"},"type":"array"},"resort_items":{"description":"`true` re-spaces line positions, keeping the current order. Not allowed on Auto Invoice invoices.","type":"boolean"},"scoped_id":{"description":"The invoice number, as a string. Not checked for duplicates.","type":"string"},"shipping_address_id":{"description":"Ship To address hash id. Null clears it.","type":["string","null"]},"tax_selection":{"description":"Set, change or remove the invoice's one tax line. Send both keys; either may be null.","properties":{"desired_tax":{"description":"The tax you want, or null to remove the tax line.","properties":{"properties":{"additionalProperties":true,"description":"The fields of that kind, as for an invoice line of that `product.type`: `auto_tax` takes `engine` `us`, `from`, `to` and `rate`; `user_tax` takes the preset `id`; `override_tax` takes `mode` and `total`.","type":"object"},"type":{"description":"`auto_tax` (US Auto Tax), `user_tax` (one of your tax presets) or `override_tax` (set by hand).","enum":["auto_tax","user_tax","override_tax"],"type":"string"}},"type":["object","null"]},"expected_tax":{"description":"The tax line you think is there now: its `id` and `lock_version` from the invoice's items, or null when it has none. If it doesn't match, nothing changes (422 `invoice_tax_conflict`).","properties":{"id":{"description":"The current tax line.","example":"V4keXwwxMQyXw7","type":"string"},"lock_version":{"description":"That line's `lock_version`.","example":1730000000000000,"minimum":0,"type":"integer"}},"type":["object","null"]}},"required":["expected_tax","desired_tax"],"type":"object"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"auto_invoice_managed":false,"bill_to_status":"okay","billing_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"billing_address_id":"117KfwwfreX15N","calc_deposit_total":169880,"cart_item_subtotal":{"dp":4,"value":3150000},"created_at":"2026-11-03T15:00:00+00:00","credit_card_surcharge":{"dp":4,"value":0},"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"deposit_due":"2026-11-05T00:00:00+00:00","deposit_required":true,"discount_subtotal":{"dp":4,"value":0},"external_type":null,"from_legacy":false,"full_amount_due":"2026-11-20T00:00:00+00:00","id":"cBRpSf5nw6upt5","is_external":false,"is_paid":false,"is_valid":true,"issue_date":"2026-11-03T00:00:00+00:00","items":[{"_meta":{"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000000,"position_hash":"EXAMPLEpositionHash","type":"order_item"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000000,"position":100,"position_hash":"EXAMPLEpositionHash","pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"tax":{"type":"taxable"},"type":"order_item"},{"_meta":{"from_legacy":false,"id":"E6U0sez7BmPz1t","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000000,"position_hash":"EXAMPLEpositionHash","type":"shipment_fee"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"E6U0sez7BmPz1t","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000000,"position":900,"position_hash":"EXAMPLEpositionHash","pricing":{"product":{"total":{"dp":6,"value":15000000}},"type":"fee"},"product":{"_meta":{"product_hash":"EXAMPLEproductHash","product_name":"Shipping"},"properties":{"description":null,"name":"Shipping","shipping_taxable":0},"type":"shipment_fee"},"quantity":{"total":{"dp":0,"value":1},"type":"unit"},"type":"shipment_fee"},{"_meta":{"from_legacy":false,"id":"WzHB84GM5mzqAw","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000001,"position_hash":"EXAMPLEpositionHash","type":"user_tax"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"WzHB84GM5mzqAw","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000001,"position":2147483647,"position_hash":"EXAMPLEpositionHash","product":{"_meta":{"editable_fields_on_update":["product.properties","product.properties.description","product.properties.id","product.properties.refresh_tax_rate","product.properties.shipping_taxable","product.properties.apply_before_discount"],"product_hash":"EXAMPLEproductHash","product_name":"State sales tax"},"properties":{"apply_before_discount":0,"description":null,"id":"KC48n7qAAfGYMM","invoice_tax_metadata":[{"rate_decimal":3,"rate_value":8250,"tax_id":4021,"tax_last_updated":"2026-10-01T09:00:00.000000Z","tax_name":"State sales tax","tax_type":"simple","total_decimal":2,"total_value":2475}],"name":"State sales tax","rate":{"dp":6,"value":8250000},"shipping_taxable":0,"user_tax_last_updated":"2026-10-01T09:00:00+00:00"},"type":"user_tax"},"type":"user_tax"}],"lock_version":1730000000000000,"order":{"id":"sFbALVSYD55eXe","scoped_id":"SO1001"},"order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","paid_amount":100000,"pdf_url":[{"description":"Invoice pdf","label":"Invoice","object_type":"invoice","url":"https://example.com/pdf/invoice.pdf"}],"scoped_id":"1001","ship_to_status":"okay","shipment_subtotal":{"dp":4,"value":150000},"shipment_tax_subtotal":{"dp":4,"value":0},"shipping_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"shipping_address_id":"117KfwwfreX15N","tax_subtotal":{"dp":4,"value":247500},"total":{"dp":4,"value":3397500},"version":2},"status":200,"success":true},"schema":{"properties":{"data":{"allOf":[{"$ref":"#/components/schemas/Invoice"},{"additionalProperties":true,"description":"An invoice. Amounts are decimal pairs at the stored scale (4 decimal places for invoice totals), except `paid_amount` and `calc_deposit_total` (thousandths). The `calc_*` totals are deprecated copies of the decimal-pair ones.","properties":{"auto_invoice_managed":{"description":"YoPrint keeps this invoice in step with the order (Auto Invoice).","type":"boolean"},"bill_to_status":{"description":"How Bill To compares with the order's.","enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"billing_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"billing_address_id":{"description":"Bill To.","example":"117KfwwfreX15N","type":["string","null"]},"calc_delivery_total":{"deprecated":true,"description":"**Deprecated:** use `shipment_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_deposit_total":{"description":"The order's deposit amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `cart_item_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"cart_item_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Billed sales order lines and shipping fees (price × quantity); `shipment_subtotal` is 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 is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Read `dp` every time: it can differ between fields and records."},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"credit_card_surcharge":{"$ref":"#/components/schemas/BigDecimalValue","description":"A 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). Read `dp` every time: it can differ between fields and records."},"customer":{"oneOf":[{"additionalProperties":true,"description":"The customer (the full customer record).","properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":"string"},"name":{"example":"Northwind Apparel","type":"string"}},"type":"object"},{"type":"null"}]},"deposit_due":{"description":"From the order. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"deposit_required":{"description":"From the order.","type":["boolean","integer","null"]},"discount_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Discounts. 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."},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"full_amount_due":{"description":"From the order. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"is_paid":{"description":"Paid amount covers the total (also true for a zero total).","type":"boolean"},"is_valid":{"description":"False when the invoice needs fixing: no lines, lines without a tax line, or a customer that differs from the order's.","type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"items":{"description":"The lines. Sort by `position`.","items":{"additionalProperties":true,"description":"An invoice line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only: `id`, `type`, `invoice_id`, `lock_version`, `from_legacy`, `position_hash`.","type":"object"},"auto_invoice_managed":{"description":"YoPrint manages this line (Auto Invoice).","type":"boolean"},"external_ids":{"description":"Links to external systems; empty for lines made in YoPrint.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The invoice line.","example":"nhsGsn84PyJBvK","type":"string"},"invoice_id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Send it back on Update an invoice line to detect a concurrent change.","example":1730000000000000,"type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"Absent on tax and discount lines. `system` (sales order lines): `_meta.unit_price` is the price copied from the sales order line and `_meta.subtotal` is that price × this line's quantity. `fee` (shipping fees): `product.total` is the fee. Prices come at the stored scale (6 decimal places); `_meta.subtotal` at the combined scale of price × quantity (compacted when large). Always read `dp`.","properties":{"type":{"enum":["system","fee"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details, always an object (with `editable_fields_on_update`); for `order_item`, `parent` describes the sales order line.","type":"object"},"properties":{"additionalProperties":true,"description":"The kind's fields; for `order_item`, `id` is the sales order line. A discount's percentage or amount comes back as `total` (you send it as `rate`).","type":"object"},"type":{"enum":["order_item","shipment_fee","invoice_discount","user_tax","override_tax","auto_tax","invoice_surcharge"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"description":"Absent on tax and discount lines.","properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"tax":{"additionalProperties":true,"description":"Absent 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.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"type":"object"},"type":{"description":"Same as `product.type`.","type":"string"}},"type":"object"},"type":"array"},"lock_version":{"example":1730000000000000,"type":"integer"},"order":{"additionalProperties":true,"description":"The sales order or quote in the v2 order shape: its header fields, with `status` and `assigned_users`, but no `items`.","properties":{"id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"scoped_id":{"example":"SO1001","type":["string","null"]}},"type":"object"},"order_id":{"description":"The sales order or quote it bills.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"order_quote":{"description":"The order is a quote.","type":"boolean"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"paid_amount":{"description":"Allocated payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12500,"type":["integer","number","string","null"]},"pdf_url":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Invoice","type":"string"},"object_type":{"example":"invoice","type":"string"},"url":{"description":"A download link with its own long-lived access token: don't publish it.","example":"https://example.com/pdf/invoice.pdf","type":"string"}},"type":"object"},"type":"array"},"scoped_id":{"description":"The invoice number.","example":"1001","type":["string","null"]},"ship_to_status":{"enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"shipment_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping fees (already in `cart_item_subtotal`). 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."},"shipment_tax_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"The tax on shipping (included in `tax_subtotal`). 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."},"shipping_address":{"oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"shipping_address_id":{"description":"Ship To.","example":"117KfwwfreX15N","type":["string","null"]},"tax_subtotal":{"$ref":"#/components/schemas/BigDecimalValue","description":"Tax. 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."},"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The invoice total. 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."},"version":{"example":2,"type":"integer"}},"type":"object"}]},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update an invoice","tags":["Invoices"],"x-yoprint-docs":{"errors":[{"fix":"Fix the fields in `error.fields`.","status":422,"when":"Validation fails (`validation_failed`, with field messages in `error.fields` such as \"The issue date must be a valid ISO8601 string.\" or \"The scoped id must be a string.\")."},{"fix":"Read `error.code` and `error.message`, fix that part and resend the whole call.","status":422,"when":"A line row or the tax selection is refused (see rules); nothing in the call is saved."},{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order (`user_is_not_authorized`)."},{"fix":"Check the id.","status":404,"when":"The invoice isn't your team's."}],"group":"Invoices and payments","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 422 `amount_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."],"permission":"Needs permission to edit the invoice's sales order: the team owner, a role whose Manage Sales Orders permission is \"update all\", or \"update assigned\" when you created the order or are assigned to it, or, on a draft order, its creator when their role can create sales orders. Otherwise 403 `user_is_not_authorized`. Reading needs only team membership.","related":["v2_public_invoice_show","v2_public_invoice_item_bulk","v2_public_invoice_tax_selection_update","v2_public_sales_order_invoice_create"],"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_items` is 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.\" A `delete` of the tax line there removes it on an invoice without Auto Invoice (refused on one with it). Use `tax_selection` for tax changes.","Every rule of the line calls applies to `item_actions` rows.","In `tax_selection`, both `expected_tax` and `desired_tax` must be present; null is allowed for either. Missing: 422 \"The tax_selection.expected_tax field must be present.\" (or `desired_tax`).","`expected_tax` must match the current tax line exactly (id and `lock_version`), or be null when there is none. Otherwise 422 `invoice_tax_conflict`: \"Invoice tax changed in another window. Reload and retry.\"","A different `type` from 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_error` with `error.context.reason` `auto_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."]}}},"/v2/api/store/{team_slug}/v2/invoice/{unique_key}/item":{"get":{"description":"Returns every line of an invoice: billed sales order lines, shipping fees, discounts and the tax line. Not paged, and in no set order: sort by `position`.\n\n| `product.type` | What it is |\n| --- | --- |\n| `order_item` | Bills a line of the sales order (any kind of product line). Name and unit price come from that line. |\n| `shipment_fee` | A shipping charge with its own price. |\n| `invoice_discount` | A discount, as a percentage or a fixed amount. |\n| `user_tax` | Tax from one of your tax presets. |\n| `override_tax` | A tax you set by hand: a fixed amount, a percentage, or tax exempt. |\n| `auto_tax` | US Auto Tax, calculated by YoPrint's tax provider. |\n\nThe sales order line kinds (`db_catalog`, `user_simple`, `db_variant`, `custom`, `fee`) are not invoice kinds: to bill one, add an `order_item` line that points at it.","operationId":"v2_public_invoice_item_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"unique_key","required":true,"schema":{"example":"cBRpSf5nw6upt5","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"_meta":{"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000000,"position_hash":"EXAMPLEpositionHash","type":"order_item"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000000,"position":100,"position_hash":"EXAMPLEpositionHash","pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"tax":{"type":"taxable"},"type":"order_item"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"An invoice line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only: `id`, `type`, `invoice_id`, `lock_version`, `from_legacy`, `position_hash`.","type":"object"},"auto_invoice_managed":{"description":"YoPrint manages this line (Auto Invoice).","type":"boolean"},"external_ids":{"description":"Links to external systems; empty for lines made in YoPrint.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The invoice line.","example":"nhsGsn84PyJBvK","type":"string"},"invoice_id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Send it back on Update an invoice line to detect a concurrent change.","example":1730000000000000,"type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"Absent on tax and discount lines. `system` (sales order lines): `_meta.unit_price` is the price copied from the sales order line and `_meta.subtotal` is that price × this line's quantity. `fee` (shipping fees): `product.total` is the fee. Prices come at the stored scale (6 decimal places); `_meta.subtotal` at the combined scale of price × quantity (compacted when large). Always read `dp`.","properties":{"type":{"enum":["system","fee"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details, always an object (with `editable_fields_on_update`); for `order_item`, `parent` describes the sales order line.","type":"object"},"properties":{"additionalProperties":true,"description":"The kind's fields; for `order_item`, `id` is the sales order line. A discount's percentage or amount comes back as `total` (you send it as `rate`).","type":"object"},"type":{"enum":["order_item","shipment_fee","invoice_discount","user_tax","override_tax","auto_tax","invoice_surcharge"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"description":"Absent on tax and discount lines.","properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"tax":{"additionalProperties":true,"description":"Absent 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.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"type":"object"},"type":{"description":"Same as `product.type`.","type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the lines of an invoice","tags":["Invoice line items"],"x-yoprint-docs":{"errors":[{"fix":"Check the invoice id.","status":404,"when":"The invoice isn't your team's."}],"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_invoice_item_create","v2_public_invoice_item_bulk","v2_public_invoice_show"]}},"post":{"description":"Adds one line to an invoice and recalculates it. Returns the new line in an action envelope (`action_performed` `CREATED`, `has_changes`, `lock_version`, `item`).\n\n| `product.type` | What it is |\n| --- | --- |\n| `order_item` | Bills a line of the sales order (any kind of product line). Name and unit price come from that line. |\n| `shipment_fee` | A shipping charge with its own price. |\n| `invoice_discount` | A discount, as a percentage or a fixed amount. |\n| `user_tax` | Tax from one of your tax presets. |\n| `override_tax` | A tax you set by hand: a fixed amount, a percentage, or tax exempt. |\n| `auto_tax` | US Auto Tax, calculated by YoPrint's tax provider. |\n\nThe sales order line kinds (`db_catalog`, `user_simple`, `db_variant`, `custom`, `fee`) are not invoice kinds: to bill one, add an `order_item` line that points at it.\n\nNumbers are `{ value, dp }` pairs: `value` is the number without its decimal point and `dp` the count of decimal places, so 12.50 is `{ \"value\": 1250, \"dp\": 2 }` (or `{ \"value\": 125, \"dp\": 1 }`). `value` is a JSON integer or a digit string, never a float. Quantities take up to 8 decimal places, a discount `rate` 4 and a manual tax `total` 6; more decimals are a 422 `validation_failed`. A shipping fee price is rounded half-up to 6 decimal places (a float `value` there is 422 `amount_out_of_range`). Send very large numbers as strings. Answers send prices at the stored scale (6 decimal places), quantities without trailing zeros, and `_meta.subtotal` (price × quantity) at the combined scale, compacted when it would exceed a safe integer: always read `dp`.\n\nAn invoice has at most one tax line (`auto_tax`, `user_tax` or `override_tax`). To switch the tax type, use Change the tax on an invoice rather than adding a second one.","operationId":"v2_public_invoice_item_create","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"unique_key","required":true,"schema":{"example":"cBRpSf5nw6upt5","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"auto_tax":{"summary":"Add US Auto Tax","value":{"position":1000,"product":{"properties":{"engine":"us","from":{"override":false},"rate":{"dp":0,"value":0},"to":{"override":false}},"type":"auto_tax"}},"x-yoprint-variant":"Auto Tax"},"invoice_discount":{"summary":"Take 10% off","value":{"position":950,"product":{"properties":{"applies_to_shipping":false,"name":"Loyalty discount","rate":{"dp":0,"value":10},"type":"percent"},"type":"invoice_discount"}},"x-yoprint-variant":"Discount"},"order_item":{"summary":"Bill 24 of a sales order line","value":{"position":100,"product":{"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"tax":{"type":"taxable"}},"x-yoprint-variant":"Sales order line"},"override_tax":{"summary":"Charge 8.25 tax by hand","value":{"position":1000,"product":{"properties":{"description":"Sales tax","mode":"fixed_total","total":{"dp":2,"value":825}},"type":"override_tax"}},"x-yoprint-variant":"Manual tax"},"shipment_fee":{"summary":"Add 15.00 shipping","value":{"position":900,"pricing":{"product":{"total":{"dp":2,"value":1500}},"type":"fee"},"product":{"properties":{"name":"Shipping","shipping_taxable":false},"type":"shipment_fee"}},"x-yoprint-variant":"Shipping fee"},"user_tax":{"summary":"Apply a tax preset","value":{"position":1000,"product":{"properties":{"id":"KC48n7qAAfGYMM"},"type":"user_tax"}},"x-yoprint-variant":"Tax from a tax preset"}},"schema":{"oneOf":[{"description":"Bills a line of the invoice's sales order. The unit price is always the sales order line's.","properties":{"position":{"description":"Where the line sits on the invoice; lower comes first. Not checked against other lines.","example":100,"type":"integer"},"product":{"properties":{"properties":{"properties":{"id":{"description":"The sales order line's `id` (a hash id). It must be on this invoice's order and not already on this invoice.","example":"V4keXwwxMQyXw7","type":"string"}},"required":["id"],"type":"object"},"type":{"const":"order_item","type":"string"}},"required":["type","properties"],"type":"object"},"quantity":{"description":"How many to bill. Not negative; you may bill more than was ordered.","properties":{"total":{"description":"The quantity, up to 8 decimal places.","example":{"dp":0,"value":24},"properties":{"dp":{"description":"How many of its digits come after the decimal point, 0 to 30.","maximum":30,"minimum":0,"type":"integer"},"value":{"description":"The number without its decimal point, as a JSON integer or a string of digits (an optional leading `-`, no leading zeros, no decimal point).","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type","total"],"type":"object"},"tax":{"description":"Sales order lines (`order_item`) only: whether the line is taxed (default `taxable`). Ignored on other kinds: shipping is taxed by the tax line's `shipping_taxable`.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"required":["type"],"type":"object"}},"required":["product","position","quantity"],"title":"Sales order line","type":"object"},{"description":"A shipping charge. Its quantity is always 1.","properties":{"position":{"description":"Where the line sits on the invoice; lower comes first. Not checked against other lines.","example":100,"type":"integer"},"pricing":{"properties":{"product":{"properties":{"total":{"description":"The fee. Rounded half-up to 6 decimal places.","example":{"dp":2,"value":1500},"properties":{"dp":{"description":"How many of its digits come after the decimal point, 0 to 30.","maximum":30,"minimum":0,"type":"integer"},"value":{"description":"The number without its decimal point, as a JSON integer or a string of digits (an optional leading `-`, no leading zeros, no decimal point).","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"type":{"const":"fee","type":"string"}},"required":["type","product"],"type":"object"},"product":{"properties":{"properties":{"properties":{"description":{"type":"string"},"name":{"description":"Defaults to \"Shipping Fee\".","type":"string"},"shipping_taxable":{"default":false,"description":"Stored, but not used by the invoice tax calculation: to tax shipping, set `shipping_taxable` on the tax line.","type":"boolean"}},"type":"object"},"type":{"const":"shipment_fee","type":"string"}},"required":["type","properties"],"type":"object"},"tax":{"description":"Sales order lines (`order_item`) only: whether the line is taxed (default `taxable`). Ignored on other kinds: shipping is taxed by the tax line's `shipping_taxable`.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"required":["type"],"type":"object"}},"required":["product","position","pricing"],"title":"Shipping fee","type":"object"},{"description":"A discount on the invoice. You may add more than one.","properties":{"position":{"description":"Where the line sits on the invoice; lower comes first. Not checked against other lines.","example":100,"type":"integer"},"product":{"properties":{"properties":{"properties":{"applies_to_shipping":{"description":"Also discount the shipping.","type":"boolean"},"description":{"type":"string"},"name":{"description":"Defaults to \"Discount\".","type":"string"},"rate":{"description":"The percentage or amount, up to 4 decimal places, not negative.","example":{"dp":0,"value":10},"properties":{"dp":{"description":"How many of its digits come after the decimal point, 0 to 30.","maximum":30,"minimum":0,"type":"integer"},"value":{"description":"The number without its decimal point, as a JSON integer or a string of digits (an optional leading `-`, no leading zeros, no decimal point).","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"description":"`percent` takes `rate` as a percentage (10 is 10%); `total` as an amount.","enum":["percent","total"],"type":"string"}},"required":["type","applies_to_shipping","rate"],"type":"object"},"type":{"const":"invoice_discount","type":"string"}},"required":["type","properties"],"type":"object"},"tax":{"description":"Sales order lines (`order_item`) only: whether the line is taxed (default `taxable`). Ignored on other kinds: shipping is taxed by the tax line's `shipping_taxable`.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"required":["type"],"type":"object"}},"required":["product","position"],"title":"Discount","type":"object"},{"description":"Tax from one of your tax presets: name and rate are copied from it.","properties":{"position":{"description":"Where the line sits on the invoice; lower comes first. Not checked against other lines.","example":100,"type":"integer"},"product":{"properties":{"properties":{"properties":{"apply_before_discount":{"description":"Work out the tax before discounts.","type":"boolean"},"description":{"type":"string"},"id":{"description":"The tax preset (from List tax presets).","example":"V4keXwwxMQyXw7","type":"string"},"shipping_taxable":{"description":"Tax the shipping too.","type":"boolean"}},"required":["id"],"type":"object"},"type":{"const":"user_tax","type":"string"}},"required":["type","properties"],"type":"object"},"tax":{"description":"Sales order lines (`order_item`) only: whether the line is taxed (default `taxable`). Ignored on other kinds: shipping is taxed by the tax line's `shipping_taxable`.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"required":["type"],"type":"object"}},"required":["product","position"],"title":"Tax from a tax preset","type":"object"},{"description":"A tax you set by hand.","properties":{"position":{"description":"Where the line sits on the invoice; lower comes first. Not checked against other lines.","example":100,"type":"integer"},"product":{"properties":{"properties":{"properties":{"apply_before_discount":{"description":"Work out the tax before discounts.","type":"boolean"},"description":{"type":"string"},"mode":{"default":"fixed_total","description":"`fixed_total` and `tax_exempt` take `total` as the tax amount; `percent` as a rate.","enum":["fixed_total","tax_exempt","percent"],"type":"string"},"shipping_taxable":{"description":"Tax the shipping too. Required when `mode` is `percent`.","type":"boolean"},"total":{"description":"The tax amount or rate, up to 6 decimal places, not negative.","example":{"dp":2,"value":825},"properties":{"dp":{"description":"How many of its digits come after the decimal point, 0 to 30.","maximum":30,"minimum":0,"type":"integer"},"value":{"description":"The number without its decimal point, as a JSON integer or a string of digits (an optional leading `-`, no leading zeros, no decimal point).","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"type":{"const":"override_tax","type":"string"}},"required":["type","properties"],"type":"object"},"tax":{"description":"Sales order lines (`order_item`) only: whether the line is taxed (default `taxable`). Ignored on other kinds: shipping is taxed by the tax line's `shipping_taxable`.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"required":["type"],"type":"object"}},"required":["product","position"],"title":"Manual tax","type":"object"},{"description":"US Auto Tax. YoPrint asks its tax provider for the rate while you wait.","properties":{"position":{"description":"Where the line sits on the invoice; lower comes first. Not checked against other lines.","example":100,"type":"integer"},"product":{"properties":{"properties":{"properties":{"apply_before_discount":{"description":"Ignored: always false.","type":"boolean"},"description":{"type":"string"},"engine":{"const":"us","type":"string"},"from":{"description":"Where the goods ship from. Without an override, the invoice's billing address.","properties":{"address_id":{"description":"Required when `override` is true.","example":"V4keXwwxMQyXw7","type":"string"},"override":{"type":"boolean"}},"required":["override"],"type":"object"},"name":{"description":"Defaults to \"Auto Tax\".","type":"string"},"rate":{"description":"Required but not used: the provider sets the rate.","example":{"dp":0,"value":0},"properties":{"dp":{"description":"How many of its digits come after the decimal point, 0 to 30.","maximum":30,"minimum":0,"type":"integer"},"value":{"description":"The number without its decimal point, as a JSON integer or a string of digits (an optional leading `-`, no leading zeros, no decimal point).","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"shipping_taxable":{"description":"Ignored: the provider decides.","type":"boolean"},"to":{"description":"Where they ship to. Without an override, the invoice's shipping address, then its billing address.","properties":{"address_id":{"description":"Required when `override` is true.","example":"V4keXwwxMQyXw7","type":"string"},"override":{"type":"boolean"}},"required":["override"],"type":"object"}},"required":["engine","from","to","rate"],"type":"object"},"type":{"const":"auto_tax","type":"string"}},"required":["type","properties"],"type":"object"},"tax":{"description":"Sales order lines (`order_item`) only: whether the line is taxed (default `taxable`). Ignored on other kinds: shipping is taxed by the tax line's `shipping_taxable`.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"required":["type"],"type":"object"}},"required":["product","position"],"title":"Auto Tax","type":"object"}],"title":"What are you adding?"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"action_performed":"CREATED","has_changes":true,"item":{"_meta":{"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000000,"position_hash":"EXAMPLEpositionHash","type":"order_item"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000000,"position":100,"position_hash":"EXAMPLEpositionHash","pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"tax":{"type":"taxable"},"type":"order_item"},"lock_version":{"invoice":{"invoice_item_lock_version":1730000000000000,"invoice_lock_version":1730000000000000},"order":{"invoice_lock_version":1730000000000000,"job_lock_version":1730000000000000,"order_item_lock_version":1730000000000000,"order_lock_version":1730000000000000,"payment_lock_version":1730000000000000,"shipment_lock_version":1730000000000000}},"object_type":"invoice_item"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"What happened, and the line.","properties":{"action_performed":{"description":"`NONE` when nothing changed.","enum":["CREATED","UPDATED","DELETED","NONE"],"type":"string"},"has_changes":{"type":"boolean"},"item":{"additionalProperties":true,"description":"An invoice line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only: `id`, `type`, `invoice_id`, `lock_version`, `from_legacy`, `position_hash`.","type":"object"},"auto_invoice_managed":{"description":"YoPrint manages this line (Auto Invoice).","type":"boolean"},"external_ids":{"description":"Links to external systems; empty for lines made in YoPrint.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The invoice line.","example":"nhsGsn84PyJBvK","type":"string"},"invoice_id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Send it back on Update an invoice line to detect a concurrent change.","example":1730000000000000,"type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"Absent on tax and discount lines. `system` (sales order lines): `_meta.unit_price` is the price copied from the sales order line and `_meta.subtotal` is that price × this line's quantity. `fee` (shipping fees): `product.total` is the fee. Prices come at the stored scale (6 decimal places); `_meta.subtotal` at the combined scale of price × quantity (compacted when large). Always read `dp`.","properties":{"type":{"enum":["system","fee"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details, always an object (with `editable_fields_on_update`); for `order_item`, `parent` describes the sales order line.","type":"object"},"properties":{"additionalProperties":true,"description":"The kind's fields; for `order_item`, `id` is the sales order line. A discount's percentage or amount comes back as `total` (you send it as `rate`).","type":"object"},"type":{"enum":["order_item","shipment_fee","invoice_discount","user_tax","override_tax","auto_tax","invoice_surcharge"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"description":"Absent on tax and discount lines.","properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"tax":{"additionalProperties":true,"description":"Absent 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.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"type":"object"},"type":{"description":"Same as `product.type`.","type":"string"}},"type":"object"},"lock_version":{"additionalProperties":true,"description":"Lock versions after the change.","properties":{"invoice":{"additionalProperties":true,"description":"The invoice's lock versions: `invoice_item_lock_version`, `invoice_lock_version`.","type":"object"},"order":{"additionalProperties":true,"description":"The order's lock versions: `job_lock_version`, `invoice_lock_version`, `order_item_lock_version`, `shipment_lock_version`, `payment_lock_version`, `order_lock_version`.","type":"object"}},"type":"object"},"object_type":{"const":"invoice_item","example":"invoice_item","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add a line to an invoice","tags":["Invoice line items"],"x-yoprint-docs":{"errors":[{"fix":"Fix the named fields.","status":422,"when":"A field fails validation (`validation_failed`, details in `error.fields`), for example \"The selected product.type is invalid.\" or a number that isn't a valid pair."},{"fix":"Read `error.message`; see the rules.","status":422,"when":"A business rule refuses the line: `cart_item_validation_error`, with `error.context.reason` naming it (`tax_type_conflict`, `duplicate_order_item`, `item_not_available`, `managed_invoice`, `auto_tax_unavailable`)."},{"fix":"Check the preset or address id; retry Auto Tax later.","status":422,"when":"A tax preset or Auto Tax address isn't found, or Auto Tax couldn't be calculated. These come back as a bare `{ \"message\": ... }` without the usual error envelope."},{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order (`user_is_not_authorized`)."},{"fix":"Check the invoice id.","status":404,"when":"The invoice isn't your team's."}],"group":"Invoices and payments","notes":["Billing more than was ordered is allowed; the sales order line then shows as over-invoiced.","Invoices have no locked or permanently \"paid\" state: you can change invoice lines even after payments are recorded. When an invoice total changes, YoPrint automatically redistributes (reallocates) the order's recorded payments across its invoices according to their updated balances."],"permission":"Needs permission to edit the invoice's sales order: the team owner, a role whose Manage Sales Orders permission is \"update all\", or \"update assigned\" when you created the order or are assigned to it, or, on a draft order, its creator when their role can create sales orders. Otherwise 403 `user_is_not_authorized`. Reading needs only team membership.","related":["v2_public_invoice_item_index","v2_public_invoice_item_bulk","v2_public_invoice_tax_selection_update","v2_public_order_item_store"],"rules":["`product.type` and `position` are always required. Any group you send (`product`, `pricing`, `quantity`, `tax`) needs its `type`.","A sales order line can be on an invoice once: a second time is 422 \"Invoice already has the same Order Item\".","A sales order line from another order, or a deleted one, is 422 \"This order item is not available for this invoice.\"","One tax line per invoice: a second is 422 `cart_item_validation_error` with `error.context.reason` `tax_type_conflict` (\"You can only have 1 Tax Type per Invoice\").","Auto Tax needs a US plan with Auto Tax turned on.","On an Auto Invoice invoice (`auto_invoice_managed: true`), YoPrint automatically updates invoice lines to match the sales order's product lines and shipping fees. You cannot add, edit, or delete its order lines, or edit or delete the shipping fees and discounts created by YoPrint. You can still add your own custom discounts and shipping fees; YoPrint always places them after the managed lines regardless of the `position` you send.","Invoices synced from Shopify can't take new lines: 422 \"Cannot create invoice item for a Shopify-synced invoice.\"","Fields that aren't listed are dropped, and a `null` counts as not sent."],"side_effects":["Recalculates the invoice: line totals, subtotal, shipping, discounts, tax and total.","Updates the sales order's invoiced totals and each line's invoiced status (not invoiced, partly, fully, or over-invoiced), and automatically redistributes (reallocates) recorded payments across the order's invoices to match updated totals (funds frozen by an open dispute or review stay where they are).","When the team syncs to QuickBooks Online automatically and the order is published, the order is synced again about 3 minutes later (not after a change of `position` only).","Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open. No webhook or email is sent.","An `auto_tax` line calls the tax provider while you wait."]}}},"/v2/api/store/{team_slug}/v2/invoice/{unique_key}/item/bulk":{"post":{"description":"Applies several line changes to one invoice in one transaction: all of them are saved, or none.\n\nThe body is a JSON array of actions. Each has your own label `bid`, an `action`, and for `create` and `update` a `payload` with the same body as Add a line to an invoice or Update an invoice line; `update` and `delete` name the line in `cart_item_id`.\n\nYoPrint runs every delete first, then the creates, then the updates, then recalculates once. Returns every line of the invoice afterwards, and a top-level `has_changes`. Numbers are `{ value, dp }` pairs: `value` is the number without its decimal point and `dp` the count of decimal places, so 12.50 is `{ \"value\": 1250, \"dp\": 2 }` (or `{ \"value\": 125, \"dp\": 1 }`). `value` is a JSON integer or a digit string, never a float. Quantities take up to 8 decimal places, a discount `rate` 4 and a manual tax `total` 6; more decimals are a 422 `validation_failed`. A shipping fee price is rounded half-up to 6 decimal places (a float `value` there is 422 `amount_out_of_range`). Send very large numbers as strings. Answers send prices at the stored scale (6 decimal places), quantities without trailing zeros, and `_meta.subtotal` (price × quantity) at the combined scale, compacted when it would exceed a safe integer: always read `dp`.","operationId":"v2_public_invoice_item_bulk","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"unique_key","required":true,"schema":{"example":"cBRpSf5nw6upt5","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"action":"create","bid":"row-1","payload":{"position":100,"product":{"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"}}},{"action":"update","bid":"row-2","cart_item_id":"wigm2YNiE4PciF","payload":{"quantity":{"total":{"dp":0,"value":6},"type":"unit"}}},{"action":"delete","bid":"row-3","cart_item_id":"DW7m2sWa8vVVDL"}],"schema":{"items":{"properties":{"action":{"enum":["create","update","delete"],"type":"string"},"bid":{"description":"Your label for this action, echoed in some errors.","example":"row-1","type":"string"},"cart_item_id":{"description":"The invoice line. Required for `update` and `delete`.","example":"V4keXwwxMQyXw7","type":"string"},"payload":{"additionalProperties":true,"description":"Required for `create` and `update`: the line body, as on the single calls.","type":"object"}},"required":["bid","action"],"type":"object"},"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"action_performed":"CREATED","has_changes":true,"item":{"_meta":{"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000000,"position_hash":"EXAMPLEpositionHash","type":"order_item"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"nhsGsn84PyJBvK","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000000,"position":100,"position_hash":"EXAMPLEpositionHash","pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"tax":{"type":"taxable"},"type":"order_item"},"lock_version":{"invoice":{"invoice_item_lock_version":1730000000000000,"invoice_lock_version":1730000000000000},"order":{"invoice_lock_version":1730000000000000,"job_lock_version":1730000000000000,"order_item_lock_version":1730000000000000,"order_lock_version":1730000000000000,"payment_lock_version":1730000000000000,"shipment_lock_version":1730000000000000}},"object_type":"invoice_item"},{"action_performed":"CREATED","has_changes":true,"item":{"_meta":{"from_legacy":false,"id":"wigm2YNiE4PciF","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000000,"position_hash":"EXAMPLEpositionHash","type":"order_item"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"wigm2YNiE4PciF","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000000,"position":200,"position_hash":"EXAMPLEpositionHash","pricing":{"_meta":{"subtotal":{"dp":0,"value":180},"unit_price":{"dp":6,"value":30000000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 18500 Hoodie"}},"properties":{"id":"OM2IMHqOYFKlP4"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":6},"type":"unit"},"tax":{"type":"taxable"},"type":"order_item"},"lock_version":{"invoice":{"invoice_item_lock_version":1730000000000000,"invoice_lock_version":1730000000000000},"order":{"invoice_lock_version":1730000000000000,"job_lock_version":1730000000000000,"order_item_lock_version":1730000000000000,"order_lock_version":1730000000000000,"payment_lock_version":1730000000000000,"shipment_lock_version":1730000000000000}},"object_type":"invoice_item"}],"has_changes":true,"status":200,"success":true},"schema":{"properties":{"data":{"description":"Every line of the invoice after the call, one envelope each, all marked `CREATED`. `has_changes` is at the top level, next to `data`.","items":{"additionalProperties":true,"description":"What happened, and the line.","properties":{"action_performed":{"description":"`NONE` when nothing changed.","enum":["CREATED","UPDATED","DELETED","NONE"],"type":"string"},"has_changes":{"type":"boolean"},"item":{"additionalProperties":true,"description":"An invoice line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only: `id`, `type`, `invoice_id`, `lock_version`, `from_legacy`, `position_hash`.","type":"object"},"auto_invoice_managed":{"description":"YoPrint manages this line (Auto Invoice).","type":"boolean"},"external_ids":{"description":"Links to external systems; empty for lines made in YoPrint.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The invoice line.","example":"nhsGsn84PyJBvK","type":"string"},"invoice_id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Send it back on Update an invoice line to detect a concurrent change.","example":1730000000000000,"type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"Absent on tax and discount lines. `system` (sales order lines): `_meta.unit_price` is the price copied from the sales order line and `_meta.subtotal` is that price × this line's quantity. `fee` (shipping fees): `product.total` is the fee. Prices come at the stored scale (6 decimal places); `_meta.subtotal` at the combined scale of price × quantity (compacted when large). Always read `dp`.","properties":{"type":{"enum":["system","fee"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details, always an object (with `editable_fields_on_update`); for `order_item`, `parent` describes the sales order line.","type":"object"},"properties":{"additionalProperties":true,"description":"The kind's fields; for `order_item`, `id` is the sales order line. A discount's percentage or amount comes back as `total` (you send it as `rate`).","type":"object"},"type":{"enum":["order_item","shipment_fee","invoice_discount","user_tax","override_tax","auto_tax","invoice_surcharge"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"description":"Absent on tax and discount lines.","properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"tax":{"additionalProperties":true,"description":"Absent 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.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"type":"object"},"type":{"description":"Same as `product.type`.","type":"string"}},"type":"object"},"lock_version":{"additionalProperties":true,"description":"Lock versions after the change.","properties":{"invoice":{"additionalProperties":true,"description":"The invoice's lock versions: `invoice_item_lock_version`, `invoice_lock_version`.","type":"object"},"order":{"additionalProperties":true,"description":"The order's lock versions: `job_lock_version`, `invoice_lock_version`, `order_item_lock_version`, `shipment_lock_version`, `payment_lock_version`, `order_lock_version`.","type":"object"}},"type":"object"},"object_type":{"const":"invoice_item","example":"invoice_item","type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/BulkValidationPayloadResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add, change and remove invoice lines at once","tags":["Invoice line items"],"x-yoprint-docs":{"errors":[{"fix":"Fix the named action and resend the whole array.","status":422,"when":"A payload fails validation (`bulk_validation_payload_failed`, with its `bid` and `fields`) or a rule refuses an action; nothing is saved."},{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order."},{"fix":"Check the invoice id.","status":404,"when":"The invoice isn't your team's."}],"group":"Invoices and payments","notes":["Every line in the response says `CREATED`, whatever happened to it; use the top-level `has_changes` (next to `data`) instead.","An empty array succeeds with `has_changes` false."],"permission":"Needs permission to edit the invoice's sales order: the team owner, a role whose Manage Sales Orders permission is \"update all\", or \"update assigned\" when you created the order or are assigned to it, or, on a draft order, its creator when their role can create sales orders. Otherwise 403 `user_is_not_authorized`. Reading needs only team membership.","related":["v2_public_invoice_item_create","v2_public_invoice_item_update","v2_public_invoice_item_destroy"],"rules":["Tax lines can't be added or changed here: 422 \"Tax Item is not allow in bulk operations.\" A `delete` of the tax line is carried out on an invoice without Auto Invoice (it is refused on one with it). Use Change the tax on an invoice for tax changes.","One action per line: a second is 422 `cart_item_validation_error` with `error.context.reason` `duplicate_item_action` and the row's `error.bid`.","An `update` or `delete` of a line that isn't on the invoice is the same code with reason `item_not_available`; the same sales order line twice is reason `duplicate_order_item`. Deleting a line that is already deleted is skipped.","Creates run sorted by kind and sales order line, not in the order you sent: use `position` for the order on the invoice.","`lock_version` is not checked in bulk.","Every rule of the single calls applies to each action."],"side_effects":["Recalculates the invoice: line totals, subtotal, shipping, discounts, tax and total.","Updates the sales order's invoiced totals and each line's invoiced status (not invoiced, partly, fully, or over-invoiced), and automatically redistributes (reallocates) recorded payments across the order's invoices to match updated totals (funds frozen by an open dispute or review stay where they are).","When the team syncs to QuickBooks Online automatically and the order is published, the order is synced again about 3 minutes later (not after a change of `position` only).","Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open. No webhook or email is sent."]}}},"/v2/api/store/{team_slug}/v2/invoice/{unique_key}/tax-selection":{"put":{"description":"Sets, changes or removes an invoice's tax line. An invoice has at most one: US Auto Tax (`auto_tax`), a tax preset (`user_tax`) or a tax set by hand (`override_tax`).\n\nSend what you expect the current tax line to be (`expected_tax`: its id and `lock_version`, or null) and what you want (`desired_tax`, or null to remove it). If someone changed the tax since you read the invoice, nothing changes and you get 422 `invoice_tax_conflict`: read the invoice again and retry.\n\nReturns `action_performed` (`CREATED`, `UPDATED`, `REPLACED`, `DELETED` or `NONE`), `has_changes`, the tax line (`tax`) and lock versions. With `auto_tax`, YoPrint asks its tax provider for the rate while you wait (it charges no tax when the team has no US nexus, the customer is tax exempt, or the destination is outside the US).","operationId":"v2_public_invoice_tax_selection_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"unique_key","required":true,"schema":{"example":"cBRpSf5nw6upt5","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"auto":{"summary":"Switch to US Auto Tax","value":{"desired_tax":{"properties":{"engine":"us","from":{"override":false},"rate":{"dp":0,"value":0},"to":{"override":false}},"type":"auto_tax"},"expected_tax":{"id":"WzHB84GM5mzqAw","lock_version":1730000000000001}}},"exempt":{"summary":"Mark tax exempt","value":{"desired_tax":{"properties":{"mode":"tax_exempt","total":{"dp":0,"value":0}},"type":"override_tax"},"expected_tax":{"id":"WzHB84GM5mzqAw","lock_version":1730000000000001}}},"preset":{"summary":"Use a tax preset on an invoice with no tax","value":{"desired_tax":{"properties":{"id":"KC48n7qAAfGYMM"},"type":"user_tax"},"expected_tax":null}},"remove":{"summary":"Remove the tax line","value":{"desired_tax":null,"expected_tax":{"id":"WzHB84GM5mzqAw","lock_version":1730000000000001}}}},"schema":{"description":"Set, change or remove the invoice's one tax line. Send both keys; either may be null.","properties":{"desired_tax":{"description":"The tax you want, or null to remove the tax line.","properties":{"properties":{"additionalProperties":true,"description":"The fields of that kind, as for an invoice line of that `product.type`: `auto_tax` takes `engine` `us`, `from`, `to` and `rate`; `user_tax` takes the preset `id`; `override_tax` takes `mode` and `total`.","type":"object"},"type":{"description":"`auto_tax` (US Auto Tax), `user_tax` (one of your tax presets) or `override_tax` (set by hand).","enum":["auto_tax","user_tax","override_tax"],"type":"string"}},"type":["object","null"]},"expected_tax":{"description":"The tax line you think is there now: its `id` and `lock_version` from the invoice's items, or null when it has none. If it doesn't match, nothing changes (422 `invoice_tax_conflict`).","properties":{"id":{"description":"The current tax line.","example":"V4keXwwxMQyXw7","type":"string"},"lock_version":{"description":"That line's `lock_version`.","example":1730000000000000,"minimum":0,"type":"integer"}},"type":["object","null"]}},"required":["expected_tax","desired_tax"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"action_performed":"CREATED","has_changes":true,"lock_version":{"invoice":{"invoice_item_lock_version":1730000000000001,"invoice_lock_version":1730000000000001},"order":{"invoice_lock_version":1730000000000001,"job_lock_version":1730000000000000,"order_item_lock_version":1730000000000000,"order_lock_version":1730000000000000,"payment_lock_version":1730000000000000,"shipment_lock_version":1730000000000000}},"object_type":"invoice_tax_selection","tax":{"_meta":{"from_legacy":false,"id":"WzHB84GM5mzqAw","invoice_id":"cBRpSf5nw6upt5","lock_version":1730000000000001,"position_hash":"EXAMPLEpositionHash","type":"user_tax"},"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"WzHB84GM5mzqAw","invoice_id":"cBRpSf5nw6upt5","is_external":false,"lock_version":1730000000000001,"position":2147483647,"position_hash":"EXAMPLEpositionHash","product":{"_meta":{"editable_fields_on_update":["product.properties","product.properties.description","product.properties.id","product.properties.refresh_tax_rate","product.properties.shipping_taxable","product.properties.apply_before_discount"],"product_hash":"EXAMPLEproductHash","product_name":"State sales tax"},"properties":{"apply_before_discount":0,"description":null,"id":"KC48n7qAAfGYMM","invoice_tax_metadata":[{"rate_decimal":3,"rate_value":8250,"tax_id":4021,"tax_last_updated":"2026-10-01T09:00:00.000000Z","tax_name":"State sales tax","tax_type":"simple","total_decimal":2,"total_value":2475}],"name":"State sales tax","rate":{"dp":6,"value":8250000},"shipping_taxable":0,"user_tax_last_updated":"2026-10-01T09:00:00+00:00"},"type":"user_tax"},"type":"user_tax"}},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"action_performed":{"enum":["CREATED","UPDATED","REPLACED","DELETED","NONE"],"type":"string"},"has_changes":{"type":"boolean"},"lock_version":{"additionalProperties":true,"description":"Lock versions after the call.","properties":{"invoice":{"additionalProperties":true,"description":"The invoice's lock versions: `invoice_item_lock_version`, `invoice_lock_version`.","type":"object"},"order":{"additionalProperties":true,"description":"The order's lock versions: `job_lock_version`, `invoice_lock_version`, `order_item_lock_version`, `shipment_lock_version`, `payment_lock_version`, `order_lock_version`.","type":"object"}},"type":"object"},"object_type":{"const":"invoice_tax_selection","example":"invoice_tax_selection","type":"string"},"tax":{"description":"The tax line after the call (a tax line has `product` but no `pricing`, `quantity` or `tax` group), or null when there is none.","oneOf":[{"additionalProperties":true,"description":"An invoice line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only: `id`, `type`, `invoice_id`, `lock_version`, `from_legacy`, `position_hash`.","type":"object"},"auto_invoice_managed":{"description":"YoPrint manages this line (Auto Invoice).","type":"boolean"},"external_ids":{"description":"Links to external systems; empty for lines made in YoPrint.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The invoice line.","example":"nhsGsn84PyJBvK","type":"string"},"invoice_id":{"description":"The invoice.","example":"cBRpSf5nw6upt5","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Send it back on Update an invoice line to detect a concurrent change.","example":1730000000000000,"type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"Absent on tax and discount lines. `system` (sales order lines): `_meta.unit_price` is the price copied from the sales order line and `_meta.subtotal` is that price × this line's quantity. `fee` (shipping fees): `product.total` is the fee. Prices come at the stored scale (6 decimal places); `_meta.subtotal` at the combined scale of price × quantity (compacted when large). Always read `dp`.","properties":{"type":{"enum":["system","fee"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details, always an object (with `editable_fields_on_update`); for `order_item`, `parent` describes the sales order line.","type":"object"},"properties":{"additionalProperties":true,"description":"The kind's fields; for `order_item`, `id` is the sales order line. A discount's percentage or amount comes back as `total` (you send it as `rate`).","type":"object"},"type":{"enum":["order_item","shipment_fee","invoice_discount","user_tax","override_tax","auto_tax","invoice_surcharge"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"description":"Absent on tax and discount lines.","properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"tax":{"additionalProperties":true,"description":"Absent 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.","properties":{"type":{"enum":["taxable","non_taxable"],"type":"string"}},"type":"object"},"type":{"description":"Same as `product.type`.","type":"string"}},"type":"object"},{"type":"null"}]}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change the tax on an invoice","tags":["Invoices"],"x-yoprint-docs":{"errors":[{"fix":"Read the invoice, take the current tax line's id and `lock_version`, and retry.","status":422,"when":"`invoice_tax_conflict`: the tax changed since you read it."},{"fix":"Fix the fields named in the error.","status":422,"when":"A missing key, an unknown `type`, or bad properties (`validation_failed`)."},{"fix":"Check the preset id; retry Auto Tax later.","status":422,"when":"An unknown tax preset, or Auto Tax couldn't be calculated. These come back as a bare `{ \"message\": ... }` (\"user_tax: User Tax ID Not found\", \"auto_tax: Auto Tax calculation failed. Please retry later.\")."},{"fix":"Check the id.","status":404,"when":"The invoice isn't your team's."}],"group":"Invoices and payments","permission":"Any member of the team. Unlike Update an invoice, this route checks no sales order permission.","related":["v2_public_invoice_show","v2_public_invoice_update","v1_public_custom_tax_index"],"rules":["Both `expected_tax` and `desired_tax` must be present; null is allowed for either. Missing: 422 \"The expected_tax field must be present.\"","`expected_tax` must match the current tax line exactly (id and `lock_version`), or be null when there is none. Otherwise 422 `invoice_tax_conflict`: \"Invoice tax changed in another window. Reload and retry.\"","A different `type` from 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_error` with `error.context.reason` `auto_tax_unavailable`.","Synced (external) invoices are read-only here: 422 `external_invoice_tax_snapshot_read_only`.","An invoice with more than one tax line can't be changed here: 422 `invoice_tax_invariant_violation`."],"side_effects":["Recalculates the invoice's tax and total, the order's invoiced totals, and redistributes (reallocates) the order's recorded payments across its invoices.","`auto_tax` calls the tax provider (address lookup and rate) while you wait; it recalculates on every call.","May queue a QuickBooks Online sync of the order. Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open."]}}},"/v2/api/store/{team_slug}/v2/job/{hash_id}":{"delete":{"description":"**Check `success`, not only the HTTP status:** when the job's order is neither a draft nor published, this call deletes the job anyway and then answers **HTTP 200** with `{ \"status\": 500, \"success\": false, \"error\": { \"code\": \"action_not_allowed\", \"message\": null } }`.\n\nDeletes a job and every line item on it.\n\nDeleting a job also removes those lines from the order's shipments and invoices, releases the stock allocated to them, removes their needs-ordering entries, and recalculates the order's totals. It can't be undone.\n\nOn an order that came from Shopify the lines are not deleted: they stay on the order without a job.","operationId":"v2_public_job_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"WaGvtaWsx7Kcn4","in":"path","name":"hash_id","required":true,"schema":{"example":"WaGvtaWsx7Kcn4","type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"accepted":{"summary":"Done","value":{"data":null,"status":200,"success":true}},"refused":{"summary":"Refused with HTTP 200: `success` is false","value":{"error":{"code":"action_not_allowed","message":null},"status":500,"success":false}}},"schema":{"oneOf":[{"properties":{"data":{"description":"Nothing: check `success`.","type":"null"},"status":{"example":200,"type":"integer"},"success":{"const":true,"example":true,"type":"boolean"}},"required":["success","status","data"],"title":"Success","type":"object"},{"$ref":"#/components/schemas/ErrorResponse"}]}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a job","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Ask the team owner to give your role Manage Sales Orders, or assign you to the order.","status":403,"when":"Your role can't edit this order (`user_is_not_authorized`)."},{"fix":"Check the job id.","status":404,"when":"The job isn't on one of your team's sales orders."},{"fix":"Check `success` in every reply. Publish the order (or work on a draft) first.","status":200,"when":"The order is in a state this call refuses: `success: false`, `error.code` `action_not_allowed`."}],"group":"Production","notes":["A refusal here is HTTP 200 with `success: false` and `error.code` `action_not_allowed` (the body's `status` says 500). A client that only checks the HTTP status will treat it as done.","Lines are removed from invoices even when the invoice has payments. Check the order's invoices before you delete a job."],"permission":"Needs permission to edit the job's sales order:\n- the team owner;\n- a role whose Manage Sales Orders permission is \"update all\";\n- a role with \"update assigned\" when you created the order or are assigned to it; or\n- on a draft order, its creator when their role can create sales orders.\n\nOtherwise 403 `user_is_not_authorized`.","related":["v2_public_job_show","v2_public_job_clone","v2_public_invoice_show"],"side_effects":["Deletes the job's line items (Shopify orders: detaches them instead).","Deletes the matching shipment and invoice line items, so shipment and invoice totals change (not on Shopify orders).","Releases allocated stock and removes the needs-ordering entries of the deleted lines (not on Shopify orders).","Recalculates the sales order totals (not on Shopify orders). Open Admin Portal pages refresh, and on a published order so do Customer Portal pages the customer has open."]}},"put":{"description":"**Check `success`, not only the HTTP status:** when the job's order is neither a draft nor published, this call answers **HTTP 200** with `{ \"status\": 500, \"success\": false, \"error\": { \"code\": \"action_not_allowed\", \"message\": null } }` and changes nothing.\n\nChanges a job's name, note, position or rush flag, and adds, changes or removes its services, tasks, mockups and production files in one call.\n\nSend only what you change. Each of `service`, `pipeline`, `mockup` and `production_file` is a list of actions: every entry has an `action` of `create`, `update` or `delete`, and entries you leave out stay as they are.\n\nChanging services (the decoration, its location, option or order) reprices the job and recalculates the sales order's totals. Other changes don't touch prices.\n\nTo change the status use Change a job's status; for the job number use Change a job number; for dates use Schedule a job. Returns the updated job.","operationId":"v2_public_job_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"WaGvtaWsx7Kcn4","in":"path","name":"hash_id","required":true,"schema":{"example":"WaGvtaWsx7Kcn4","type":"string"}},{"description":"Optional. `1` (or `true`, `yes`, `on`) makes the answer smaller: each mockup and production file's `current_approval` leaves out its `items` list, and every other key stays as it is. The job's `pending_approval` and webhook payloads keep their items. Every file repeats its approval with all of its items, so a job with many files on one approval answers with far less data this way; read approval items from the approvals operations instead. Left out (or any other value), the answer is unchanged. Only the query string is read: a body field with this name is ignored.","example":"1","in":"query","name":"omit_media_approval_items","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"add_task":{"summary":"Add a task","value":{"pipeline":[{"action":"create","assigned_users":["4mdDkMg3dgQOa3"],"due_date":"2026-11-05T17:00:00Z","name":"Burn screens","pipeline_id":"SE3SfXjt6dPfnH","start_date":"2026-11-04T09:00:00Z","status_id":"hTFITko5Q0R83y"}]}},"rename":{"summary":"Rename a job and mark it rush","value":{"is_rush":true,"name":"Front and back print"}}},"schema":{"properties":{"has_service":{"description":"Accepted for older clients; it changes nothing.","type":"boolean"},"is_rush":{"description":"Marks the job as a rush job.","type":"boolean"},"mockup":{"description":"Mockup actions. Mockups are uploaded files attached to the job.","items":{"properties":{"action":{"enum":["create","update","delete"],"type":"string"},"approval_request_action":{"description":"For `delete`: what to do with open artwork approvals that include this mockup. `remove_open_items` takes it out of every open approval of the job, and deletes each approval left with nothing to approve. With `keep` (the default) a mockup under an open approval stays in that approval.","enum":["keep","remove_open_items"],"type":"string"},"id":{"description":"The uploaded file (for `create`) or the mockup.","example":"V4keXwwxMQyXw7","type":"string"},"job_service":{"description":"The job service or services the mockup shows.","items":{"type":"string"},"type":["string","array"]},"name":{"type":"string"},"position":{"description":"Required when `action` is `create`, but not used: YoPrint puts the new file last.","type":"integer"},"show_in_pdf":{"description":"Show it on the sales order PDF. Required unless `action` is `delete`.","type":"boolean"}},"required":["id","action"],"type":"object"},"type":"array"},"name":{"description":"The job name. A null is ignored (the name is kept).","type":"string"},"note":{"description":"The job note.","type":"string"},"pipeline":{"description":"Task actions.","items":{"properties":{"action":{"enum":["create","update","delete"],"type":"string"},"assigned_users":{"description":"User hash ids to assign.","items":{"type":"string"},"type":"array"},"due_date":{"description":"An ISO 8601 date or date-time, or null. Required (it may be null) when `action` is `create`.","format":"date-time","type":["string","null"]},"id":{"description":"The task. Required unless `action` is `create`.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"description":"The task name.","type":"string"},"pipeline_id":{"description":"The task preset. Required unless `action` is `delete`.","example":"V4keXwwxMQyXw7","type":"string"},"position":{"maximum":2147483647,"minimum":-2147483648,"type":"integer"},"start_date":{"description":"An ISO 8601 date or date-time, or null. Required (it may be null) when `action` is `create`.","format":"date-time","type":["string","null"]},"status_id":{"description":"A status of that task preset. Required unless `action` is `delete`.","example":"V4keXwwxMQyXw7","type":"string"},"unassigned_users":{"description":"User hash ids to unassign (`update` only).","items":{"type":"string"},"type":"array"}},"required":["action"],"type":"object"},"type":"array"},"position":{"description":"The job's place among the order's jobs. To reorder every job safely, use Reorder the jobs of a sales order or quote.","maximum":2147483647,"minimum":-2147483648,"type":"integer"},"production_file":{"description":"Production file actions.","items":{"properties":{"action":{"enum":["create","update","delete"],"type":"string"},"id":{"description":"The uploaded file (for `create`) or the production file.","example":"V4keXwwxMQyXw7","type":"string"},"job_service":{"description":"The job service or services the file is for.","items":{"type":"string"},"type":["string","array"]},"position":{"description":"Required when `action` is `create`, but not used: YoPrint puts the new file last.","type":"integer"}},"required":["id","action"],"type":"object"},"type":"array"},"scoped_id":{"description":"Accepted but ignored here. Use Change a job number.","type":"string"},"service":{"description":"Service actions (the decorations on the job).","items":{"properties":{"action":{"enum":["create","update","delete"],"type":"string"},"customer_note":{"description":"Customer notes.","type":"string"},"id":{"description":"Required for every action. For `update` and `delete`, the job service's hash id. For `create`, a temporary id you choose that starts with `tmpid-` (`tmpid-1`); `mockup` and `production_file` entries in the same call can name it in `job_service`. Any other made-up value fails as a bad hash id.","example":"tmpid-1","type":"string"},"location":{"description":"Where the service goes. Required unless `action` is `delete`.","properties":{"id":{"description":"The saved location. Required when `type` is `database`.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"description":"The location name. Required when `type` is `custom`.","example":"Left chest","type":"string"},"type":{"description":"`database` for one of your saved locations, `custom` for a name you type.","enum":["database","custom"],"type":"string"}},"type":"object"},"note":{"description":"Internal notes.","type":"string"},"option":{"description":"The service option, as your service defines it. Required unless `action` is `delete`.","example":"2"},"position":{"description":"Order of the service on the job. Required unless `action` is `delete`.","maximum":2147483647,"minimum":-2147483648,"type":"integer"},"service_id":{"description":"The service from your team's services. Required unless `action` is `delete`.","example":"V4keXwwxMQyXw7","type":"string"}},"required":["id","action"],"type":"object"},"type":"array"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"accepted":{"summary":"Done","value":{"data":{"assigned_users":[],"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"due_date":"2026-11-06T17:00:00+00:00","id":"WaGvtaWsx7Kcn4","is_rush":true,"item_count":48,"mockup":[],"name":"Front and back print","note":null,"order_id":"sFbALVSYD55eXe","order_scoped_id":"SO1001","pdf":[{"description":"Job details without mockup","label":"Job Details","url":"https://example.com/pdf/job-details.pdf"}],"pipelines":[{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-05T17:00:00+00:00","id":"hpioY1gDBQZdbI","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"hTFITko5Q0R83y","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T15:05:00+00:00"}],"position":1,"pricing_original_total":{"dp":6,"value":600000000},"pricing_rule_applied":null,"pricing_total":{"dp":6,"value":600000000},"production_file":[],"sales_order":{"is_quote":false,"is_rush":false,"name":"Team shirts","object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"scoped_id":"JOB-2419","services":[{"id":"tCBpDSBjXaPhHN","option":"2","position":1,"service_id":"5Sf6XRMN2Vuxvh","service_name":"Screen print"}],"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"scaWHQnPLtqMPT","label":"Printing","position":3,"role":"job","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"scaWHQnPLtqMPT","status_last_change_date":"2026-11-03T15:05:00+00:00","total_qty_need_ordering":"0.00000000","unique_key":"job_EXAMPLEuniqueKey"},"status":200,"success":true}},"refused":{"summary":"Refused with HTTP 200: `success` is false","value":{"error":{"code":"action_not_allowed","message":null},"status":500,"success":false}}},"schema":{"oneOf":[{"properties":{"data":{"additionalProperties":true,"description":"A job.","properties":{"approval_ready_mockup_design_count":{"type":"integer"},"assigned_users":{"description":"People on the job.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"auto_saved_for":{"description":"Set only on autosave copies.","example":null,"type":["string","null"]},"customer":{"additionalProperties":true,"properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"name":{"example":"Northwind Apparel","type":["string","null"]}},"type":"object"},"due_date":{"description":"Production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"from_legacy":{"type":"boolean"},"has_service":{"description":"Kept for older clients; not a count of services.","type":"boolean"},"id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"impression_count":{"type":["number","null"]},"inventory_status":{"description":"The stock status of the job's lines.","type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Units on the job.","example":48,"type":["number","null"]},"location_count":{"type":["number","null"]},"mockup":{"description":"Mockup files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"mockup_design_count":{"type":"integer"},"mockup_summary":{"additionalProperties":true,"properties":{"count":{"type":"integer"},"has_mockups":{"type":"boolean"}},"type":"object"},"name":{"example":"Team shirts","type":["string","null"]},"need_cust_provide_product":{"description":"Blanks are provided by the customer.","type":["boolean","integer","null"]},"note":{"type":["string","null"]},"order_customer_po_number":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pdf":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Job Details","type":"string"},"url":{"description":"A download link that carries its own long-lived access token: don't publish it.","example":"https://example.com/pdf/job-details.pdf","format":"uri","type":"string"}},"type":"object"},"type":"array"},"pending_approval":{"description":"The open approval request, if any."},"pipelines":{"description":"The job's tasks.","items":{"additionalProperties":true,"description":"A task.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"type":"array"},"position":{"example":1,"type":["integer","null"]},"pricing_original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price before pricing rules, at the stored scale. 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_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null. These answers usually carry only `type`, the two ids and the two totals. List the jobs of a sales order or quote and Get one job of a sales order or quote answer with the full summary (the rule's current name and position, the prices before and after).","oneOf":[{"additionalProperties":true,"properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","type":["string","null"]},"after_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price after the rule. 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."},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","type":["string","null"]},"base_type":{"description":"Full summary only: `service_price`.","type":["string","null"]},"normal_price":{"description":"Full summary only: the price with no rule (the same as `base` for a job).","type":["string","null"]},"original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price before the rule. 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_id":{"description":"The pricing group.","example":"V4keXwwxMQyXw7","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The pricing rule.","example":"V4keXwwxMQyXw7","type":["string","null"]},"rule":{"description":"Full summary only: the rule as the group holds it now (`id`, `label`, `position`, where 1 is the first rule checked), or null when it no longer exists.","type":["object","null"]},"type":{"description":"`service` on a job.","type":["string","null"]}},"type":"object"},{"type":"null"}]},"pricing_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price, at the stored scale (usually 6 decimal places: `{ \"value\": 600000000, \"dp\": 6 }` is 600.00). 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."},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"qr_code_url":{"description":"A QR code image for the job.","example":"https://example.com/qr/job.png","type":["string","null"]},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"name":{"description":"Order name.","example":"Team shirts","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number as shown, with its `JOB-` prefix. Change a job number takes only the digits.","example":"JOB-2419","type":"string"},"services":{"description":"The services (decorations).","items":{"additionalProperties":true,"properties":{"customer_note":{"description":"Customer notes.","type":["string","null"]},"id":{"description":"The job service.","example":"tCBpDSBjXaPhHN","type":"string"},"location":{"additionalProperties":true,"type":"object"},"note":{"description":"Internal notes.","type":["string","null"]},"option":{"description":"The service option."},"position":{"type":["integer","null"]},"pricing_total":{"description":"A decimal pair, or null."},"service_id":{"description":"The service.","example":"5Sf6XRMN2Vuxvh","type":"string"},"service_name":{"example":"Screen print","type":"string"}},"type":"object"},"type":"array"},"services_still_valid":{"type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The job's current status: its production stage. Look it up in List job statuses, or read `status`.","example":"scaWHQnPLtqMPT","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"total_qty_need_ordering":{"description":"Quantity that still needs ordering, with 8 decimal places (`\"12.00000000\"`). A decimal string, such as `\"0.00000000\"`; parse it as a decimal.","example":"0.00000000","type":["string","null"]},"unique_key":{"description":"The job's unique key.","example":"job_EXAMPLEuniqueKey","type":["string","null"]},"version":{"example":2,"type":"integer"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"const":true,"example":true,"type":"boolean"}},"required":["success","status","data"],"title":"Success","type":"object"},{"$ref":"#/components/schemas/ErrorResponse"}]}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a job","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Read `error.fields` and resend the entries.","status":422,"when":"A list entry breaks its field rules (for example a service without `location.type`): `validation_failed`."},{"fix":"Correct that entry and resend.","status":422,"when":"A service, option, task preset or task status is not valid, a task gets only one of its two dates, or a file wasn't uploaded first: `job_validation_error`, with the reason in `error.message` and no `error.fields`."},{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order (`user_is_not_authorized`)."},{"fix":"Use the job's hash id (`id`) from the order's job list; unique keys don't work in this path.","status":404,"when":"The job isn't your team's, its order is an old (version 1) order, or an entry's `id` (task, mockup, production file) isn't on this job. Jobs on quotes work too."},{"fix":"Check `success` in every reply, not only the HTTP status.","status":200,"when":"The order is neither a draft nor published (`success: false`, `action_not_allowed`)."}],"group":"Production","notes":["A refusal here is HTTP 200 with `success: false` and `error.code` `action_not_allowed` (the body's `status` says 500). A client that only checks the HTTP status will treat it as done.","Do not send `status_id` here. Use Change a job's status, which checks the status and sends the status webhook.","Mockup and production file `create` entries take the hash id of a file you uploaded first with the async upload (`v1.public.async_upload.store`); any other id is a 422."],"permission":"Needs permission to edit the job's sales order:\n- the team owner;\n- a role whose Manage Sales Orders permission is \"update all\";\n- a role with \"update assigned\" when you created the order or are assigned to it; or\n- on a draft order, its creator when their role can create sales orders.\n\nOtherwise 403 `user_is_not_authorized`.","related":["v2_public_job_show","v2_public_job_change_status","v2_public_job_update_scoped_id","v2_public_job_update_prod_date","v2_public_job_rearrange"],"rules":["The job's sales order must be a draft or published. Otherwise the reply is HTTP 200 with `success: false` and `error.code` `action_not_allowed` and nothing changes.","Every list entry needs an `action`. `service` entries need `service_id`, `option`, `location` and `position` unless they delete.","A task's `status_id` must belong to its `pipeline_id` (task preset)."],"side_effects":["Changing services reprices the job and recalculates the order, its invoices and shipments that share pricing tiers.","Turning `is_rush` on or off sends the `job.marked_as_rush` or `job.marked_as_not_rush` webhook.","Deleting a mockup with `approval_request_action: remove_open_items` changes the job's open artwork approvals (see the field); Customer Portal pages the customer has open refresh for the approvals that remain.","Open Admin Portal pages refresh."]}}},"/v2/api/store/{team_slug}/v2/job/{hash_id}/clone":{"put":{"description":"Copies a job into a sales order or quote: the same one or another of your team's. Returns the new job.\n\nBy default the copy takes the job's line items, tasks, mockups and files, but not its approvals. Dates keep their distance from the order's issue date: the copy starts and is due as long after the target order's issue date as the original is after its own order's (so within the same order they don't change). A job without both dates uses its tasks' earliest start and latest due date; with neither, the copy is unscheduled.\n\nLines on phased-out or deleted products, sizes or colors are never copied as they are. If the job has any, the first call is refused with `clone_needs_choices`, which lists them. Call again with an `item_choices` entry for each: leave it out, or replace it with another size or color of the same product that is still sold.","operationId":"v2_public_job_clone","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"WaGvtaWsx7Kcn4","in":"path","name":"hash_id","required":true,"schema":{"example":"WaGvtaWsx7Kcn4","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"same_order":{"summary":"Copy a job within its order","value":{"target_order":"sFbALVSYD55eXe"}},"with_choices":{"summary":"Copy with choices for unsellable lines","value":{"clone_job_approval":false,"item_choices":[{"action":"leave_out","id":"ZJTJ2uF5dMiArL"},{"action":"replace","id":"Py196Qo19s55qk","replacement_id":"Tl6eTHKHoKqrMw"}],"target_order":"yYkdcUrFwnbqE2"}}},"schema":{"properties":{"clone_job_approval":{"default":false,"description":"Copy the job's approvals. Fails with 500 when an approval includes mockup designs, or includes files while `clone_media` is false.","type":"boolean"},"clone_media":{"default":true,"description":"Copy the mockups and production files.","type":"boolean"},"clone_mockup_designs":{"description":"Copy mockup designs. Defaults to `clone_media`.","type":"boolean"},"clone_order_item":{"default":true,"description":"Copy the line items. Ignored (never copied) when either order came from Shopify.","type":"boolean"},"clone_work_pipeline":{"default":true,"description":"Copy the tasks.","type":"boolean"},"item_choices":{"description":"One choice per line that uses a phased-out or deleted product, size or color. Only for those lines.","items":{"properties":{"action":{"enum":["leave_out","replace"],"type":"string"},"id":{"description":"The line item on the source job. Each line at most once.","example":"V4keXwwxMQyXw7","type":"string"},"replacement_id":{"description":"Required for `replace`: another size or color (variant) of the same product that is still on sale.","example":"V4keXwwxMQyXw7","type":"string"}},"required":["id","action"],"type":"object"},"type":"array"},"target_order":{"description":"The sales order or quote to copy into (hash id or unique key). It can be the job's own order.","example":"V4keXwwxMQyXw7","type":"string"}},"required":["target_order"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"due_date":"2026-11-06T17:00:00+00:00","id":"6E8Ybl4wnA5yBW","is_rush":true,"item_count":48,"mockup":[],"name":"Front print","note":null,"order_id":"sFbALVSYD55eXe","order_scoped_id":"SO1001","pdf":[{"description":"Job details without mockup","label":"Job Details","url":"https://example.com/pdf/job-details.pdf"}],"pipelines":[{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-05T17:00:00+00:00","id":"iv0dBo17IwYGzb","job_id":"6E8Ybl4wnA5yBW","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2420","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"hTFITko5Q0R83y","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T15:05:00+00:00"}],"position":1,"pricing_original_total":{"dp":6,"value":600000000},"pricing_rule_applied":null,"pricing_total":{"dp":6,"value":600000000},"production_file":[],"sales_order":{"is_quote":false,"is_rush":false,"name":"Team shirts","object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"scoped_id":"JOB-2420","services":[{"id":"tCBpDSBjXaPhHN","option":"2","position":1,"service_id":"5Sf6XRMN2Vuxvh","service_name":"Screen print"}],"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"scaWHQnPLtqMPT","label":"Printing","position":3,"role":"job","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"scaWHQnPLtqMPT","status_last_change_date":"2026-11-03T15:05:00+00:00","total_qty_need_ordering":"0.00000000","unique_key":"job_EXAMPLEuniqueKe2"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A job.","properties":{"approval_ready_mockup_design_count":{"type":"integer"},"assigned_users":{"description":"People on the job.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"auto_saved_for":{"description":"Set only on autosave copies.","example":null,"type":["string","null"]},"customer":{"additionalProperties":true,"properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"name":{"example":"Northwind Apparel","type":["string","null"]}},"type":"object"},"due_date":{"description":"Production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"from_legacy":{"type":"boolean"},"has_service":{"description":"Kept for older clients; not a count of services.","type":"boolean"},"id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"impression_count":{"type":["number","null"]},"inventory_status":{"description":"The stock status of the job's lines.","type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Units on the job.","example":48,"type":["number","null"]},"location_count":{"type":["number","null"]},"mockup":{"description":"Mockup files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"mockup_design_count":{"type":"integer"},"mockup_summary":{"additionalProperties":true,"properties":{"count":{"type":"integer"},"has_mockups":{"type":"boolean"}},"type":"object"},"name":{"example":"Team shirts","type":["string","null"]},"need_cust_provide_product":{"description":"Blanks are provided by the customer.","type":["boolean","integer","null"]},"note":{"type":["string","null"]},"order_customer_po_number":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pdf":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Job Details","type":"string"},"url":{"description":"A download link that carries its own long-lived access token: don't publish it.","example":"https://example.com/pdf/job-details.pdf","format":"uri","type":"string"}},"type":"object"},"type":"array"},"pending_approval":{"description":"The open approval request, if any."},"pipelines":{"description":"The job's tasks.","items":{"additionalProperties":true,"description":"A task.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"type":"array"},"position":{"example":1,"type":["integer","null"]},"pricing_original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price before pricing rules, at the stored scale. 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_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null. These answers usually carry only `type`, the two ids and the two totals. List the jobs of a sales order or quote and Get one job of a sales order or quote answer with the full summary (the rule's current name and position, the prices before and after).","oneOf":[{"additionalProperties":true,"properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","type":["string","null"]},"after_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price after the rule. 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."},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","type":["string","null"]},"base_type":{"description":"Full summary only: `service_price`.","type":["string","null"]},"normal_price":{"description":"Full summary only: the price with no rule (the same as `base` for a job).","type":["string","null"]},"original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price before the rule. 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_id":{"description":"The pricing group.","example":"V4keXwwxMQyXw7","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The pricing rule.","example":"V4keXwwxMQyXw7","type":["string","null"]},"rule":{"description":"Full summary only: the rule as the group holds it now (`id`, `label`, `position`, where 1 is the first rule checked), or null when it no longer exists.","type":["object","null"]},"type":{"description":"`service` on a job.","type":["string","null"]}},"type":"object"},{"type":"null"}]},"pricing_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price, at the stored scale (usually 6 decimal places: `{ \"value\": 600000000, \"dp\": 6 }` is 600.00). 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."},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"qr_code_url":{"description":"A QR code image for the job.","example":"https://example.com/qr/job.png","type":["string","null"]},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"name":{"description":"Order name.","example":"Team shirts","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number as shown, with its `JOB-` prefix. Change a job number takes only the digits.","example":"JOB-2419","type":"string"},"services":{"description":"The services (decorations).","items":{"additionalProperties":true,"properties":{"customer_note":{"description":"Customer notes.","type":["string","null"]},"id":{"description":"The job service.","example":"tCBpDSBjXaPhHN","type":"string"},"location":{"additionalProperties":true,"type":"object"},"note":{"description":"Internal notes.","type":["string","null"]},"option":{"description":"The service option."},"position":{"type":["integer","null"]},"pricing_total":{"description":"A decimal pair, or null."},"service_id":{"description":"The service.","example":"5Sf6XRMN2Vuxvh","type":"string"},"service_name":{"example":"Screen print","type":"string"}},"type":"object"},"type":"array"},"services_still_valid":{"type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The job's current status: its production stage. Look it up in List job statuses, or read `status`.","example":"scaWHQnPLtqMPT","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"total_qty_need_ordering":{"description":"Quantity that still needs ordering, with 8 decimal places (`\"12.00000000\"`). A decimal string, such as `\"0.00000000\"`; parse it as a decimal.","example":"0.00000000","type":["string","null"]},"unique_key":{"description":"The job's unique key.","example":"job_EXAMPLEuniqueKey","type":["string","null"]},"version":{"example":2,"type":"integer"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Copy a job","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Send one `item_choices` entry for each listed line, then call again.","status":422,"when":"Lines need choices: `clone_needs_choices`, with the lines in `error.lines` and their jobs in `error.jobs` (directly under `error`, not in `error.data`). Each line has `id`, `job_id`, `product_id`, `product_name`, `product_type`, `quantity` (a decimal string), `reason` (`variant_phased_out`, `variant_deleted`, `product_phased_out` or `product_deleted`) and, for variant products, `product_size`, `product_color`, `size_id` and `color_id`. Each job has `id`, `scoped_id` (`JOB-126`), `name` and `keeps_products`."},{"fix":"Correct `item_choices` as the rules say, then call again.","status":422,"when":"A choice is refused: `clone_choice_not_needed` (same `error.lines` and `error.jobs`, listing the lines that are on sale again), `clone_choice_unknown_line` (the unknown line ids in `error.ids`) or `clone_replacement_invalid` (the line in `error.line`)."},{"fix":"Ask the team owner to adjust your role or assign you to the orders.","status":403,"when":"You can't view the source order or edit the target order."},{"fix":"Check both ids.","status":404,"when":"The job or `target_order` isn't your team's."},{"fix":"Copy without approvals, or keep `clone_media` on.","status":500,"when":"With `clone_job_approval`: an approval includes mockup designs, or it includes files and `clone_media` is false. The body is `{ \"message\": \"Server Error\" }` and nothing is copied."}],"group":"Production","permission":"Needs permission to view the source order and to edit the target order (team owner, Manage Sales Orders \"update all\", or \"update assigned\" on orders you created or are assigned to; for a draft target, also its creator when their role can create sales orders).","related":["v2_public_job_show","v2_public_job_update","v2_public_job_destroy"],"rules":["A choice for a line that is on sale is refused with `clone_choice_not_needed`; a choice naming a line that isn't on the job with `clone_choice_unknown_line`.","A product without sizes or colors can only be left out: `replace` on it is `clone_replacement_invalid`.","A replacement must be another variant of the same product that is still sold (`clone_replacement_invalid`).","Nothing is copied when a choice is refused."],"side_effects":["Creates the job, and copies of its lines, tasks and files as chosen.","Recalculates the target order and may run its auto-invoicing; neither happens when the target order came from Shopify.","Open Admin Portal pages refresh after the copy is saved."]}}},"/v2/api/store/{team_slug}/v2/job/{hash_id}/scoped_id":{"put":{"description":"Sets the job number (`scoped_id`, shown as `JOB-<number>`). Returns the updated job.\n\nThe value is saved as sent: it isn't validated or checked for duplicates, so check your numbering before you call.","operationId":"v2_public_job_update_scoped_id","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"WaGvtaWsx7Kcn4","in":"path","name":"hash_id","required":true,"schema":{"example":"WaGvtaWsx7Kcn4","type":"string"}},{"description":"Optional. `1` (or `true`, `yes`, `on`) makes the answer smaller: each mockup and production file's `current_approval` leaves out its `items` list, and every other key stays as it is. The job's `pending_approval` and webhook payloads keep their items. Every file repeats its approval with all of its items, so a job with many files on one approval answers with far less data this way; read approval items from the approvals operations instead. Left out (or any other value), the answer is unchanged. Only the query string is read: a body field with this name is ignored.","example":"1","in":"query","name":"omit_media_approval_items","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"scoped_id":"2419"},"schema":{"properties":{"scoped_id":{"description":"The new job number, without the `JOB-` prefix. Always send it: leaving it out clears the number.","example":"2419","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"due_date":"2026-11-06T17:00:00+00:00","id":"WaGvtaWsx7Kcn4","is_rush":true,"item_count":48,"mockup":[],"name":"Front print","note":null,"order_id":"sFbALVSYD55eXe","order_scoped_id":"SO1001","pdf":[{"description":"Job details without mockup","label":"Job Details","url":"https://example.com/pdf/job-details.pdf"}],"pipelines":[{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-05T17:00:00+00:00","id":"hpioY1gDBQZdbI","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"hTFITko5Q0R83y","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T15:05:00+00:00"}],"position":1,"pricing_original_total":{"dp":6,"value":600000000},"pricing_rule_applied":null,"pricing_total":{"dp":6,"value":600000000},"production_file":[],"sales_order":{"is_quote":false,"is_rush":false,"name":"Team shirts","object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"scoped_id":"JOB-2419","services":[{"id":"tCBpDSBjXaPhHN","option":"2","position":1,"service_id":"5Sf6XRMN2Vuxvh","service_name":"Screen print"}],"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"scaWHQnPLtqMPT","label":"Printing","position":3,"role":"job","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"scaWHQnPLtqMPT","status_last_change_date":"2026-11-03T15:05:00+00:00","total_qty_need_ordering":"0.00000000","unique_key":"job_EXAMPLEuniqueKey"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A job.","properties":{"approval_ready_mockup_design_count":{"type":"integer"},"assigned_users":{"description":"People on the job.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"auto_saved_for":{"description":"Set only on autosave copies.","example":null,"type":["string","null"]},"customer":{"additionalProperties":true,"properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"name":{"example":"Northwind Apparel","type":["string","null"]}},"type":"object"},"due_date":{"description":"Production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"from_legacy":{"type":"boolean"},"has_service":{"description":"Kept for older clients; not a count of services.","type":"boolean"},"id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"impression_count":{"type":["number","null"]},"inventory_status":{"description":"The stock status of the job's lines.","type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Units on the job.","example":48,"type":["number","null"]},"location_count":{"type":["number","null"]},"mockup":{"description":"Mockup files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"mockup_design_count":{"type":"integer"},"mockup_summary":{"additionalProperties":true,"properties":{"count":{"type":"integer"},"has_mockups":{"type":"boolean"}},"type":"object"},"name":{"example":"Team shirts","type":["string","null"]},"need_cust_provide_product":{"description":"Blanks are provided by the customer.","type":["boolean","integer","null"]},"note":{"type":["string","null"]},"order_customer_po_number":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pdf":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Job Details","type":"string"},"url":{"description":"A download link that carries its own long-lived access token: don't publish it.","example":"https://example.com/pdf/job-details.pdf","format":"uri","type":"string"}},"type":"object"},"type":"array"},"pending_approval":{"description":"The open approval request, if any."},"pipelines":{"description":"The job's tasks.","items":{"additionalProperties":true,"description":"A task.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"type":"array"},"position":{"example":1,"type":["integer","null"]},"pricing_original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price before pricing rules, at the stored scale. 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_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null. These answers usually carry only `type`, the two ids and the two totals. List the jobs of a sales order or quote and Get one job of a sales order or quote answer with the full summary (the rule's current name and position, the prices before and after).","oneOf":[{"additionalProperties":true,"properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","type":["string","null"]},"after_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price after the rule. 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."},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","type":["string","null"]},"base_type":{"description":"Full summary only: `service_price`.","type":["string","null"]},"normal_price":{"description":"Full summary only: the price with no rule (the same as `base` for a job).","type":["string","null"]},"original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price before the rule. 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_id":{"description":"The pricing group.","example":"V4keXwwxMQyXw7","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The pricing rule.","example":"V4keXwwxMQyXw7","type":["string","null"]},"rule":{"description":"Full summary only: the rule as the group holds it now (`id`, `label`, `position`, where 1 is the first rule checked), or null when it no longer exists.","type":["object","null"]},"type":{"description":"`service` on a job.","type":["string","null"]}},"type":"object"},{"type":"null"}]},"pricing_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price, at the stored scale (usually 6 decimal places: `{ \"value\": 600000000, \"dp\": 6 }` is 600.00). 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."},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"qr_code_url":{"description":"A QR code image for the job.","example":"https://example.com/qr/job.png","type":["string","null"]},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"name":{"description":"Order name.","example":"Team shirts","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number as shown, with its `JOB-` prefix. Change a job number takes only the digits.","example":"JOB-2419","type":"string"},"services":{"description":"The services (decorations).","items":{"additionalProperties":true,"properties":{"customer_note":{"description":"Customer notes.","type":["string","null"]},"id":{"description":"The job service.","example":"tCBpDSBjXaPhHN","type":"string"},"location":{"additionalProperties":true,"type":"object"},"note":{"description":"Internal notes.","type":["string","null"]},"option":{"description":"The service option."},"position":{"type":["integer","null"]},"pricing_total":{"description":"A decimal pair, or null."},"service_id":{"description":"The service.","example":"5Sf6XRMN2Vuxvh","type":"string"},"service_name":{"example":"Screen print","type":"string"}},"type":"object"},"type":"array"},"services_still_valid":{"type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The job's current status: its production stage. Look it up in List job statuses, or read `status`.","example":"scaWHQnPLtqMPT","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"total_qty_need_ordering":{"description":"Quantity that still needs ordering, with 8 decimal places (`\"12.00000000\"`). A decimal string, such as `\"0.00000000\"`; parse it as a decimal.","example":"0.00000000","type":["string","null"]},"unique_key":{"description":"The job's unique key.","example":"job_EXAMPLEuniqueKey","type":["string","null"]},"version":{"example":2,"type":"integer"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change a job number","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order."},{"fix":"Check the job id.","status":404,"when":"The job isn't your team's, or its order is an old (version 1) order. Jobs on quotes work too."}],"group":"Production","notes":["Leaving `scoped_id` out clears the number. Always send it."],"permission":"Needs permission to edit the job's sales order:\n- the team owner;\n- a role whose Manage Sales Orders permission is \"update all\";\n- a role with \"update assigned\" when you created the order or are assigned to it; or\n- on a draft order, its creator when their role can create sales orders.\n\nOtherwise 403 `user_is_not_authorized`.","related":["v2_public_job_show","v2_public_job_update"],"rules":["The `JOB-` prefix is added when the number is shown; send the bare number."]}}},"/v2/api/store/{team_slug}/v2/job/{hash_id}/status":{"put":{"description":"**Check `success`, not only the HTTP status:** when the job's order isn't published (a draft), this call answers **HTTP 200** with `{ \"status\": 500, \"success\": false, \"error\": { \"code\": \"action_not_allowed\", \"message\": null } }` and changes nothing.\n\nMoves a job to another of your team's job statuses. Returns the job with `previous_status_id`, `previous_status` and `participant_emails` (the order's message participants who receive email).\n\nA job's production stage is its status. The job's current status is `status_id` (and the `status` object, with its `label`, `type` and `position`) on the job, as Get one job of an order and the job lists return it. Statuses are set up per team (List job statuses); each has a type: Pending (`start`), In Progress (`pre_production` or `in_progress`) or Completed (`end`).\n\nTo move a job to the next stage: read the job's `status_id`, list the job statuses, sort them by `position`, send the id of the one after the current one here, and check `success` in the reply. Tasks are separate: they track the steps inside a job, and finishing them doesn't move the job.\n\nSending the status the job already has is accepted and changes nothing.","operationId":"v2_public_job_change_status","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"WaGvtaWsx7Kcn4","in":"path","name":"hash_id","required":true,"schema":{"example":"WaGvtaWsx7Kcn4","type":"string"}},{"description":"Optional. `1` (or `true`, `yes`, `on`) makes the answer smaller: each mockup and production file's `current_approval` leaves out its `items` list, and every other key stays as it is. The job's `pending_approval` and webhook payloads keep their items. Every file repeats its approval with all of its items, so a job with many files on one approval answers with far less data this way; read approval items from the approvals operations instead. Left out (or any other value), the answer is unchanged. Only the query string is read: a body field with this name is ignored.","example":"1","in":"query","name":"omit_media_approval_items","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"status_id":"scaWHQnPLtqMPT"},"schema":{"properties":{"notify_customer":{"description":"Accepted and ignored: this route sends the customer nothing.","type":["boolean","null"]},"status_id":{"description":"A job status of your team (from List job statuses).","example":"V4keXwwxMQyXw7","type":"string"}},"required":["status_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"accepted":{"summary":"Done","value":{"data":{"assigned_users":[],"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"due_date":"2026-11-06T17:00:00+00:00","id":"WaGvtaWsx7Kcn4","is_rush":true,"item_count":48,"mockup":[],"name":"Front print","note":null,"order_id":"sFbALVSYD55eXe","order_scoped_id":"SO1001","participant_emails":["alex@example.com"],"pdf":[{"description":"Job details without mockup","label":"Job Details","url":"https://example.com/pdf/job-details.pdf"}],"pipelines":[{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-05T17:00:00+00:00","id":"hpioY1gDBQZdbI","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"hTFITko5Q0R83y","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T15:05:00+00:00"}],"position":1,"previous_status":{"color":"#9e9e9e","customer_label":"Pending","id":"P32Ic61q2HqUCD","label":"Artwork","position":2,"role":"job","trashed":false,"type":"start"},"previous_status_id":"P32Ic61q2HqUCD","pricing_original_total":{"dp":6,"value":600000000},"pricing_rule_applied":null,"pricing_total":{"dp":6,"value":600000000},"production_file":[],"sales_order":{"is_quote":false,"is_rush":false,"name":"Team shirts","object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"scoped_id":"JOB-2419","services":[{"id":"tCBpDSBjXaPhHN","option":"2","position":1,"service_id":"5Sf6XRMN2Vuxvh","service_name":"Screen print"}],"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"scaWHQnPLtqMPT","label":"Printing","position":3,"role":"job","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"scaWHQnPLtqMPT","status_last_change_date":"2026-11-03T15:05:00+00:00","total_qty_need_ordering":"0.00000000","unique_key":"job_EXAMPLEuniqueKey"},"status":200,"success":true}},"refused":{"summary":"Refused with HTTP 200: `success` is false","value":{"error":{"code":"action_not_allowed","message":null},"status":500,"success":false}}},"schema":{"oneOf":[{"properties":{"data":{"additionalProperties":true,"description":"The job after the change, with the status it had before.","properties":{"approval_ready_mockup_design_count":{"type":"integer"},"assigned_users":{"description":"People on the job.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"auto_saved_for":{"description":"Set only on autosave copies.","example":null,"type":["string","null"]},"customer":{"additionalProperties":true,"properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"name":{"example":"Northwind Apparel","type":["string","null"]}},"type":"object"},"due_date":{"description":"Production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"from_legacy":{"type":"boolean"},"has_service":{"description":"Kept for older clients; not a count of services.","type":"boolean"},"id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"impression_count":{"type":["number","null"]},"inventory_status":{"description":"The stock status of the job's lines.","type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Units on the job.","example":48,"type":["number","null"]},"location_count":{"type":["number","null"]},"mockup":{"description":"Mockup files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"mockup_design_count":{"type":"integer"},"mockup_summary":{"additionalProperties":true,"properties":{"count":{"type":"integer"},"has_mockups":{"type":"boolean"}},"type":"object"},"name":{"example":"Team shirts","type":["string","null"]},"need_cust_provide_product":{"description":"Blanks are provided by the customer.","type":["boolean","integer","null"]},"note":{"type":["string","null"]},"order_customer_po_number":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"participant_emails":{"description":"The order's message participants who receive email.","items":{"example":"alex@example.com","type":"string"},"type":"array"},"pdf":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Job Details","type":"string"},"url":{"description":"A download link that carries its own long-lived access token: don't publish it.","example":"https://example.com/pdf/job-details.pdf","format":"uri","type":"string"}},"type":"object"},"type":"array"},"pending_approval":{"description":"The open approval request, if any."},"pipelines":{"description":"The job's tasks.","items":{"additionalProperties":true,"description":"A task.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"type":"array"},"position":{"example":1,"type":["integer","null"]},"previous_status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"previous_status_id":{"description":"The status before this call.","example":"P32Ic61q2HqUCD","type":["string","null"]},"pricing_original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price before pricing rules, at the stored scale. 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_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null. These answers usually carry only `type`, the two ids and the two totals. List the jobs of a sales order or quote and Get one job of a sales order or quote answer with the full summary (the rule's current name and position, the prices before and after).","oneOf":[{"additionalProperties":true,"properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","type":["string","null"]},"after_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price after the rule. 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."},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","type":["string","null"]},"base_type":{"description":"Full summary only: `service_price`.","type":["string","null"]},"normal_price":{"description":"Full summary only: the price with no rule (the same as `base` for a job).","type":["string","null"]},"original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price before the rule. 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_id":{"description":"The pricing group.","example":"V4keXwwxMQyXw7","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The pricing rule.","example":"V4keXwwxMQyXw7","type":["string","null"]},"rule":{"description":"Full summary only: the rule as the group holds it now (`id`, `label`, `position`, where 1 is the first rule checked), or null when it no longer exists.","type":["object","null"]},"type":{"description":"`service` on a job.","type":["string","null"]}},"type":"object"},{"type":"null"}]},"pricing_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price, at the stored scale (usually 6 decimal places: `{ \"value\": 600000000, \"dp\": 6 }` is 600.00). 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."},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"qr_code_url":{"description":"A QR code image for the job.","example":"https://example.com/qr/job.png","type":["string","null"]},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"name":{"description":"Order name.","example":"Team shirts","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number as shown, with its `JOB-` prefix. Change a job number takes only the digits.","example":"JOB-2419","type":"string"},"services":{"description":"The services (decorations).","items":{"additionalProperties":true,"properties":{"customer_note":{"description":"Customer notes.","type":["string","null"]},"id":{"description":"The job service.","example":"tCBpDSBjXaPhHN","type":"string"},"location":{"additionalProperties":true,"type":"object"},"note":{"description":"Internal notes.","type":["string","null"]},"option":{"description":"The service option."},"position":{"type":["integer","null"]},"pricing_total":{"description":"A decimal pair, or null."},"service_id":{"description":"The service.","example":"5Sf6XRMN2Vuxvh","type":"string"},"service_name":{"example":"Screen print","type":"string"}},"type":"object"},"type":"array"},"services_still_valid":{"type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The job's current status: its production stage. Look it up in List job statuses, or read `status`.","example":"scaWHQnPLtqMPT","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"total_qty_need_ordering":{"description":"Quantity that still needs ordering, with 8 decimal places (`\"12.00000000\"`). A decimal string, such as `\"0.00000000\"`; parse it as a decimal.","example":"0.00000000","type":["string","null"]},"unique_key":{"description":"The job's unique key.","example":"job_EXAMPLEuniqueKey","type":["string","null"]},"version":{"example":2,"type":"integer"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"const":true,"example":true,"type":"boolean"}},"required":["success","status","data"],"title":"Success","type":"object"},{"$ref":"#/components/schemas/ErrorResponse"}]}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change a job's status","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Use a status id from List job statuses.","status":404,"when":"The job or the status isn't your team's, the job's order is an old (version 1) order, or the status isn't a job status."},{"fix":"Send `status_id`.","status":422,"when":"`status_id` is missing or not a hash id."},{"fix":"Publish the order first. Always check `success`.","status":200,"when":"The order isn't published (`success: false`, `action_not_allowed`)."}],"group":"Production","notes":["A refusal here is HTTP 200 with `success: false` and `error.code` `action_not_allowed` (the body's `status` says 500). A client that only checks the HTTP status will treat it as done."],"permission":"Any member of the team; this route checks no sales order permission.","related":["v1_public_status_list_job","v2_public_job_show","v2_public_job_work_pipeline_change_status"],"rules":["The job's order must be published. On a draft the reply is HTTP 200 with `success: false` and `error.code` `action_not_allowed`, and nothing changes.","The status must be a job status of your team; a task preset status is a 404."],"side_effects":["Sends the `job.status_changed` webhook, only when the status really changed.","Records the change in the status history and the order's activity log, and updates `status_last_change_date` (and `status_completion_date` for a Completed status).","Moving to a Completed status rechecks the order's shipments: a shipment whose jobs are all Completed is marked ready to ship."]}}},"/v2/api/store/{team_slug}/v2/job/{hash_id}/update_prod_date":{"put":{"description":"Sets, moves or clears a job's production start and due dates. Returns the job, with every task's new dates, and a top-level `previous_schedule` next to `data`: the job and task dates as they were before the call.\n\n- To schedule or move, send both dates. If every dated task still fits inside the new dates, the tasks stay where they are. Otherwise all dated tasks shift together so the earliest starts at the new `start_date`; a task start that would fall before the new `start_date` is set to it, a task due date that would fall after the new `due_date` is set to it, and a dated task without a due date gets the new due date.\n- To unschedule, send both as `null`. Every task of the job loses its dates too. To undo, the web app sends the `previous_schedule` back to its restore call, which is not on the public API, so keep that value if you may need it.\n\nAlways send both keys: leaving both out (`{}`) is the same as sending both null, and unschedules the job.","operationId":"v2_public_job_update_prod_date","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"WaGvtaWsx7Kcn4","in":"path","name":"hash_id","required":true,"schema":{"example":"WaGvtaWsx7Kcn4","type":"string"}},{"description":"Optional. `1` (or `true`, `yes`, `on`) makes the answer smaller: each mockup and production file's `current_approval` leaves out its `items` list, and every other key stays as it is. The job's `pending_approval` and webhook payloads keep their items. Every file repeats its approval with all of its items, so a job with many files on one approval answers with far less data this way; read approval items from the approvals operations instead. Left out (or any other value), the answer is unchanged. Only the query string is read: a body field with this name is ignored.","example":"1","in":"query","name":"omit_media_approval_items","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"schedule":{"summary":"Schedule or move","value":{"due_date":"2026-11-06T17:00:00Z","start_date":"2026-11-04T09:00:00Z"}},"unschedule":{"summary":"Unschedule","value":{"due_date":null,"start_date":null}}},"schema":{"properties":{"due_date":{"description":"The production due date (an ISO 8601 date or date-time), or null to unschedule. Not before `start_date`.","format":"date-time","type":["string","null"]},"start_date":{"description":"The production start (an ISO 8601 date or date-time), or null to unschedule.","format":"date-time","type":["string","null"]}},"required":["start_date","due_date"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"due_date":"2026-11-06T17:00:00+00:00","id":"WaGvtaWsx7Kcn4","is_rush":true,"item_count":48,"mockup":[],"name":"Front print","note":null,"order_id":"sFbALVSYD55eXe","order_scoped_id":"SO1001","pdf":[{"description":"Job details without mockup","label":"Job Details","url":"https://example.com/pdf/job-details.pdf"}],"pipelines":[{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-05T17:00:00+00:00","id":"hpioY1gDBQZdbI","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"hTFITko5Q0R83y","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T15:05:00+00:00"}],"position":1,"pricing_original_total":{"dp":6,"value":600000000},"pricing_rule_applied":null,"pricing_total":{"dp":6,"value":600000000},"production_file":[],"sales_order":{"is_quote":false,"is_rush":false,"name":"Team shirts","object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"scoped_id":"JOB-2419","services":[{"id":"tCBpDSBjXaPhHN","option":"2","position":1,"service_id":"5Sf6XRMN2Vuxvh","service_name":"Screen print"}],"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"scaWHQnPLtqMPT","label":"Printing","position":3,"role":"job","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"scaWHQnPLtqMPT","status_last_change_date":"2026-11-03T15:05:00+00:00","total_qty_need_ordering":"0.00000000","unique_key":"job_EXAMPLEuniqueKey"},"previous_schedule":{"due_date":"2026-11-05T17:00:00+00:00","job_id":"WaGvtaWsx7Kcn4","start_date":"2026-11-03T09:00:00+00:00","tasks":[{"due_date":"2026-11-04T17:00:00+00:00","id":"hpioY1gDBQZdbI","start_date":"2026-11-03T09:00:00+00:00"}]},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A job.","properties":{"approval_ready_mockup_design_count":{"type":"integer"},"assigned_users":{"description":"People on the job.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"auto_saved_for":{"description":"Set only on autosave copies.","example":null,"type":["string","null"]},"customer":{"additionalProperties":true,"properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"name":{"example":"Northwind Apparel","type":["string","null"]}},"type":"object"},"due_date":{"description":"Production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"from_legacy":{"type":"boolean"},"has_service":{"description":"Kept for older clients; not a count of services.","type":"boolean"},"id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"impression_count":{"type":["number","null"]},"inventory_status":{"description":"The stock status of the job's lines.","type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Units on the job.","example":48,"type":["number","null"]},"location_count":{"type":["number","null"]},"mockup":{"description":"Mockup files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"mockup_design_count":{"type":"integer"},"mockup_summary":{"additionalProperties":true,"properties":{"count":{"type":"integer"},"has_mockups":{"type":"boolean"}},"type":"object"},"name":{"example":"Team shirts","type":["string","null"]},"need_cust_provide_product":{"description":"Blanks are provided by the customer.","type":["boolean","integer","null"]},"note":{"type":["string","null"]},"order_customer_po_number":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pdf":{"description":"PDF links.","items":{"additionalProperties":true,"properties":{"label":{"example":"Job Details","type":"string"},"url":{"description":"A download link that carries its own long-lived access token: don't publish it.","example":"https://example.com/pdf/job-details.pdf","format":"uri","type":"string"}},"type":"object"},"type":"array"},"pending_approval":{"description":"The open approval request, if any."},"pipelines":{"description":"The job's tasks.","items":{"additionalProperties":true,"description":"A task.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"type":"array"},"position":{"example":1,"type":["integer","null"]},"pricing_original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price before pricing rules, at the stored scale. 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_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null. These answers usually carry only `type`, the two ids and the two totals. List the jobs of a sales order or quote and Get one job of a sales order or quote answer with the full summary (the rule's current name and position, the prices before and after).","oneOf":[{"additionalProperties":true,"properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","type":["string","null"]},"after_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price after the rule. 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."},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","type":["string","null"]},"base_type":{"description":"Full summary only: `service_price`.","type":["string","null"]},"normal_price":{"description":"Full summary only: the price with no rule (the same as `base` for a job).","type":["string","null"]},"original_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The decoration price before the rule. 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_id":{"description":"The pricing group.","example":"V4keXwwxMQyXw7","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The pricing rule.","example":"V4keXwwxMQyXw7","type":["string","null"]},"rule":{"description":"Full summary only: the rule as the group holds it now (`id`, `label`, `position`, where 1 is the first rule checked), or null when it no longer exists.","type":["object","null"]},"type":{"description":"`service` on a job.","type":["string","null"]}},"type":"object"},{"type":"null"}]},"pricing_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The job's price, at the stored scale (usually 6 decimal places: `{ \"value\": 600000000, \"dp\": 6 }` is 600.00). 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."},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"properties":{"id":{"description":"The file.","example":"V4keXwwxMQyXw7","type":"string"},"name":{"type":["string","null"]},"url":{"description":"Download link with its own access token.","type":["string","null"]}},"type":"object"},"type":"array"},"qr_code_url":{"description":"A QR code image for the job.","example":"https://example.com/qr/job.png","type":["string","null"]},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"name":{"description":"Order name.","example":"Team shirts","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number as shown, with its `JOB-` prefix. Change a job number takes only the digits.","example":"JOB-2419","type":"string"},"services":{"description":"The services (decorations).","items":{"additionalProperties":true,"properties":{"customer_note":{"description":"Customer notes.","type":["string","null"]},"id":{"description":"The job service.","example":"tCBpDSBjXaPhHN","type":"string"},"location":{"additionalProperties":true,"type":"object"},"note":{"description":"Internal notes.","type":["string","null"]},"option":{"description":"The service option."},"position":{"type":["integer","null"]},"pricing_total":{"description":"A decimal pair, or null."},"service_id":{"description":"The service.","example":"5Sf6XRMN2Vuxvh","type":"string"},"service_name":{"example":"Screen print","type":"string"}},"type":"object"},"type":"array"},"services_still_valid":{"type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The job's current status: its production stage. Look it up in List job statuses, or read `status`.","example":"scaWHQnPLtqMPT","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"total_qty_need_ordering":{"description":"Quantity that still needs ordering, with 8 decimal places (`\"12.00000000\"`). A decimal string, such as `\"0.00000000\"`; parse it as a decimal.","example":"0.00000000","type":["string","null"]},"unique_key":{"description":"The job's unique key.","example":"job_EXAMPLEuniqueKey","type":["string","null"]},"version":{"example":2,"type":"integer"}},"type":"object"},"previous_schedule":{"description":"The job and task dates as they were before this request. Send it unchanged to restore_schedule to undo an unschedule.","properties":{"due_date":{"example":"2025-04-19T03:59:59+00:00","format":"date-time","type":["string","null"]},"job_id":{"example":"1WtTf0Po039HZW","type":"string"},"start_date":{"example":"2025-04-17T04:00:00+00:00","format":"date-time","type":["string","null"]},"tasks":{"items":{"properties":{"due_date":{"example":"2025-04-18T03:59:59+00:00","format":"date-time","type":["string","null"]},"id":{"example":"leNSwopOfNWQmv","type":"string"},"start_date":{"example":"2025-04-17T04:00:00+00:00","format":"date-time","type":["string","null"]}},"required":["id","start_date","due_date"],"type":"object"},"type":"array"}},"required":["job_id","start_date","due_date","tasks"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data","previous_schedule"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Schedule a job","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Send both keys, as ISO 8601 date-times or null.","status":422,"when":"Only one of the two keys is sent, or a date isn't ISO 8601 (`validation_failed`, details in `error.fields`)."},{"fix":"Send both dates in order, or both null.","status":422,"when":"One date is null and the other set, or the start is after the due date (`job_validation_error`)."},{"fix":"Check the job id.","status":404,"when":"The job isn't your team's, or its order is an old (version 1) order. Jobs on quotes work too."}],"group":"Production","permission":"Any member of the team; this route checks no sales order permission.","related":["v2_public_job_show","v2_public_job_work_pipeline_update","v1_public_job_calendar"],"rules":["Send both dates, or both as null. One null and the other set is a 422 `job_validation_error`: \"Invalid date range. Both start/due dates should either be set or null.\" Sending only one of the two keys is a 422 `validation_failed`.","`start_date` after `due_date` is a 422 `job_validation_error`: \"Invalid date range. Due Date should be greater than Start Date.\"","Leaving both keys out is the same as sending both null: it unschedules the job and clears every task's dates."],"side_effects":["Moves the job's dated tasks when they no longer fit the new dates (see above), or clears every task's dates when you unschedule.","Open Admin Portal calendars and boards refresh."]}}},"/v2/api/store/{team_slug}/v2/job/{hash_id}/work_pipeline":{"get":{"description":"**Check `success`, not only the HTTP status:** when the job's order is neither a draft nor published, this call answers **HTTP 200** with `{ \"status\": 500, \"success\": false, \"error\": { \"code\": \"action_not_allowed\", \"message\": null } }` instead of the list.\n\nReturns every task of one job, with its preset, status, dates and assignees. Not paged.","operationId":"v2_public_job_work_pipeline_index_for_job","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"WaGvtaWsx7Kcn4","in":"path","name":"hash_id","required":true,"schema":{"example":"WaGvtaWsx7Kcn4","type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"accepted":{"summary":"Done","value":{"data":[{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-05T17:00:00+00:00","id":"hpioY1gDBQZdbI","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"hTFITko5Q0R83y","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T15:05:00+00:00"}],"status":200,"success":true}},"refused":{"summary":"Refused with HTTP 200: `success` is false","value":{"error":{"code":"action_not_allowed","message":null},"status":500,"success":false}}},"schema":{"oneOf":[{"properties":{"data":{"items":{"additionalProperties":true,"description":"A task.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"const":true,"example":true,"type":"boolean"}},"required":["success","status","data"],"title":"Success","type":"object"},{"$ref":"#/components/schemas/ErrorResponse"}]}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the tasks of a job","tags":["Tasks"],"x-yoprint-docs":{"errors":[{"fix":"Check the job id.","status":404,"when":"The job isn't on one of your team's orders, or its order was deleted."},{"fix":"Check `success` in every reply. Publish the order (or work on a draft) first.","status":200,"when":"The order is in a state this call refuses: `success: false`, `error.code` `action_not_allowed`."}],"group":"Production","notes":["A refusal here is HTTP 200 with `success: false` and `error.code` `action_not_allowed` (the body's `status` says 500). A client that only checks the HTTP status will treat it as done."],"permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_job_work_pipeline_store","v2_public_job_work_pipeline_show","v1_public_work_pipeline_filter"],"rules":["The job's order must be a draft or published; otherwise the reply is HTTP 200 with `success: false` and `error.code` `action_not_allowed`."]}},"post":{"description":"**Check `success`, not only the HTTP status:** when the job's order is neither a draft nor published, this call answers **HTTP 200** with `{ \"status\": 500, \"success\": false, \"error\": { \"code\": \"action_not_allowed\", \"message\": null } }` and creates nothing.\n\nAdds one task to a job and returns it.\n\nA task comes from a task preset (Settings > Task Presets), which sets its statuses. Without `status_id` the task starts in the preset's first Pending status; without `name` it takes the preset's name.\n\nSend `start_date` and `due_date` together (both may be null). A start after the due date is a 422 (\"Invalid date range. Due Date should be greater than Start Date.\"). Changing a task's dates resets the job's dates to span its dated tasks: the earliest task start and the latest task due date (none when no task has dates).","operationId":"v2_public_job_work_pipeline_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The job's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"WaGvtaWsx7Kcn4","in":"path","name":"hash_id","required":true,"schema":{"example":"WaGvtaWsx7Kcn4","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"assigned_users":["4mdDkMg3dgQOa3"],"due_date":"2026-11-05T17:00:00Z","name":"Burn screens","pipeline_id":"SE3SfXjt6dPfnH","start_date":"2026-11-04T09:00:00Z"},"schema":{"properties":{"assigned_users":{"description":"User hash ids to assign. Send an array.","example":["4mdDkMg3dgQOa3"],"items":{"type":"string"},"type":"array"},"color":{"description":"A hex color. Validated but not saved.","type":"string"},"due_date":{"description":"ISO 8601. Send with `start_date`.","example":"2026-11-05T17:00:00Z","format":"date-time","type":["string","null"]},"name":{"description":"The task name. Defaults to the preset name.","example":"Burn screens","type":"string"},"note":{"example":"Use 230 mesh.","type":"string"},"pipeline_id":{"description":"The task preset (from List task presets). It sets the statuses and the default name. Required in practice: the server doesn't demand it, but without it (and without `name`) the call fails with 500, and with only `name` it creates a task that has no preset or status.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among the job's tasks.","maximum":2147483647,"minimum":-2147483648,"type":"integer"},"start_date":{"description":"ISO 8601. Send with `due_date`.","example":"2026-11-04T09:00:00Z","format":"date-time","type":["string","null"]},"status_id":{"description":"A status of that preset. Defaults to the preset's first Pending status.","example":"hTFITko5Q0R83y","type":"string"}},"required":["pipeline_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"accepted":{"summary":"Done","value":{"data":{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-05T17:00:00+00:00","id":"hpioY1gDBQZdbI","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#9e9e9e","customer_label":"Pending","id":"P32Ic61q2HqUCD","label":"To do","pipeline_id":"SE3SfXjt6dPfnH","position":1,"role":"pipeline","trashed":false,"type":"start"},"status_completion_date":null,"status_id":"P32Ic61q2HqUCD","status_last_change_date":"2026-11-03T15:00:00+00:00","updated_at":"2026-11-03T15:00:00+00:00"},"status":200,"success":true}},"refused":{"summary":"Refused with HTTP 200: `success` is false","value":{"error":{"code":"action_not_allowed","message":null},"status":500,"success":false}}},"schema":{"oneOf":[{"properties":{"data":{"additionalProperties":true,"description":"A task.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"const":true,"example":true,"type":"boolean"}},"required":["success","status","data"],"title":"Success","type":"object"},{"$ref":"#/components/schemas/ErrorResponse"}]}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add a task to a job","tags":["Tasks"],"x-yoprint-docs":{"errors":[{"fix":"Send both dates, or neither.","status":422,"when":"`start_date` or `due_date` sent without the other, or a field of the wrong type (`validation_failed`, details in `error.fields`)."},{"fix":"Send the dates in order and a status of the chosen preset.","status":422,"when":"A start after the due date, an unknown preset, or a status from another preset (`job_validation_error`)."},{"fix":"Check the ids.","status":404,"when":"The job, or an assigned user, isn't your team's."},{"fix":"Always send `pipeline_id`.","status":500,"when":"Neither `pipeline_id` nor `name` is sent."},{"fix":"Check `success` in every reply. Publish the order (or work on a draft) first.","status":200,"when":"The order is in a state this call refuses: `success: false`, `error.code` `action_not_allowed`."}],"group":"Production","notes":["A refusal here is HTTP 200 with `success: false` and `error.code` `action_not_allowed` (the body's `status` says 500). A client that only checks the HTTP status will treat it as done."],"permission":"Any member of the team. No sales order permission is checked.","related":["v1_public_pipeline_index","v1_public_status_list_pipeline","v1_public_user_index","v2_public_job_work_pipeline_update"],"rules":["The job's order must be a draft or published; otherwise the reply is HTTP 200 with `success: false` and `error.code` `action_not_allowed` and nothing is created.","A task's status must be a status of its task preset. An unknown preset is a 422 \"Pipeline not found!\"; a status from another preset a 422 \"Pipeline Status not found!\".","Assigned users must be members of your team (404 otherwise)."],"side_effects":["May change the job's start and due dates (see the description).","Open Admin Portal pages refresh. No one is notified of the assignment by email."]}}},"/v2/api/store/{team_slug}/v2/payment_link/{hash_id}":{"delete":{"description":"Deletes a payment link and all its allocations. The payments stay recorded on the sales order, unallocated, and the invoices show that much less paid. No money moves.","operationId":"v2_public_payment_link_delete","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment link's hash id. Hash ids only: a unique key or a document number gives 404.","example":"IirNDCwiaCVSKx","in":"path","name":"hash_id","required":true,"schema":{"example":"IirNDCwiaCVSKx","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a payment link","tags":["Payment links"],"x-yoprint-docs":{"errors":[{"fix":"Check the id.","status":404,"when":"The link isn't your team's."}],"group":"Invoices and payments","notes":["Unlike the other payment link calls, delete also works on an order that was deleted in Shopify."],"permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_sales_order_payment_link_index","v2_public_sales_order_payment_link_create"],"side_effects":["Invoices show less paid. The order's customer's balance totals update in the background, and Customer Portal pages the customer has open refresh."]}},"get":{"description":"A payment link records how payments already received on a sales order are split across its invoices (the web app calls this a payment allocation). It is not a URL or payment page your customer opens to pay, and it moves no money.\n\nReturns the link with `total` (the sum of its allocations) and `allocated_transactions`: one row per allocation, with the `invoice_id`, the payment (`transaction_id`), the allocated `total`, the payment's `unallocated_amount` and `state` `existing`.","operationId":"v2_public_payment_link_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment link's hash id. Hash ids only: a unique key or a document number gives 404.","example":"IirNDCwiaCVSKx","in":"path","name":"hash_id","required":true,"schema":{"example":"IirNDCwiaCVSKx","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"allocated_transactions":[{"id":"SAo2jTR8BZUnyc","invoice_id":"gtnwEWU4Npp9eC","state":"existing","total":{"dp":3,"value":12500},"transaction_id":"tUq7cR8dTLKFPm","unallocated_amount":{"dp":3,"value":2500}},{"id":"8Ejv1L5Duc4hRZ","invoice_id":"7ELS3Vmu6QfJxT","state":"existing","total":{"dp":3,"value":5000},"transaction_id":"tUq7cR8dTLKFPm","unallocated_amount":{"dp":3,"value":2500}}],"created_at":"2026-11-03T15:00:00+00:00","id":"IirNDCwiaCVSKx","note":"Deposit split across two invoices","order_id":"ERwEdCKYNeQIHW","total":{"dp":4,"value":175000},"updated_at":"2026-11-03T15:05:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"allocated_transactions":{"description":"One row per allocation.","items":{"additionalProperties":true,"properties":{"id":{"description":"The allocation. Send it in `allocated_transactions[].id` to update or delete it.","example":"SAo2jTR8BZUnyc","type":"string"},"invoice_id":{"description":"The invoice it pays.","example":"gtnwEWU4Npp9eC","type":"string"},"state":{"const":"existing","example":"existing","type":"string"},"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The allocated amount (usually 3 decimal places; a finer stored amount comes back with a larger `dp`). 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."},"transaction_id":{"description":"The payment.","example":"tUq7cR8dTLKFPm","type":"string"},"unallocated_amount":{"$ref":"#/components/schemas/BigDecimalValue","description":"What the payment still has to allocate (usually 3 decimal places; a finer stored amount comes back with a larger `dp`). 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."}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"id":{"description":"The payment link.","example":"IirNDCwiaCVSKx","type":"string"},"note":{"example":"Deposit split across two invoices","type":["string","null"]},"order_id":{"description":"The sales order.","example":"ERwEdCKYNeQIHW","type":"string"},"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The sum of its allocations. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 175000, \"dp\": 4 }` is 17.50). Kept at 4 decimal places; `{ \"value\": 0, \"dp\": 0 }` when the link has no allocations. Read `dp` every time."},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"required":["id","order_id","created_at","updated_at","total","allocated_transactions"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Show one payment link with allocations","tags":["Payment links"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from List the payment links of a sales order.","status":404,"when":"The link isn't your team's."},{"fix":"Only local cleanup is allowed on that order.","status":422,"when":"The order came from Shopify and was deleted there (`shopify_order_deleted_externally`)."}],"group":"Invoices and payments","permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_sales_order_payment_link_index","v2_public_payment_link_get_update_template","v2_public_payment_link_update"]}},"put":{"description":"A payment link records how payments already received on a sales order are split across its invoices (the web app calls this a payment allocation). It is not a URL or payment page your customer opens to pay, and it moves no money.\n\nChanges the note and the allocations in one call: `delete` and `update` act on existing allocations (by allocation `id`), `create` adds new ones (a payment and an invoice of the same order). Allocations you leave out stay as they are. Returns the link as Show one payment link does.\n\nAmounts in allocations must use exactly 3 decimal places (`dp: 3`):\n- Correct: `{ \"value\": 12500, \"dp\": 3 }` for 12.50.\n- Wrong: `{ \"value\": 1250, \"dp\": 2 }` — the server always interprets `value` as thousandths (scale 3), which would mean 1.250, and validation requires `dp: 3`.\n\nIn answers, the link's own `total` uses 4 decimal places (`{ \"value\": 175000, \"dp\": 4 }` is 17.50): always read each pair's `dp`.\n\nAmounts are capped, not refused: an allocation never exceeds what the invoice still owes or what the payment has left. A `create` row asking for more than the payment has left, or for an invoice with nothing left to pay, is skipped without an error. Read the response to see what was saved.","operationId":"v2_public_payment_link_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment link's hash id. Hash ids only: a unique key or a document number gives 404.","example":"IirNDCwiaCVSKx","in":"path","name":"hash_id","required":true,"schema":{"example":"IirNDCwiaCVSKx","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"allocated_transactions":[{"action":"update","id":"SAo2jTR8BZUnyc","total":{"dp":3,"value":12500}}],"note":"Deposit split across two invoices","unallocated_transactions":[{"action":"create","invoice_id":"7ELS3Vmu6QfJxT","total":{"dp":3,"value":5000},"transaction_id":"tUq7cR8dTLKFPm"}]},"schema":{"properties":{"allocated_transactions":{"description":"Changes to existing allocations.","items":{"properties":{"action":{"enum":["update","delete"],"type":"string"},"id":{"description":"The allocation id from `allocated_transactions[].id`.","example":"SAo2jTR8BZUnyc","type":"string"},"total":{"description":"Required for `update`: the new allocated amount with `dp: 3` (for example `{ \"value\": 12500, \"dp\": 3 }` for 12.50). `value` is always read as thousandths.","properties":{"dp":{"const":3,"example":3,"type":"integer"},"value":{"example":12500,"minimum":0,"type":"integer"}},"required":["value","dp"],"type":"object"}},"required":["action","id"],"type":"object"},"type":"array"},"note":{"description":"A note on the link.","type":"string"},"unallocated_transactions":{"description":"New allocations.","items":{"properties":{"action":{"const":"create","type":"string"},"invoice_id":{"description":"An invoice of the same sales order.","example":"7ELS3Vmu6QfJxT","type":"string"},"total":{"description":"The amount to allocate. Send it: the server doesn't require it, and a row without it adds a 0.000 allocation. `value` is always read as thousandths whatever `dp` says (for example send `{ \"value\": 12500, \"dp\": 3 }` for 12.50).","properties":{"dp":{"const":3,"example":3,"type":"integer"},"value":{"example":5000,"minimum":0,"type":"integer"}},"type":"object"},"transaction_id":{"description":"A payment on the same sales order.","example":"tUq7cR8dTLKFPm","type":"string"}},"required":["action","transaction_id","invoice_id","total"],"type":"object"},"type":"array"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"allocated_transactions":[{"id":"SAo2jTR8BZUnyc","invoice_id":"gtnwEWU4Npp9eC","state":"existing","total":{"dp":3,"value":12500},"transaction_id":"tUq7cR8dTLKFPm","unallocated_amount":{"dp":3,"value":2500}},{"id":"8Ejv1L5Duc4hRZ","invoice_id":"7ELS3Vmu6QfJxT","state":"existing","total":{"dp":3,"value":5000},"transaction_id":"tUq7cR8dTLKFPm","unallocated_amount":{"dp":3,"value":2500}}],"created_at":"2026-11-03T15:00:00+00:00","id":"IirNDCwiaCVSKx","note":"Deposit split across two invoices","order_id":"ERwEdCKYNeQIHW","total":{"dp":4,"value":175000},"updated_at":"2026-11-03T15:05:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"allocated_transactions":{"description":"One row per allocation.","items":{"additionalProperties":true,"properties":{"id":{"description":"The allocation. Send it in `allocated_transactions[].id` to update or delete it.","example":"SAo2jTR8BZUnyc","type":"string"},"invoice_id":{"description":"The invoice it pays.","example":"gtnwEWU4Npp9eC","type":"string"},"state":{"const":"existing","example":"existing","type":"string"},"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The allocated amount (usually 3 decimal places; a finer stored amount comes back with a larger `dp`). 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."},"transaction_id":{"description":"The payment.","example":"tUq7cR8dTLKFPm","type":"string"},"unallocated_amount":{"$ref":"#/components/schemas/BigDecimalValue","description":"What the payment still has to allocate (usually 3 decimal places; a finer stored amount comes back with a larger `dp`). 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."}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"id":{"description":"The payment link.","example":"IirNDCwiaCVSKx","type":"string"},"note":{"example":"Deposit split across two invoices","type":["string","null"]},"order_id":{"description":"The sales order.","example":"ERwEdCKYNeQIHW","type":"string"},"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The sum of its allocations. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 175000, \"dp\": 4 }` is 17.50). Kept at 4 decimal places; `{ \"value\": 0, \"dp\": 0 }` when the link has no allocations. Read `dp` every time."},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"required":["id","order_id","created_at","updated_at","total","allocated_transactions"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a payment link","tags":["Payment links"],"x-yoprint-docs":{"errors":[{"fix":"Start from Get the starting point for editing a payment link and keep its shapes.","status":422,"when":"A row lacks `action`, an `id`, `invoice_id` or `transaction_id`, or an update `total` isn't 3 decimal places."},{"fix":"Only local cleanup is allowed on that order.","status":422,"when":"The order came from Shopify and was deleted there (`shopify_order_deleted_externally`)."},{"fix":"Check the id.","status":404,"when":"The link isn't your team's."}],"group":"Invoices and payments","permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_payment_link_get_update_template","v2_public_payment_link_show","v2_public_sales_order_payment_link_create"],"rules":["Payments and invoices must belong to the link's sales order; others are skipped.","For `update`, `total.dp` must be 3 and `total.value` 0 or more (422 otherwise).","Deletes run first, then updates, then creates, so you can move money from one invoice to another in one call."],"side_effects":["Changes how much each invoice shows as paid.","Updates the order's customer's balance totals in the background.","No money moves and nothing is sent to the customer. Open Admin Portal pages refresh, and so do Customer Portal pages the customer has open."]}}},"/v2/api/store/{team_slug}/v2/payment_link/{hash_id}/get_update_template":{"get":{"description":"Returns what you need to build an Update a payment link body: the link with its `allocated_transactions` (`state` `existing`, each with its allocation `id`), plus `unallocated_transactions`: every payment on the order that still has money to allocate (`state` `new`, `transaction_id`, `unallocated_amount`, `invoice_id` null and a zero `total`).\n\nTo edit: change `total` on existing rows and mark them `update` or `delete`; fill `invoice_id` and `total` on new rows and mark them `create`. Amounts in allocations must use exactly 3 decimal places (`dp: 3`):\n- Correct: `{ \"value\": 12500, \"dp\": 3 }` for 12.50.\n- Wrong: `{ \"value\": 1250, \"dp\": 2 }` — the server always interprets `value` as thousandths (scale 3), which would mean 1.250, and validation requires `dp: 3`.\n\nIn answers, the link's own `total` uses 4 decimal places (`{ \"value\": 175000, \"dp\": 4 }` is 17.50): always read each pair's `dp`.","operationId":"v2_public_payment_link_get_update_template","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The payment link's hash id. Hash ids only: a unique key or a document number gives 404.","example":"IirNDCwiaCVSKx","in":"path","name":"hash_id","required":true,"schema":{"example":"IirNDCwiaCVSKx","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"allocated_transactions":[{"id":"SAo2jTR8BZUnyc","invoice_id":"gtnwEWU4Npp9eC","state":"existing","total":{"dp":3,"value":15000},"transaction_id":"tUq7cR8dTLKFPm","unallocated_amount":{"dp":3,"value":5000}}],"created_at":"2026-11-03T15:00:00+00:00","id":"IirNDCwiaCVSKx","note":"Deposit split across two invoices","order_id":"ERwEdCKYNeQIHW","total":{"dp":4,"value":150000},"unallocated_transactions":[{"invoice_id":null,"state":"new","total":{"dp":3,"value":0},"transaction_id":"tUq7cR8dTLKFPm","unallocated_amount":{"dp":3,"value":5000}}],"updated_at":"2026-11-03T15:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"allocated_transactions":{"description":"One row per allocation.","items":{"additionalProperties":true,"properties":{"id":{"description":"The allocation. Send it in `allocated_transactions[].id` to update or delete it.","example":"SAo2jTR8BZUnyc","type":"string"},"invoice_id":{"description":"The invoice it pays.","example":"gtnwEWU4Npp9eC","type":"string"},"state":{"const":"existing","example":"existing","type":"string"},"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The allocated amount (usually 3 decimal places; a finer stored amount comes back with a larger `dp`). 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."},"transaction_id":{"description":"The payment.","example":"tUq7cR8dTLKFPm","type":"string"},"unallocated_amount":{"$ref":"#/components/schemas/BigDecimalValue","description":"What the payment still has to allocate (usually 3 decimal places; a finer stored amount comes back with a larger `dp`). 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."}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"id":{"description":"The payment link.","example":"IirNDCwiaCVSKx","type":"string"},"note":{"example":"Deposit split across two invoices","type":["string","null"]},"order_id":{"description":"The sales order.","example":"ERwEdCKYNeQIHW","type":"string"},"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The sum of its allocations. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 175000, \"dp\": 4 }` is 17.50). Kept at 4 decimal places; `{ \"value\": 0, \"dp\": 0 }` when the link has no allocations. Read `dp` every time."},"unallocated_transactions":{"description":"Payments on the order that still have money to allocate.","items":{"additionalProperties":true,"properties":{"invoice_id":{"description":"Fill in the invoice to allocate to.","type":"null"},"state":{"const":"new","example":"new","type":"string"},"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"Starts at `{ \"value\": 0, \"dp\": 3 }`: fill in the amount. 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."},"transaction_id":{"description":"A payment with money left to allocate.","example":"tUq7cR8dTLKFPm","type":"string"},"unallocated_amount":{"$ref":"#/components/schemas/BigDecimalValue","description":"What it has left (usually 3 decimal places; a finer stored amount comes back with a larger `dp`). 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."}},"type":"object"},"type":"array"},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"required":["id","order_id","created_at","updated_at","total","allocated_transactions"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get the starting point for editing a payment link","tags":["Payment links"],"x-yoprint-docs":{"errors":[{"fix":"Check the id.","status":404,"when":"The link isn't your team's."},{"fix":"Only local cleanup is allowed on that order.","status":422,"when":"The order came from Shopify and was deleted there (`shopify_order_deleted_externally`)."}],"group":"Invoices and payments","permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_payment_link_update","v2_public_payment_link_show"]}}},"/v2/api/store/{team_slug}/v2/quote/filter":{"post":{"description":"Lists quotes, a page at a time, with filters and sorting. It is a read, despite the POST. Sales orders are not included.\n\nSend `filters` and `sort` in the body, both optional. Rows are in `data`, in the Get a sales order shape without line items; each row carries `customer` (the customer record, or null), so you don't need a lookup per row. `pagination` has the total. A page holds the team's page size (50 unless the team changed it); ask for the next page with `?page=2`.\n\nFilter keys, with their operators and values:\n\n| Key | Operators | Value |\n| --- | --- | --- |\n| `issue_date`, `due_date` (production due), `cust_due_date` (in-hands date), `ship_due_date`, `deposit_due`, `full_amount_due`, `status_last_change_date`, `status_completion_date`, `quickbook_last_success_sync`, `quickbook_last_error_sync` | `eq`, `gte`, `lte` | whole days from today in UTC: 0 is today, -7 a week ago, 7 a week ahead. `gte N` starts at 00:00 UTC of day N. `lte N` stops at 00:00 UTC of day N, so day N is left out. `eq N` matches almost nothing. See the rules below |\n| `status_id`, `customer_id`, `created_by`, `assigned_users`, `tag` | `in`, `nin` | a list of ids |\n| `status_type` | `in`, `nin` | a list of `start` (Pending), `in_progress`, `end` (Completed) |\n| `approval_status` | `in`, `nin` | a list of `requested`, `sent-to-customer`, `viewed-by-customer`, `need-changes`, `approved` |\n| `external_type` | `in`, `nin` | a list of `shopify`, `native` |\n| `payment_status`, `deposit_status` | `eq` | `paid` or `unpaid` |\n| `is_rush`, `draft`, `quote`, `trashed_only`, `created_by_me`, `assigned_to_me`, `my_customer`, `has_order_approval`, `has_job_approval`, `has_not_invoiced_items`, `has_over_invoiced_items`, `shopify_deleted_externally` | `eq`, `neq` | `true` or `false` (JSON booleans) |\n| `total_qty_need_ordering` | `eq`, `gte`, `lte` | a number |\n\nSort keys: `id`, `issue_date`, `due_date`, `start_date`, `deposit_due`, `cust_due_date`, `ship_due_date`, `full_amount_due`, `status_last_change_date`, `status_completion_date`, `calc_total`, `status_id`, `status_position`, `quote`, `is_rush`, `quickbooks_sync_status`, `name`, `customer_name`, `created_at`, `total_qty_need_ordering`; each with `direction` `asc` or `desc`.\n\nUse this instead of the retired v1 quote filter.","operationId":"v2_public_quote_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The page to return, from 1.","in":"query","name":"page","required":false,"schema":{"minimum":1,"type":"integer"}}],"requestBody":{"content":{"application/json":{"example":{"filters":[{"key":"issue_date","operator":"gte","value":-30}],"sort":[{"direction":"desc","key":"issue_date"}]},"schema":{"properties":{"count_only":{"description":"true to get only `pagination` (the total), with no rows.","type":"boolean"},"filters":{"description":"Conditions, combined with AND. Leave it out to list everything.","items":{"properties":{"key":{"description":"A filter key from the table.","type":"string"},"operator":{"enum":["eq","neq","gte","lte","in","nin"],"type":"string"},"value":{"description":"A number of days, a list of ids or options, a string option, a boolean, or a number, depending on the key."}},"required":["key","operator","value"],"type":"object"},"type":"array"},"sort":{"description":"Sort order, first entry first.","items":{"properties":{"direction":{"enum":["asc","desc"],"type":"string"},"key":{"type":"string"}},"required":["key","direction"],"type":"object"},"type":"array"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"assigned_users":[],"calc_deposit_total":0,"customer":{"id":"63KcENAAsKuipY","is_external":false,"name":"Northwind Apparel","tax_exempt":false},"customer_id":"63KcENAAsKuipY","customer_po_number":null,"deposit_amount_due":{"dp":4,"value":0},"deposit_required":false,"deposit_total":0,"due_date":"2026-11-14T00:00:00+00:00","id":"3wxqE48CXfVh5b","internal_status":"published","invoiced_discount_subtotal":{"dp":0,"value":0},"invoiced_order_item_subtotal":{"dp":0,"value":0},"invoiced_shipment_subtotal":{"dp":0,"value":0},"invoiced_tax_subtotal":{"dp":0,"value":0},"invoiced_total":{"dp":0,"value":0},"is_rush":false,"issue_date":"2026-11-03T00:00:00+00:00","mode":"view","name":"Fall jackets","object_type":"quote","order_balance_due":{"dp":4,"value":0},"order_item_cart_total":{"dp":4,"value":1250000},"paid_amount":0,"quote":true,"scoped_id":"SO1002","status":{"color":"#2196f3","customer_label":"In Progress","id":"rSURI1Tq50X9Er","label":"Sent","position":2,"role":"quote","trashed":false,"type":"in_progress"},"status_id":"rSURI1Tq50X9Er","total_qty_need_ordering":"0.00000000","trashed":false,"type":"quote","unique_key":"ord_EXAMPLEquoteKey"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A sales order or quote.","properties":{"approval_status":{"description":"`requested`, `sent-to-customer`, `viewed-by-customer`, `need-changes` or `approved`; null without approvals.","type":["string","null"]},"assigned_users":{"description":"The team members in the order's Assigned To list (always included).","items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"auto_invoice_managed":{"description":"true when YoPrint keeps one invoice in step with the order.","type":"boolean"},"auto_invoice_shipment_price_type":{"description":"`DONOTMANAGE`, `NONE`, `MARKUP` or `MARGIN`.","type":["string","null"]},"auto_invoice_shipment_rate":{"description":"The MARKUP or MARGIN percentage. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"auto_invoice_type":{"description":"How the automatic invoice is built. Always `single_invoice` today.","type":["string","null"]},"billing_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"billing_address_id":{"type":["string","null"]},"calc_deposit_total":{"description":"The deposit amount, rounded to 2 decimal places: the percentage of `order_item_cart_total`, or of the invoiced total once every line is invoiced (or the invoiced total reaches the order's); 0 unless `deposit_required`. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `invoiced_discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `invoiced_order_item_subtotal`, which already includes billed shipping. This older field adds `invoiced_shipment_subtotal` to it once more. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `invoiced_tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `invoiced_total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"client_note":{"description":"The Client Note.","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_by":{"description":"Created By (a team member id).","type":["string","null"]},"creator_name":{"type":["string","null"]},"cust_due_date":{"description":"Customer in-hands date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"Always present on order answers, lists included: the customer record, or null when the order has none. Get a sales order also nests the customer's contacts, addresses, brand profiles, tags, files and assigned users in it.","properties":{"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"id":{"example":"63KcENAAsKuipY","type":"string"},"is_external":{"description":"true for a customer synced from an integration.","type":"boolean"},"name":{"example":"Northwind Apparel","type":"string"},"tax_exempt":{"type":"boolean"}},"type":["object","null"]},"customer_billing_contact_id":{"description":"The id of the contact on the order (the same contact as `customer_contact_id`), or null.","type":["string","null"]},"customer_contact_id":{"type":["string","null"]},"customer_has_email":{"type":"boolean"},"customer_id":{"example":"63KcENAAsKuipY","type":["string","null"]},"customer_po_number":{"example":"PO-1188","type":["string","null"]},"customer_profile_id":{"description":"Brand profile.","type":["string","null"]},"deposit_amount_due":{"description":"Deposit still to pay (negative once overpaid). A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"deposit_due":{"description":"Deposit due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"deposit_required":{"type":"boolean"},"deposit_total":{"description":"The deposit as a **percentage** of the order. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","type":["integer","number","string","null"]},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"external_ids":{"description":"The order's links to records in other systems. An empty list when there are none.","items":{"additionalProperties":true,"description":"One link to a record in another system (Shopify, QuickBooks and so on): `id`, `external_integration_id`, `external_id`, `data`, `created_at`, `updated_at` and the nested `external_integration`.","type":"object"},"type":"array"},"external_type":{"description":"`shopify` for a Shopify order; null for YoPrint orders.","type":["string","null"]},"from_legacy":{"description":"true for an order that was moved over from the old format.","type":"boolean"},"full_amount_due":{"description":"Full payment due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"grouped_pdf":{"description":"PDF links, grouped: `Main` (only for roles with `view_order_finance`), `Job` (not on Shopify orders), `Shipment` and the team's templates.","items":{"additionalProperties":true,"properties":{"documents":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"label":{"example":"Main","type":"string"}},"type":"object"},"type":"array"},"has_external_integration_sync_error":{"description":"true when the last sync with an integration failed.","type":"boolean"},"has_invoice":{"description":"true when the order has at least one invoice, so a zero invoiced total can be told apart from no invoice.","type":"boolean"},"has_not_invoiced_items":{"description":"true when some line items are not on an invoice yet.","type":"boolean"},"has_over_invoiced_items":{"description":"true when some line items are invoiced for more than the order has.","type":"boolean"},"has_shipment_items_not_allocated":{"description":"true when some line items are not on a shipment yet.","type":"boolean"},"has_shipment_items_over_allocated":{"description":"true when some line items are on shipments for more than the order has.","type":"boolean"},"has_valid_invoice":{"description":"true when at least one of the order's invoices is in a valid state.","type":"boolean"},"has_valid_shipment":{"description":"true when at least one of the order's shipments is in a valid state.","type":"boolean"},"id":{"description":"The order's hash id: use it in every other call.","example":"V4keXwwxMQyXw7","type":"string"},"internal_status":{"description":"`draft` until published.","enum":["draft","published"],"type":"string"},"inventory_status":{"description":"Stock status of the order's lines: `not_committed`, `committed`, `partially_committed`, `not_applicable` or `pending`.","type":["string","null"]},"invoice_lock_version":{"description":"Changes whenever the order's invoices change.","type":["integer","string","null"]},"invoiced_discount_subtotal":{"description":"Discounts on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_order_item_subtotal":{"description":"The lines and shipping fees the order's invoices bill (the sum of their `cart_item_subtotal`); 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_shipment_subtotal":{"description":"The shipping fees in `invoiced_order_item_subtotal`; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_tax_subtotal":{"description":"Tax on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_total":{"description":"Total of the order's invoices. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"is_client_note_editable":{"description":"false for a Shopify order, whose client note comes from Shopify.","type":"boolean"},"is_external":{"description":"true for an order synced from an integration such as Shopify.","type":"boolean"},"is_legacy":{"description":"true for an order made in the old format.","type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"job_lock_version":{"description":"Changes whenever the order's jobs change.","type":["integer","string","null"]},"last_payment_request_date":{"description":"When a payment reminder was last emailed for the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"lock_version":{"description":"Changes on every save.","type":["integer","string","null"]},"mode":{"description":"Older flag: `create` for a draft, `view` once published.","enum":["create","view","edit"],"type":"string"},"name":{"example":"Spring team shirts","type":["string","null"]},"object_type":{"enum":["sales_order","quote"],"type":"string"},"order_balance_due":{"description":"Invoiced total minus paid. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_cart_total":{"description":"The value of the order's lines: the order's own total before invoicing. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_lock_version":{"description":"Changes whenever the order's line items change.","type":["integer","string","null"]},"order_margin_percentage":{"description":"Margin, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_markup_percentage":{"description":"Markup, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_profit":{"description":"Profit. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"paid_amount":{"description":"Paid so far. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"payment_lock_version":{"description":"Changes whenever the order's payments change.","type":["integer","string","null"]},"payment_term_id":{"type":["string","null"]},"pricing_group_id":{"type":["string","null"]},"pricing_strategy":{"description":"`job_separately`, `job_together` or `service_loc_together`.","type":["string","null"]},"prod_note":{"description":"The production note.","type":["string","null"]},"producible_item_count":{"description":"Quantity to produce.","type":["number","integer","string","null"]},"quickbook_disable_sync":{"description":"true when QuickBooks sync is off for this order.","type":"boolean"},"quickbook_disable_sync_at":{"description":"When the switch was last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_disable_sync_by":{"description":"The team member who last changed the switch, or null.","type":["string","null"]},"quickbook_disable_sync_reason":{"description":"The note given at the last change of the order's QuickBooks sync switch (off or back on), at most 500 characters, or null.","type":["string","null"]},"quickbook_last_error_sync":{"description":"When a QuickBooks sync of the order last failed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_last_success_sync":{"description":"When QuickBooks last accepted the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbooks_hold":{"description":"Set when YoPrint holds back a QuickBooks payment covering this order: `code` is `changed`, `deleted` or `rejected` (the payment was changed or deleted in QuickBooks, or QuickBooks refused a change), and `detail` is `already_deposited` (the payment is in a QuickBooks bank deposit) or null. Null when nothing is held.","properties":{"code":{"enum":["changed","deleted","rejected"],"type":"string"},"detail":{"type":["string","null"]}},"type":["object","null"]},"quote":{"description":"Older flag: true for a quote.","type":"boolean"},"scoped_id":{"description":"The order number people see, `SO` and at least four digits (quotes too). Not an id.","example":"SO1001","type":"string"},"ship_due_date":{"description":"Ship due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shipment_billable_fee_invoice_status":{"description":"Whether those shipping fees are on an invoice. Null when there is nothing to bill.","type":["string","null"]},"shipment_billable_fee_total":{"description":"The shipping fees you bill the customer on the order's shipments. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_cost_total":{"description":"Shipping cost incurred. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_lock_version":{"description":"Changes whenever the order's shipments change.","type":["integer","string","null"]},"shipping_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"shipping_address_id":{"type":["string","null"]},"shopify_last_error_sync":{"description":"When a Shopify sync of the order last failed. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_last_success_sync":{"description":"When Shopify last accepted the order. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_terminal_topic":{"description":"Shopify orders only: the Shopify event name behind the order's final state there. Null on YoPrint orders. The answer can also hold more `shopify_*` fields (`shopify_admin_url`, `shopify_compliance_deletion`, `shopify_finance_notices`, `shopify_has_fulfillment_conflict`, `shopify_last_fulfillment_conflict_at`): they are null or empty on YoPrint orders.","type":["string","null"]},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"The order's status (always included).","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_completion_date":{"description":"When the order's status last moved to an end status. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status_id":{"description":"The order's status (from the team's sales order or quote statuses).","example":"52CuV8sWcDZLPm","type":"string"},"status_last_change_date":{"description":"Last status change. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"tags":{"items":{"additionalProperties":true,"properties":{"color_hex":{"description":"Tag color, for example `#E53935`.","type":["string","null"]},"id":{"example":"7qYPMmbLZR9oFg","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"total_qty_need_ordering":{"description":"Quantity still to buy, as a decimal string with 8 decimal places (`\"24.00000000\"`).","example":"0.00000000","type":"string"},"trashed":{"description":"true when the order is deleted.","type":"boolean"},"type":{"description":"Older name for `object_type`.","enum":["order","quote"],"type":"string"},"unallocated_amount":{"description":"Payments not yet allocated to an invoice. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"unique_key":{"description":"The order's unique key (`ord_…`); accepted wherever `{order_unique_key}` is.","example":"ord_EXAMPLEuniqueKey","type":"string"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"version":{"description":"The order format version.","type":["integer","string","null"]},"wallet_currency_iso":{"description":"The order's currency code (`USD` and so on), or null on older orders without one.","example":"USD","type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"required":["id","unique_key","scoped_id","object_type","internal_status"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List quotes","tags":["Quotes"],"x-yoprint-docs":{"errors":[{"fix":"Check each filter against the table.","status":422,"when":"An unknown key, a wrong operator for the key, or a value of the wrong kind."},{"fix":"Ask the team owner for view permission.","status":403,"when":"The role can't view quotes at all. This error has no envelope: the body is `{\"message\": \"You do not have permission to view this resource\"}`."}],"group":"Sales","notes":["Deleted quotes are hidden unless you filter `trashed_only` `eq` true.","Drafts are included; filter `draft` `eq` false to leave them out.","Day offsets here count forward from today (7 is a week ahead). Some older v1 filters count the other way; check each filter's page before reusing a filter."],"permission":"Needs permission to view quotes: a role that sees every order (`view_all_order`) gets all of them; a role that sees only its own (`view_self_order`) gets only the ones its user created. Without either, 403.","related":["v2_public_sales_order_filter","v2_public_order_show"],"rules":["Every filter needs `key`, `operator` and `value`, and the operator and value must suit the key; otherwise 422 with no detail of which filter failed.","Date filters take a whole number of days from today (UTC), not a calendar date: `0` is today, `7` is 7 days from today, `-7` is 7 days ago. The number becomes a UTC date and is compared with the stored date and time. `gte N` starts at 00:00 UTC of day N. `lte N` stops at 00:00 UTC of day N, so day N itself is left out. `eq N` matches only a record stamped exactly 00:00:00 UTC, so in practice almost nothing. Due dates are stored as the end of the team's local day, so a UTC day does not line up with it.","To cover the days A to B of your team's calendar, ask `gte A-1` and `lte B+2`, then keep the rows whose date falls in those days by checking the dates in your own code. For \"late\", ask `lte 1` and keep the rows whose date is before now.","Booleans must be JSON `true` or `false`.","Ids are the `id` fields of other answers (status, customer, user and tag ids)."]}}},"/v2/api/store/{team_slug}/v2/sales_order/filter":{"post":{"description":"Lists sales orders, a page at a time, with filters and sorting. It is a read, despite the POST. Quotes are not included: list them with List quotes.\n\nSend `filters` and `sort` in the body, both optional. Rows are in `data`, in the Get a sales order shape without line items; each row carries `customer` (the customer record, or null), so you don't need a lookup per row. `pagination` has the total. A page holds the team's page size (50 unless the team changed it); ask for the next page with `?page=2`.\n\nFilter keys, with their operators and values:\n\n| Key | Operators | Value |\n| --- | --- | --- |\n| `issue_date`, `due_date` (production due), `cust_due_date` (in-hands date), `ship_due_date`, `deposit_due`, `full_amount_due`, `status_last_change_date`, `status_completion_date`, `quickbook_last_success_sync`, `quickbook_last_error_sync` | `eq`, `gte`, `lte` | whole days from today in UTC: 0 is today, -7 a week ago, 7 a week ahead. `gte N` starts at 00:00 UTC of day N. `lte N` stops at 00:00 UTC of day N, so day N is left out. `eq N` matches almost nothing. See the rules below |\n| `status_id`, `customer_id`, `created_by`, `assigned_users`, `tag` | `in`, `nin` | a list of ids |\n| `status_type` | `in`, `nin` | a list of `start` (Pending), `in_progress`, `end` (Completed) |\n| `approval_status` | `in`, `nin` | a list of `requested`, `sent-to-customer`, `viewed-by-customer`, `need-changes`, `approved` |\n| `external_type` | `in`, `nin` | a list of `shopify`, `native` |\n| `payment_status`, `deposit_status` | `eq` | `paid` or `unpaid` |\n| `is_rush`, `draft`, `quote`, `trashed_only`, `created_by_me`, `assigned_to_me`, `my_customer`, `has_order_approval`, `has_job_approval`, `has_not_invoiced_items`, `has_over_invoiced_items`, `shopify_deleted_externally` | `eq`, `neq` | `true` or `false` (JSON booleans) |\n| `total_qty_need_ordering` | `eq`, `gte`, `lte` | a number |\n\nSort keys: `id`, `issue_date`, `due_date`, `start_date`, `deposit_due`, `cust_due_date`, `ship_due_date`, `full_amount_due`, `status_last_change_date`, `status_completion_date`, `calc_total`, `status_id`, `status_position`, `quote`, `is_rush`, `quickbooks_sync_status`, `name`, `customer_name`, `created_at`, `total_qty_need_ordering`; each with `direction` `asc` or `desc`.\n\nUse this instead of the retired v1 sales order filter.","operationId":"v2_public_sales_order_filter","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The page to return, from 1.","in":"query","name":"page","required":false,"schema":{"minimum":1,"type":"integer"}}],"requestBody":{"content":{"application/json":{"example":{"filters":[{"key":"status_type","operator":"in","value":["start","in_progress"]},{"key":"due_date","operator":"lte","value":7}],"sort":[{"direction":"asc","key":"due_date"}]},"schema":{"properties":{"count_only":{"description":"true to get only `pagination` (the total), with no rows.","type":"boolean"},"filters":{"description":"Conditions, combined with AND. Leave it out to list everything.","items":{"properties":{"key":{"description":"A filter key from the table.","type":"string"},"operator":{"enum":["eq","neq","gte","lte","in","nin"],"type":"string"},"value":{"description":"A number of days, a list of ids or options, a string option, a boolean, or a number, depending on the key."}},"required":["key","operator","value"],"type":"object"},"type":"array"},"sort":{"description":"Sort order, first entry first.","items":{"properties":{"direction":{"enum":["asc","desc"],"type":"string"},"key":{"type":"string"}},"required":["key","direction"],"type":"object"},"type":"array"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"assigned_users":[],"calc_deposit_total":67500,"customer":{"id":"63KcENAAsKuipY","is_external":false,"name":"Northwind Apparel","tax_exempt":false},"customer_id":"63KcENAAsKuipY","customer_po_number":"PO-1188","deposit_amount_due":{"dp":4,"value":175000},"deposit_required":true,"deposit_total":50000,"due_date":"2026-11-14T00:00:00+00:00","id":"V4keXwwxMQyXw7","internal_status":"published","invoiced_discount_subtotal":{"dp":4,"value":0},"invoiced_order_item_subtotal":{"dp":4,"value":1250000},"invoiced_shipment_subtotal":{"dp":4,"value":0},"invoiced_tax_subtotal":{"dp":4,"value":100000},"invoiced_total":{"dp":4,"value":1350000},"is_rush":false,"issue_date":"2026-11-03T00:00:00+00:00","mode":"view","name":"Spring team shirts","object_type":"sales_order","order_balance_due":{"dp":4,"value":850000},"order_item_cart_total":{"dp":4,"value":1250000},"paid_amount":50000,"quote":false,"scoped_id":"SO1001","status":{"color":"#2196f3","customer_label":"In Progress","id":"52CuV8sWcDZLPm","label":"In production","position":2,"role":"order","trashed":false,"type":"in_progress"},"status_id":"52CuV8sWcDZLPm","total_qty_need_ordering":"0.00000000","trashed":false,"type":"order","unique_key":"ord_EXAMPLEuniqueKey"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A sales order or quote.","properties":{"approval_status":{"description":"`requested`, `sent-to-customer`, `viewed-by-customer`, `need-changes` or `approved`; null without approvals.","type":["string","null"]},"assigned_users":{"description":"The team members in the order's Assigned To list (always included).","items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"auto_invoice_managed":{"description":"true when YoPrint keeps one invoice in step with the order.","type":"boolean"},"auto_invoice_shipment_price_type":{"description":"`DONOTMANAGE`, `NONE`, `MARKUP` or `MARGIN`.","type":["string","null"]},"auto_invoice_shipment_rate":{"description":"The MARKUP or MARGIN percentage. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"auto_invoice_type":{"description":"How the automatic invoice is built. Always `single_invoice` today.","type":["string","null"]},"billing_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"billing_address_id":{"type":["string","null"]},"calc_deposit_total":{"description":"The deposit amount, rounded to 2 decimal places: the percentage of `order_item_cart_total`, or of the invoiced total once every line is invoiced (or the invoiced total reaches the order's); 0 unless `deposit_required`. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `invoiced_discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `invoiced_order_item_subtotal`, which already includes billed shipping. This older field adds `invoiced_shipment_subtotal` to it once more. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `invoiced_tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `invoiced_total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"client_note":{"description":"The Client Note.","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_by":{"description":"Created By (a team member id).","type":["string","null"]},"creator_name":{"type":["string","null"]},"cust_due_date":{"description":"Customer in-hands date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"Always present on order answers, lists included: the customer record, or null when the order has none. Get a sales order also nests the customer's contacts, addresses, brand profiles, tags, files and assigned users in it.","properties":{"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"id":{"example":"63KcENAAsKuipY","type":"string"},"is_external":{"description":"true for a customer synced from an integration.","type":"boolean"},"name":{"example":"Northwind Apparel","type":"string"},"tax_exempt":{"type":"boolean"}},"type":["object","null"]},"customer_billing_contact_id":{"description":"The id of the contact on the order (the same contact as `customer_contact_id`), or null.","type":["string","null"]},"customer_contact_id":{"type":["string","null"]},"customer_has_email":{"type":"boolean"},"customer_id":{"example":"63KcENAAsKuipY","type":["string","null"]},"customer_po_number":{"example":"PO-1188","type":["string","null"]},"customer_profile_id":{"description":"Brand profile.","type":["string","null"]},"deposit_amount_due":{"description":"Deposit still to pay (negative once overpaid). A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"deposit_due":{"description":"Deposit due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"deposit_required":{"type":"boolean"},"deposit_total":{"description":"The deposit as a **percentage** of the order. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","type":["integer","number","string","null"]},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"external_ids":{"description":"The order's links to records in other systems. An empty list when there are none.","items":{"additionalProperties":true,"description":"One link to a record in another system (Shopify, QuickBooks and so on): `id`, `external_integration_id`, `external_id`, `data`, `created_at`, `updated_at` and the nested `external_integration`.","type":"object"},"type":"array"},"external_type":{"description":"`shopify` for a Shopify order; null for YoPrint orders.","type":["string","null"]},"from_legacy":{"description":"true for an order that was moved over from the old format.","type":"boolean"},"full_amount_due":{"description":"Full payment due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"grouped_pdf":{"description":"PDF links, grouped: `Main` (only for roles with `view_order_finance`), `Job` (not on Shopify orders), `Shipment` and the team's templates.","items":{"additionalProperties":true,"properties":{"documents":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"label":{"example":"Main","type":"string"}},"type":"object"},"type":"array"},"has_external_integration_sync_error":{"description":"true when the last sync with an integration failed.","type":"boolean"},"has_invoice":{"description":"true when the order has at least one invoice, so a zero invoiced total can be told apart from no invoice.","type":"boolean"},"has_not_invoiced_items":{"description":"true when some line items are not on an invoice yet.","type":"boolean"},"has_over_invoiced_items":{"description":"true when some line items are invoiced for more than the order has.","type":"boolean"},"has_shipment_items_not_allocated":{"description":"true when some line items are not on a shipment yet.","type":"boolean"},"has_shipment_items_over_allocated":{"description":"true when some line items are on shipments for more than the order has.","type":"boolean"},"has_valid_invoice":{"description":"true when at least one of the order's invoices is in a valid state.","type":"boolean"},"has_valid_shipment":{"description":"true when at least one of the order's shipments is in a valid state.","type":"boolean"},"id":{"description":"The order's hash id: use it in every other call.","example":"V4keXwwxMQyXw7","type":"string"},"internal_status":{"description":"`draft` until published.","enum":["draft","published"],"type":"string"},"inventory_status":{"description":"Stock status of the order's lines: `not_committed`, `committed`, `partially_committed`, `not_applicable` or `pending`.","type":["string","null"]},"invoice_lock_version":{"description":"Changes whenever the order's invoices change.","type":["integer","string","null"]},"invoiced_discount_subtotal":{"description":"Discounts on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_order_item_subtotal":{"description":"The lines and shipping fees the order's invoices bill (the sum of their `cart_item_subtotal`); 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_shipment_subtotal":{"description":"The shipping fees in `invoiced_order_item_subtotal`; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_tax_subtotal":{"description":"Tax on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_total":{"description":"Total of the order's invoices. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"is_client_note_editable":{"description":"false for a Shopify order, whose client note comes from Shopify.","type":"boolean"},"is_external":{"description":"true for an order synced from an integration such as Shopify.","type":"boolean"},"is_legacy":{"description":"true for an order made in the old format.","type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"job_lock_version":{"description":"Changes whenever the order's jobs change.","type":["integer","string","null"]},"last_payment_request_date":{"description":"When a payment reminder was last emailed for the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"lock_version":{"description":"Changes on every save.","type":["integer","string","null"]},"mode":{"description":"Older flag: `create` for a draft, `view` once published.","enum":["create","view","edit"],"type":"string"},"name":{"example":"Spring team shirts","type":["string","null"]},"object_type":{"enum":["sales_order","quote"],"type":"string"},"order_balance_due":{"description":"Invoiced total minus paid. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_cart_total":{"description":"The value of the order's lines: the order's own total before invoicing. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_lock_version":{"description":"Changes whenever the order's line items change.","type":["integer","string","null"]},"order_margin_percentage":{"description":"Margin, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_markup_percentage":{"description":"Markup, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_profit":{"description":"Profit. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"paid_amount":{"description":"Paid so far. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"payment_lock_version":{"description":"Changes whenever the order's payments change.","type":["integer","string","null"]},"payment_term_id":{"type":["string","null"]},"pricing_group_id":{"type":["string","null"]},"pricing_strategy":{"description":"`job_separately`, `job_together` or `service_loc_together`.","type":["string","null"]},"prod_note":{"description":"The production note.","type":["string","null"]},"producible_item_count":{"description":"Quantity to produce.","type":["number","integer","string","null"]},"quickbook_disable_sync":{"description":"true when QuickBooks sync is off for this order.","type":"boolean"},"quickbook_disable_sync_at":{"description":"When the switch was last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_disable_sync_by":{"description":"The team member who last changed the switch, or null.","type":["string","null"]},"quickbook_disable_sync_reason":{"description":"The note given at the last change of the order's QuickBooks sync switch (off or back on), at most 500 characters, or null.","type":["string","null"]},"quickbook_last_error_sync":{"description":"When a QuickBooks sync of the order last failed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_last_success_sync":{"description":"When QuickBooks last accepted the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbooks_hold":{"description":"Set when YoPrint holds back a QuickBooks payment covering this order: `code` is `changed`, `deleted` or `rejected` (the payment was changed or deleted in QuickBooks, or QuickBooks refused a change), and `detail` is `already_deposited` (the payment is in a QuickBooks bank deposit) or null. Null when nothing is held.","properties":{"code":{"enum":["changed","deleted","rejected"],"type":"string"},"detail":{"type":["string","null"]}},"type":["object","null"]},"quote":{"description":"Older flag: true for a quote.","type":"boolean"},"scoped_id":{"description":"The order number people see, `SO` and at least four digits (quotes too). Not an id.","example":"SO1001","type":"string"},"ship_due_date":{"description":"Ship due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shipment_billable_fee_invoice_status":{"description":"Whether those shipping fees are on an invoice. Null when there is nothing to bill.","type":["string","null"]},"shipment_billable_fee_total":{"description":"The shipping fees you bill the customer on the order's shipments. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_cost_total":{"description":"Shipping cost incurred. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_lock_version":{"description":"Changes whenever the order's shipments change.","type":["integer","string","null"]},"shipping_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"shipping_address_id":{"type":["string","null"]},"shopify_last_error_sync":{"description":"When a Shopify sync of the order last failed. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_last_success_sync":{"description":"When Shopify last accepted the order. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_terminal_topic":{"description":"Shopify orders only: the Shopify event name behind the order's final state there. Null on YoPrint orders. The answer can also hold more `shopify_*` fields (`shopify_admin_url`, `shopify_compliance_deletion`, `shopify_finance_notices`, `shopify_has_fulfillment_conflict`, `shopify_last_fulfillment_conflict_at`): they are null or empty on YoPrint orders.","type":["string","null"]},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"The order's status (always included).","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_completion_date":{"description":"When the order's status last moved to an end status. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status_id":{"description":"The order's status (from the team's sales order or quote statuses).","example":"52CuV8sWcDZLPm","type":"string"},"status_last_change_date":{"description":"Last status change. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"tags":{"items":{"additionalProperties":true,"properties":{"color_hex":{"description":"Tag color, for example `#E53935`.","type":["string","null"]},"id":{"example":"7qYPMmbLZR9oFg","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"total_qty_need_ordering":{"description":"Quantity still to buy, as a decimal string with 8 decimal places (`\"24.00000000\"`).","example":"0.00000000","type":"string"},"trashed":{"description":"true when the order is deleted.","type":"boolean"},"type":{"description":"Older name for `object_type`.","enum":["order","quote"],"type":"string"},"unallocated_amount":{"description":"Payments not yet allocated to an invoice. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"unique_key":{"description":"The order's unique key (`ord_…`); accepted wherever `{order_unique_key}` is.","example":"ord_EXAMPLEuniqueKey","type":"string"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"version":{"description":"The order format version.","type":["integer","string","null"]},"wallet_currency_iso":{"description":"The order's currency code (`USD` and so on), or null on older orders without one.","example":"USD","type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"required":["id","unique_key","scoped_id","object_type","internal_status"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List sales orders","tags":["Sales orders"],"x-yoprint-docs":{"errors":[{"fix":"Check each filter against the table.","status":422,"when":"An unknown key, a wrong operator for the key, or a value of the wrong kind."},{"fix":"Ask the team owner for view permission.","status":403,"when":"The role can't view sales orders at all. This error has no envelope: the body is `{\"message\": \"You do not have permission to view this resource\"}`."}],"group":"Sales","notes":["Deleted sales orders are hidden unless you filter `trashed_only` `eq` true.","Drafts are included; filter `draft` `eq` false to leave them out.","Day offsets here count forward from today (7 is a week ahead). Some older v1 filters count the other way; check each filter's page before reusing a filter."],"permission":"Needs permission to view sales orders: a role that sees every order (`view_all_order`) gets all of them; a role that sees only its own (`view_self_order`) gets only the ones its user created. Without either, 403.","related":["v2_public_quote_filter","v2_public_order_show","v2_public_search_orders_post"],"rules":["Every filter needs `key`, `operator` and `value`, and the operator and value must suit the key; otherwise 422 with no detail of which filter failed.","Date filters take a whole number of days from today (UTC), not a calendar date: `0` is today, `7` is 7 days from today, `-7` is 7 days ago. The number becomes a UTC date and is compared with the stored date and time. `gte N` starts at 00:00 UTC of day N. `lte N` stops at 00:00 UTC of day N, so day N itself is left out. `eq N` matches only a record stamped exactly 00:00:00 UTC, so in practice almost nothing. Due dates are stored as the end of the team's local day, so a UTC day does not line up with it.","To cover the days A to B of your team's calendar, ask `gte A-1` and `lte B+2`, then keep the rows whose date falls in those days by checking the dates in your own code. For \"late\", ask `lte 1` and keep the rows whose date is before now.","Booleans must be JSON `true` or `false`.","Ids are the `id` fields of other answers (status, customer, user and tag ids)."]}}},"/v2/api/store/{team_slug}/v2/sales_order/new":{"post":{"description":"Creates a new draft sales order or quote. The draft already has its order number (`scoped_id`, such as SO1001) but sends nothing to the customer; add jobs and lines, then publish it.\n\nSet `object_type` to `quote` for a quote (or the older `quote: true`). Without either you get a sales order.\n\nThe new draft takes its defaults from the team and the customer: today's issue date, the customer's (or team's) pricing group, payment term and warehouse, the customer's primary brand profile, the team's starting status, and due and production dates from the team's settings.\n\nThe order number (`scoped_id`) is the team's next number unless you send your own, and publishing keeps it.\n\nTypical flow: create the draft, add jobs (`v2/sales_order/{hash_id}/job`), add line items, then publish. The answer is the order: its `id` and `unique_key`, `scoped_id` (the number people see), `name`, `object_type` (`sales_order` or `quote`), `internal_status` (`draft` until published), `status_id` and `status`, the customer and addresses, dates, notes, `is_rush`, pricing settings and totals. The value of the order's lines is `order_item_cart_total`. `invoiced_total`, `invoiced_order_item_subtotal`, `invoiced_shipment_subtotal`, `invoiced_tax_subtotal` and `invoiced_discount_subtotal` count only what has been **invoiced** (0 until the order has an invoice). They are **decimal pairs** (`{ \"value\": 850000, \"dp\": 4 }` is 85.00; always read `dp`). `paid_amount`, `calc_deposit_total` and `unallocated_amount` are in **thousandths** (`135000` is 135.00). `deposit_total` is a **percentage ×1000** (`50000` is 50%). `calc_subtotal`, `calc_discount`, `calc_tax` and `calc_total` are deprecated thousandths copies of the invoiced totals: they still return, but use the decimal pair fields instead.","operationId":"v2_public_order_create","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"quote":{"summary":"A quote","value":{"client_note":"Prices valid for 30 days.","customer_id":"63KcENAAsKuipY","object_type":"quote"}},"sales_order":{"summary":"A sales order for a customer","value":{"customer_id":"63KcENAAsKuipY","customer_po_number":"PO-1188","object_type":"sales_order"}}},"schema":{"properties":{"client_note":{"description":"The Client Note, printed on documents the customer receives.","type":["string","null"]},"customer_id":{"description":"The customer's `id`. Optional, but an order needs a customer before it can be published. An id that is not one of your customers is ignored.","type":"string"},"customer_po_number":{"description":"The customer's purchase order number.","type":["string","null"]},"object_type":{"description":"`quote` for a quote; `sales_order` (the default) for a sales order.","enum":["sales_order","quote"],"type":"string"},"quote":{"description":"Older way to ask for a quote. If you send both, they must agree.","type":"boolean"},"scoped_id":{"description":"Your own order number. Leave it out to get the team's next number.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"calc_deposit_total":0,"customer":{"id":"63KcENAAsKuipY","is_external":false,"name":"Northwind Apparel","tax_exempt":false},"customer_id":"63KcENAAsKuipY","customer_po_number":"PO-1188","deposit_amount_due":{"dp":4,"value":0},"deposit_required":true,"deposit_total":50000,"due_date":"2026-11-14T00:00:00+00:00","id":"V4keXwwxMQyXw7","internal_status":"draft","invoiced_discount_subtotal":{"dp":0,"value":0},"invoiced_order_item_subtotal":{"dp":0,"value":0},"invoiced_shipment_subtotal":{"dp":0,"value":0},"invoiced_tax_subtotal":{"dp":0,"value":0},"invoiced_total":{"dp":0,"value":0},"is_rush":false,"issue_date":"2026-11-03T09:00:00+00:00","mode":"create","name":null,"object_type":"sales_order","order_balance_due":{"dp":4,"value":0},"order_item_cart_total":{"dp":0,"value":0},"paid_amount":0,"quote":false,"scoped_id":"SO1001","status":{"color":"#9e9e9e","customer_label":"Pending","id":"HqXxdtvY4icbzQ","label":"New","position":1,"role":"order","trashed":false,"type":"start"},"status_id":"HqXxdtvY4icbzQ","total_qty_need_ordering":"0.00000000","trashed":false,"type":"order","unique_key":"ord_EXAMPLEuniqueKey"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A sales order or quote.","properties":{"approval_status":{"description":"`requested`, `sent-to-customer`, `viewed-by-customer`, `need-changes` or `approved`; null without approvals.","type":["string","null"]},"assigned_users":{"description":"The team members in the order's Assigned To list (always included).","items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"auto_invoice_managed":{"description":"true when YoPrint keeps one invoice in step with the order.","type":"boolean"},"auto_invoice_shipment_price_type":{"description":"`DONOTMANAGE`, `NONE`, `MARKUP` or `MARGIN`.","type":["string","null"]},"auto_invoice_shipment_rate":{"description":"The MARKUP or MARGIN percentage. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"auto_invoice_type":{"description":"How the automatic invoice is built. Always `single_invoice` today.","type":["string","null"]},"billing_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"billing_address_id":{"type":["string","null"]},"calc_deposit_total":{"description":"The deposit amount, rounded to 2 decimal places: the percentage of `order_item_cart_total`, or of the invoiced total once every line is invoiced (or the invoiced total reaches the order's); 0 unless `deposit_required`. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `invoiced_discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `invoiced_order_item_subtotal`, which already includes billed shipping. This older field adds `invoiced_shipment_subtotal` to it once more. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `invoiced_tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `invoiced_total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"client_note":{"description":"The Client Note.","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_by":{"description":"Created By (a team member id).","type":["string","null"]},"creator_name":{"type":["string","null"]},"cust_due_date":{"description":"Customer in-hands date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"Always present on order answers, lists included: the customer record, or null when the order has none. Get a sales order also nests the customer's contacts, addresses, brand profiles, tags, files and assigned users in it.","properties":{"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"id":{"example":"63KcENAAsKuipY","type":"string"},"is_external":{"description":"true for a customer synced from an integration.","type":"boolean"},"name":{"example":"Northwind Apparel","type":"string"},"tax_exempt":{"type":"boolean"}},"type":["object","null"]},"customer_billing_contact_id":{"description":"The id of the contact on the order (the same contact as `customer_contact_id`), or null.","type":["string","null"]},"customer_contact_id":{"type":["string","null"]},"customer_has_email":{"type":"boolean"},"customer_id":{"example":"63KcENAAsKuipY","type":["string","null"]},"customer_po_number":{"example":"PO-1188","type":["string","null"]},"customer_profile_id":{"description":"Brand profile.","type":["string","null"]},"deposit_amount_due":{"description":"Deposit still to pay (negative once overpaid). A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"deposit_due":{"description":"Deposit due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"deposit_required":{"type":"boolean"},"deposit_total":{"description":"The deposit as a **percentage** of the order. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","type":["integer","number","string","null"]},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"external_ids":{"description":"The order's links to records in other systems. An empty list when there are none.","items":{"additionalProperties":true,"description":"One link to a record in another system (Shopify, QuickBooks and so on): `id`, `external_integration_id`, `external_id`, `data`, `created_at`, `updated_at` and the nested `external_integration`.","type":"object"},"type":"array"},"external_type":{"description":"`shopify` for a Shopify order; null for YoPrint orders.","type":["string","null"]},"from_legacy":{"description":"true for an order that was moved over from the old format.","type":"boolean"},"full_amount_due":{"description":"Full payment due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"grouped_pdf":{"description":"PDF links, grouped: `Main` (only for roles with `view_order_finance`), `Job` (not on Shopify orders), `Shipment` and the team's templates.","items":{"additionalProperties":true,"properties":{"documents":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"label":{"example":"Main","type":"string"}},"type":"object"},"type":"array"},"has_external_integration_sync_error":{"description":"true when the last sync with an integration failed.","type":"boolean"},"has_invoice":{"description":"true when the order has at least one invoice, so a zero invoiced total can be told apart from no invoice.","type":"boolean"},"has_not_invoiced_items":{"description":"true when some line items are not on an invoice yet.","type":"boolean"},"has_over_invoiced_items":{"description":"true when some line items are invoiced for more than the order has.","type":"boolean"},"has_shipment_items_not_allocated":{"description":"true when some line items are not on a shipment yet.","type":"boolean"},"has_shipment_items_over_allocated":{"description":"true when some line items are on shipments for more than the order has.","type":"boolean"},"has_valid_invoice":{"description":"true when at least one of the order's invoices is in a valid state.","type":"boolean"},"has_valid_shipment":{"description":"true when at least one of the order's shipments is in a valid state.","type":"boolean"},"id":{"description":"The order's hash id: use it in every other call.","example":"V4keXwwxMQyXw7","type":"string"},"internal_status":{"description":"`draft` until published.","enum":["draft","published"],"type":"string"},"inventory_status":{"description":"Stock status of the order's lines: `not_committed`, `committed`, `partially_committed`, `not_applicable` or `pending`.","type":["string","null"]},"invoice_lock_version":{"description":"Changes whenever the order's invoices change.","type":["integer","string","null"]},"invoiced_discount_subtotal":{"description":"Discounts on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_order_item_subtotal":{"description":"The lines and shipping fees the order's invoices bill (the sum of their `cart_item_subtotal`); 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_shipment_subtotal":{"description":"The shipping fees in `invoiced_order_item_subtotal`; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_tax_subtotal":{"description":"Tax on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_total":{"description":"Total of the order's invoices. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"is_client_note_editable":{"description":"false for a Shopify order, whose client note comes from Shopify.","type":"boolean"},"is_external":{"description":"true for an order synced from an integration such as Shopify.","type":"boolean"},"is_legacy":{"description":"true for an order made in the old format.","type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"job_lock_version":{"description":"Changes whenever the order's jobs change.","type":["integer","string","null"]},"last_payment_request_date":{"description":"When a payment reminder was last emailed for the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"lock_version":{"description":"Changes on every save.","type":["integer","string","null"]},"mode":{"description":"Older flag: `create` for a draft, `view` once published.","enum":["create","view","edit"],"type":"string"},"name":{"example":"Spring team shirts","type":["string","null"]},"object_type":{"enum":["sales_order","quote"],"type":"string"},"order_balance_due":{"description":"Invoiced total minus paid. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_cart_total":{"description":"The value of the order's lines: the order's own total before invoicing. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_lock_version":{"description":"Changes whenever the order's line items change.","type":["integer","string","null"]},"order_margin_percentage":{"description":"Margin, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_markup_percentage":{"description":"Markup, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_profit":{"description":"Profit. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"paid_amount":{"description":"Paid so far. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"payment_lock_version":{"description":"Changes whenever the order's payments change.","type":["integer","string","null"]},"payment_term_id":{"type":["string","null"]},"pricing_group_id":{"type":["string","null"]},"pricing_strategy":{"description":"`job_separately`, `job_together` or `service_loc_together`.","type":["string","null"]},"prod_note":{"description":"The production note.","type":["string","null"]},"producible_item_count":{"description":"Quantity to produce.","type":["number","integer","string","null"]},"quickbook_disable_sync":{"description":"true when QuickBooks sync is off for this order.","type":"boolean"},"quickbook_disable_sync_at":{"description":"When the switch was last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_disable_sync_by":{"description":"The team member who last changed the switch, or null.","type":["string","null"]},"quickbook_disable_sync_reason":{"description":"The note given at the last change of the order's QuickBooks sync switch (off or back on), at most 500 characters, or null.","type":["string","null"]},"quickbook_last_error_sync":{"description":"When a QuickBooks sync of the order last failed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_last_success_sync":{"description":"When QuickBooks last accepted the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbooks_hold":{"description":"Set when YoPrint holds back a QuickBooks payment covering this order: `code` is `changed`, `deleted` or `rejected` (the payment was changed or deleted in QuickBooks, or QuickBooks refused a change), and `detail` is `already_deposited` (the payment is in a QuickBooks bank deposit) or null. Null when nothing is held.","properties":{"code":{"enum":["changed","deleted","rejected"],"type":"string"},"detail":{"type":["string","null"]}},"type":["object","null"]},"quote":{"description":"Older flag: true for a quote.","type":"boolean"},"scoped_id":{"description":"The order number people see, `SO` and at least four digits (quotes too). Not an id.","example":"SO1001","type":"string"},"ship_due_date":{"description":"Ship due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shipment_billable_fee_invoice_status":{"description":"Whether those shipping fees are on an invoice. Null when there is nothing to bill.","type":["string","null"]},"shipment_billable_fee_total":{"description":"The shipping fees you bill the customer on the order's shipments. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_cost_total":{"description":"Shipping cost incurred. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_lock_version":{"description":"Changes whenever the order's shipments change.","type":["integer","string","null"]},"shipping_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"shipping_address_id":{"type":["string","null"]},"shopify_last_error_sync":{"description":"When a Shopify sync of the order last failed. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_last_success_sync":{"description":"When Shopify last accepted the order. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_terminal_topic":{"description":"Shopify orders only: the Shopify event name behind the order's final state there. Null on YoPrint orders. The answer can also hold more `shopify_*` fields (`shopify_admin_url`, `shopify_compliance_deletion`, `shopify_finance_notices`, `shopify_has_fulfillment_conflict`, `shopify_last_fulfillment_conflict_at`): they are null or empty on YoPrint orders.","type":["string","null"]},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"The order's status (always included).","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_completion_date":{"description":"When the order's status last moved to an end status. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status_id":{"description":"The order's status (from the team's sales order or quote statuses).","example":"52CuV8sWcDZLPm","type":"string"},"status_last_change_date":{"description":"Last status change. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"tags":{"items":{"additionalProperties":true,"properties":{"color_hex":{"description":"Tag color, for example `#E53935`.","type":["string","null"]},"id":{"example":"7qYPMmbLZR9oFg","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"total_qty_need_ordering":{"description":"Quantity still to buy, as a decimal string with 8 decimal places (`\"24.00000000\"`).","example":"0.00000000","type":"string"},"trashed":{"description":"true when the order is deleted.","type":"boolean"},"type":{"description":"Older name for `object_type`.","enum":["order","quote"],"type":"string"},"unallocated_amount":{"description":"Payments not yet allocated to an invoice. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"unique_key":{"description":"The order's unique key (`ord_…`); accepted wherever `{order_unique_key}` is.","example":"ord_EXAMPLEuniqueKey","type":"string"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"version":{"description":"The order format version.","type":["integer","string","null"]},"wallet_currency_iso":{"description":"The order's currency code (`USD` and so on), or null on older orders without one.","example":"USD","type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"required":["id","unique_key","scoped_id","object_type","internal_status"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a sales order or quote","tags":["Sales orders"],"x-yoprint-docs":{"errors":[{"fix":"Set a default pricing group in Settings, send matching values, or pick another customer.","status":422,"when":"The team has no default pricing group, `object_type` and `quote` disagree, or the customer comes from Shopify."},{"fix":"Leave `is_external` out.","status":422,"when":"`is_external: true`: \"Cannot create external object from API.\""},{"fix":"Ask the team owner for permission to create orders.","status":403,"when":"The API key's role lacks `create_order`."}],"group":"Sales","notes":["The answer's `id` is the order's id for every other call. Save it.","A new draft has no name; set one with Update.","Change the customer of a draft later with the `change_customer` action, not with Update."],"permission":"Needs the `create_order` permission (the team owner always has it). Quotes use the same permission.","related":["v2_public_job_store","v2_public_order_item_store","v2_public_order_publish","v2_public_order_update"],"rules":["The team must have a default pricing group: \"This team must have a default pricing group configured before creating an order or quote.\"","`object_type` and `quote`, when both sent, must describe the same thing.","A customer synced from Shopify can't be used: \"Shopify customer cannot be used for native order or quote creation.\"","Creating with `is_external: true` is refused for integrations."],"side_effects":["Creates a draft. No email, webhook or stock change happens until you publish."]}}},"/v2/api/store/{team_slug}/v2/sales_order/order_item/{order_item_unique_key}":{"delete":{"description":"Deletes one line and recalculates the order's totals.\n\n`{order_item_unique_key}` is the line's `id` (a hash id) from the order's line items. Its `orditm_` unique key is also accepted, but no API answer shows it, so use `id`.\n\nDeleting a line that is already deleted is safe: it returns 200 with the line and `action_performed: \"NONE\"` (a line an integration brought in is refused with 422 even then). Otherwise the answer is the deleted line in `data.item` (`trashed: true`) with `action_performed: \"DELETED\"`.","operationId":"v2_public_order_item_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The line's `id` (a hash id), from the order's line items. Its `orditm_…` unique key is also accepted, but no API answer shows it, so use `id`.","example":"Owr88lhAk28aqL","in":"path","name":"order_item_unique_key","required":true,"schema":{"example":"Owr88lhAk28aqL","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"action_performed":"DELETED","has_changes":true,"item":{"id":"Owr88lhAk28aqL","job":{"id":"K6iF8n29iwOZnj","scoped_id":"JOB-1001","type":"linked","unique_key":"job_EXAMPLEuniqueKey"},"lock_version":1793696400234567,"order_id":"V4keXwwxMQyXw7","order_unique_key":"ord_EXAMPLEuniqueKey","position":200000,"pricing":{"product":{"override":true,"total":{"dp":6,"value":12500000}},"type":"product_cost_service"},"product":{"properties":{"customer_supplied":false,"id":"nqSB3HG1O2u5Jg"},"type":"user_simple"},"quantity":{"total":{"dp":0,"value":10},"type":"unit"},"subtotal":{"dp":4,"value":1250000},"trashed":true,"type":"user_simple","unit_price":{"dp":6,"value":12500000}},"lock_version":{"order":{"invoice_lock_version":1793696400123456,"job_lock_version":1793696400123456,"order_item_lock_version":1793696400234567,"order_lock_version":1793696400234567,"payment_lock_version":1793696400123456,"shipment_lock_version":null}},"object_type":"order_item"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"action_performed":{"description":"`NONE` when nothing changed.","enum":["CREATED","UPDATED","DELETED","NONE"],"type":"string"},"has_changes":{"type":"boolean"},"item":{"additionalProperties":true,"description":"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).","properties":{"_meta":{"additionalProperties":true,"description":"The line's own values again (`id`, `type`, `order_id`, `unit_price`, `subtotal` and so on). Always an object.","type":"object"},"id":{"example":"Owr88lhAk28aqL","type":"string"},"inventory_status":{"description":"Stock status of the line.","type":["string","null"]},"job":{"additionalProperties":true,"type":"object"},"lock_version":{"description":"The line's own lock version (a microsecond timestamp).","type":["integer","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_unique_key":{"description":"The order's `unique_key`. The line's own `unique_key` is not in the answer: use `id`.","example":"ord_EXAMPLEuniqueKey","type":"string"},"position":{"example":200000,"type":"integer"},"pricing":{"additionalProperties":true,"type":"object"},"pricing_rule_applied":{"description":"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.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"11.05","type":"string"},"after_total":{"description":"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.","example":{"dp":6,"value":11050000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: that starting price, as a decimal string with at least 2 decimal places.","example":"8.50","type":"string"},"base_type":{"description":"Full summary only: what the rule started from: the supplier price for catalog lines, the product's own price for other lines.","enum":["supplier_price","base_price"],"type":"string"},"normal_price":{"description":"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`.","example":"11.05","type":["string","null"]},"original_total":{"description":"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.","example":{"dp":6,"value":8500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The line keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`product` on a line.","example":"product","type":"string"}},"type":["object","null"]},"product":{"additionalProperties":true,"type":"object"},"quantity":{"additionalProperties":true,"description":"The quantity, trailing zeros dropped: 10 is `{ \"value\": 10, \"dp\": 0 }`.","type":"object"},"subtotal":{"description":"`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.","example":{"dp":4,"value":1250000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"trashed":{"description":"true when the line was deleted.","example":false,"type":"boolean"},"type":{"description":"The kind of line: db_catalog, user_simple, db_variant, custom or fee.","example":"user_simple","type":"string"},"unit_price":{"description":"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.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"}},"type":"object"},"lock_version":{"description":"The order's lock versions after this call. Each is a whole number (a microsecond timestamp) that changes on every save, or null.","properties":{"order":{"properties":{"invoice_lock_version":{"type":["integer","null"]},"job_lock_version":{"type":["integer","null"]},"order_item_lock_version":{"type":["integer","null"]},"order_lock_version":{"description":"The order's own `lock_version`.","type":["integer","null"]},"payment_lock_version":{"type":["integer","null"]},"shipment_lock_version":{"type":["integer","null"]}},"type":"object"}},"required":["order"],"type":"object"},"object_type":{"const":"order_item","example":"order_item","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a line item","tags":["Sales order line items"],"x-yoprint-docs":{"errors":[{"fix":"Change it where it came from, or repair the job in the web app.","status":422,"when":"The line came from an integration, or its job's services need repair."},{"fix":"Ask the team owner for sales order edit permission.","status":403,"when":"The API key's role can't edit this order."},{"fix":"Check the id.","status":404,"when":"The line does not exist in this team."}],"group":"Sales","permission":"Needs permission to edit this sales order or quote:\n\n- The team owner\n- A role with `update_all_order`\n- A role with `update_self_order`, when the order was created by or is assigned to the API key's user\n- The person who created a draft, with `create_order`\n\nQuotes use the same sales order permissions.","related":["v2_public_order_item_bulk","v2_public_order_item_index"],"rules":["Lines an integration brought in can't be deleted through the API: \"Cannot delete external object from API.\"","Refused while the line's job has a decoration setup that needs repair."],"side_effects":["Removes the line from the order's shipments and from every invoice of the order, and cancels its stock reservations and purchase links.","Recalculates the job's decoration pricing, the order totals and auto-managed 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."]}},"get":{"description":"Returns one line of a sales order or quote.\n\n`{order_item_unique_key}` is the line's `id` (a hash id) from the order's line items. Its `orditm_` unique key is also accepted, but no API answer shows it, so use `id`. The line comes back in the same shape as in the list.","operationId":"v2_public_order_item_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The line's `id` (a hash id), from the order's line items. Its `orditm_…` unique key is also accepted, but no API answer shows it, so use `id`.","example":"Owr88lhAk28aqL","in":"path","name":"order_item_unique_key","required":true,"schema":{"example":"Owr88lhAk28aqL","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"id":"Owr88lhAk28aqL","job":{"id":"K6iF8n29iwOZnj","scoped_id":"JOB-1001","type":"linked","unique_key":"job_EXAMPLEuniqueKey"},"lock_version":1793696400234567,"order_id":"V4keXwwxMQyXw7","order_unique_key":"ord_EXAMPLEuniqueKey","position":200000,"pricing":{"product":{"override":true,"total":{"dp":6,"value":12500000}},"type":"product_cost_service"},"product":{"properties":{"customer_supplied":false,"id":"nqSB3HG1O2u5Jg"},"type":"user_simple"},"quantity":{"total":{"dp":0,"value":10},"type":"unit"},"subtotal":{"dp":4,"value":1250000},"trashed":false,"type":"user_simple","unit_price":{"dp":6,"value":12500000}},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"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).","properties":{"_meta":{"additionalProperties":true,"description":"The line's own values again (`id`, `type`, `order_id`, `unit_price`, `subtotal` and so on). Always an object.","type":"object"},"id":{"example":"Owr88lhAk28aqL","type":"string"},"inventory_status":{"description":"Stock status of the line.","type":["string","null"]},"job":{"additionalProperties":true,"type":"object"},"lock_version":{"description":"The line's own lock version (a microsecond timestamp).","type":["integer","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_unique_key":{"description":"The order's `unique_key`. The line's own `unique_key` is not in the answer: use `id`.","example":"ord_EXAMPLEuniqueKey","type":"string"},"position":{"example":200000,"type":"integer"},"pricing":{"additionalProperties":true,"type":"object"},"pricing_rule_applied":{"description":"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.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"11.05","type":"string"},"after_total":{"description":"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.","example":{"dp":6,"value":11050000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: that starting price, as a decimal string with at least 2 decimal places.","example":"8.50","type":"string"},"base_type":{"description":"Full summary only: what the rule started from: the supplier price for catalog lines, the product's own price for other lines.","enum":["supplier_price","base_price"],"type":"string"},"normal_price":{"description":"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`.","example":"11.05","type":["string","null"]},"original_total":{"description":"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.","example":{"dp":6,"value":8500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The line keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`product` on a line.","example":"product","type":"string"}},"type":["object","null"]},"product":{"additionalProperties":true,"type":"object"},"quantity":{"additionalProperties":true,"description":"The quantity, trailing zeros dropped: 10 is `{ \"value\": 10, \"dp\": 0 }`.","type":"object"},"subtotal":{"description":"`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.","example":{"dp":4,"value":1250000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"trashed":{"description":"true when the line was deleted.","example":false,"type":"boolean"},"type":{"description":"The kind of line: db_catalog, user_simple, db_variant, custom or fee.","example":"user_simple","type":"string"},"unit_price":{"description":"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.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get one line item","tags":["Sales order line items"],"x-yoprint-docs":{"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_item_index","v2_public_order_item_update"]}},"put":{"description":"Changes one line and recalculates the order's totals. Send only what changes; everything you leave out keeps its value.\n\nThe line's kind can't change: if you send `product.type` or `pricing.type`, it must be the line's own. Each object you send (`product`, `pricing`, `quantity`, `job`, `weight`) must include its `type`.\n\nWhat an update can change:\n\n- the quantity;\n- the price: `pricing.product` (your own price), `pricing.service` (decoration price), `pricing.product_cost`, and for catalog lines `pricing.catalog`;\n- the job (`job`), within the same order;\n- the position and the weight;\n- the line's description, and the name of a custom line or fee.\n\nThe product itself (its id, or the catalog item) and `customer_supplied` can't change: delete the line and add a new one.\n\nAmounts 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.\n\n`{order_item_unique_key}` is the line's `id` (a hash id) from the order's line items. Its `orditm_` unique key is also accepted, but no API answer shows it, so use `id`.\n\nThe answer is `data.item`, the saved line, with `action_performed` `UPDATED`, or `NONE` and `has_changes: false` when nothing changed.","operationId":"v2_public_order_item_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The line's `id` (a hash id), from the order's line items. Its `orditm_…` unique key is also accepted, but no API answer shows it, so use `id`.","example":"Owr88lhAk28aqL","in":"path","name":"order_item_unique_key","required":true,"schema":{"example":"Owr88lhAk28aqL","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"catalog":{"summary":"Change a catalog line's quantity","value":{"quantity":{"total":{"dp":0,"value":36},"type":"unit"}},"x-yoprint-variant":"Catalog product"},"custom":{"summary":"Rename a custom line and change its price","value":{"pricing":{"product":{"override":true,"total":{"dp":2,"value":350}},"type":"custom_product"},"product":{"properties":{"name":"Woven patch"},"type":"custom"}},"x-yoprint-variant":"Custom line item"},"fee":{"summary":"Change a fee's amount","value":{"pricing":{"product":{"total":{"dp":2,"value":3000}},"type":"fee"}},"x-yoprint-variant":"Fee line item"},"simple":{"summary":"Set your own price on a simple-product line","value":{"pricing":{"product":{"override":true,"total":{"dp":2,"value":1400}},"type":"product_cost_service"}},"x-yoprint-variant":"Custom simple product"},"variant":{"summary":"Move a variant line to another job of the order","value":{"job":{"id":"I3hKS5NY8hhW8u","type":"linked"}},"x-yoprint-variant":"Custom variant product"}},"schema":{"anyOf":[{"description":"Change a product from a supplier catalog (one size and color).","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. YoPrint determines the product price in this order:\n\n1. Price override: if `product.override` is true, YoPrint uses `product.total`.\n2. Customer-supplied: if `customer_supplied` is true (`product.properties.customer_supplied`), the product price is 0.\n3. Marked-up cost: otherwise, YoPrint takes the supplier cost in `catalog` and applies the order's pricing group markup or a matching pricing rule.\n\nOn an update, `catalog` is optional; send it to change the supplier cost.","properties":{"catalog":{"description":"The supplier price the line starts from. When you send `catalog`, all four fields are required.","properties":{"date":{"description":"When the price was looked up, an ISO 8601 date such as 2026-11-03 (a date-time is accepted too).","format":"date","type":"string"},"provider":{"description":"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.","type":"string"},"selected":{"description":"Which supplier price `total` represents:\n\n- `piece`: standard piece price\n- `dozen`: dozen price tier\n- `case`: case price tier\n- `account`: your account's negotiated price (`your_price` in catalog lookups)\n- `sales`: the supplier's sale price (`sales_price` in catalog lookups)\n- `custom`: a custom cost you entered manually\n- `legacy`: lines migrated from the old editor","enum":["piece","dozen","case","account","sales","custom","legacy"],"type":"string"},"total":{"description":"The supplier's cost for one unit.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["provider","selected","date","total"],"type":"object"},"product":{"description":"Set your own product price for one unit with `override: true` and `total`. It replaces the marked-up catalog cost.","properties":{"override":{"description":"true to use `total` as given; false to let YoPrint work it out.","type":"boolean"},"total":{"description":"The amount for one unit, as a `{ value, dp }` pair. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"catalog_product_pricing","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"}},"type":"object"},"type":{"const":"db_catalog","type":"string"}},"required":["type"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out to use the product's weight.","discriminator":{"mapping":{"mass":"#/components/schemas/WeightMassUpdate","use_system":"#/components/schemas/WeightUseSystem"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/WeightUseSystem"},{"$ref":"#/components/schemas/WeightMassUpdate"}],"title":"Weight"}},"title":"Catalog product","type":"object"},{"description":"Change one of your own products that has no sizes or colors.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. YoPrint determines the product price in this order:\n\n1. Price override: if `product.override` is true, YoPrint uses `product.total`.\n2. Customer-supplied: if `customer_supplied` is true (`product.properties.customer_supplied`), the product price is 0.\n3. Product pricing: otherwise, YoPrint starts from `product_cost.total` (or the price from Products when omitted or 0) and applies any matching pricing rule.","properties":{"product":{"description":"Set your own product price for one unit with `override: true` and `total`.","properties":{"override":{"description":"true to use `total` as given; false to let YoPrint work it out.","type":"boolean"},"total":{"description":"The amount for one unit, as a `{ value, dp }` pair. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"product_cost":{"description":"Your cost for one unit. Optional: leave it out, or send a total of 0, to use the product's price from Products.","properties":{"override":{"description":"true when you set the cost yourself.","type":"boolean"},"total":{"description":"The cost for one unit. 0 means \"use the product's price\".","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override","total"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"product_cost_service","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"}},"type":"object"},"type":{"const":"user_simple","type":"string"}},"required":["type"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out to use the product's weight.","discriminator":{"mapping":{"mass":"#/components/schemas/WeightMassUpdate","use_system":"#/components/schemas/WeightUseSystem"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/WeightUseSystem"},{"$ref":"#/components/schemas/WeightMassUpdate"}],"title":"Weight"}},"title":"Custom simple product","type":"object"},{"description":"Change one size and color of your own product.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. YoPrint determines the product price in this order:\n\n1. Price override: if `product.override` is true, YoPrint uses `product.total`.\n2. Customer-supplied: if `customer_supplied` is true (`product.properties.customer_supplied`), the product price is 0.\n3. Product pricing: otherwise, YoPrint starts from `product_cost.total` (or the price from Products when omitted or 0) and applies any matching pricing rule.","properties":{"product":{"description":"Set your own product price for one unit with `override: true` and `total`.","properties":{"override":{"description":"true to use `total` as given; false to let YoPrint work it out.","type":"boolean"},"total":{"description":"The amount for one unit, as a `{ value, dp }` pair. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"product_cost":{"description":"Your cost for one unit. Optional: leave it out, or send a total of 0, to use the product's price from Products.","properties":{"override":{"description":"true when you set the cost yourself.","type":"boolean"},"total":{"description":"The cost for one unit. 0 means \"use the product's price\".","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override","total"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"product_cost_service","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"}},"type":"object"},"type":{"const":"db_variant","type":"string"}},"required":["type"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out to use the product's weight.","discriminator":{"mapping":{"mass":"#/components/schemas/WeightMassUpdate","use_system":"#/components/schemas/WeightUseSystem"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/WeightUseSystem"},{"$ref":"#/components/schemas/WeightMassUpdate"}],"title":"Weight"}},"title":"Custom variant product","type":"object"},{"description":"Change a one-off line with a name and a price, not linked to a product.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. Send the unit price in `product.total` with `override: true`.","properties":{"product":{"description":"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.","properties":{"override":{"description":"true to use `total` as the price.","type":"boolean"},"total":{"description":"The price for one unit. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"product_cost":{"description":"Optional: your cost for one unit, used for profit and margin.","properties":{"total":{"description":"Your cost for one unit.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"custom_product","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"},"name":{"description":"The line's name, as the customer sees it.","type":"string"}},"type":"object"},"type":{"const":"custom","type":"string"}},"required":["type"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type"],"type":"object"},"weight":{"description":"Optional, used for shipping.","oneOf":[{"description":"Your own weight for one unit. `unit` is required; leave `total` out to keep the current weight.","properties":{"total":{"description":"The weight as a `{ value, dp }` pair whose two parts are strings: 1.5 is `{ \"value\": \"15\", \"dp\": \"1\" }`.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, as a string.","type":"string"},"value":{"description":"The weight without its decimal point, as a string of digits.","type":"string"}},"required":["value","dp"],"type":"object"},"type":{"const":"mass","type":"string"},"unit":{"enum":["lb","kg"],"type":"string"}},"required":["type","unit"],"title":"Set the weight","type":"object"}],"title":"Weight"}},"title":"Custom line item","type":"object"},{"description":"Change a fee, such as a rush or setup fee.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"The fee amount for one unit. Fees never take a decoration price.","properties":{"product":{"properties":{"total":{"description":"The fee for one unit, 0 or more.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"type":{"const":"fee","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"description":{"description":"Extra text shown under the fee, for example what it covers.","type":"string"},"name":{"description":"The fee's name, for example \"Rush fee\".","type":"string"}},"type":"object"},"type":{"const":"fee","type":"string"}},"required":["type"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out for no weight.","oneOf":[{"description":"Your own weight for one unit. `unit` is required; leave `total` out to keep the current weight.","properties":{"total":{"description":"The weight as a `{ value, dp }` pair whose two parts are strings: 1.5 is `{ \"value\": \"15\", \"dp\": \"1\" }`.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, as a string.","type":"string"},"value":{"description":"The weight without its decimal point, as a string of digits.","type":"string"}},"required":["value","dp"],"type":"object"},"type":{"const":"mass","type":"string"},"unit":{"enum":["lb","kg"],"type":"string"}},"required":["type","unit"],"title":"Set the weight","type":"object"}],"title":"Weight"}},"title":"Fee line item","type":"object"}],"description":"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.","title":"What kind of line are you changing?","x-yoprint-discriminator":{"mapping":{"custom":"Custom line item","db_catalog":"Catalog product","db_variant":"Custom variant product","fee":"Fee line item","user_simple":"Custom simple product"},"propertyPath":"product.type"}}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"action_performed":"UPDATED","has_changes":true,"item":{"id":"Owr88lhAk28aqL","job":{"id":"K6iF8n29iwOZnj","scoped_id":"JOB-1001","type":"linked","unique_key":"job_EXAMPLEuniqueKey"},"lock_version":1793696400234567,"order_id":"V4keXwwxMQyXw7","order_unique_key":"ord_EXAMPLEuniqueKey","position":200000,"pricing":{"product":{"override":true,"total":{"dp":6,"value":14000000}},"type":"product_cost_service"},"product":{"properties":{"customer_supplied":false,"id":"nqSB3HG1O2u5Jg"},"type":"user_simple"},"quantity":{"total":{"dp":0,"value":10},"type":"unit"},"subtotal":{"dp":4,"value":1400000},"trashed":false,"type":"user_simple","unit_price":{"dp":6,"value":14000000}},"lock_version":{"order":{"invoice_lock_version":1793696400123456,"job_lock_version":1793696400123456,"order_item_lock_version":1793696400234567,"order_lock_version":1793696400234567,"payment_lock_version":1793696400123456,"shipment_lock_version":null}},"object_type":"order_item"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"action_performed":{"description":"`NONE` when nothing changed.","enum":["CREATED","UPDATED","DELETED","NONE"],"type":"string"},"has_changes":{"type":"boolean"},"item":{"additionalProperties":true,"description":"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).","properties":{"_meta":{"additionalProperties":true,"description":"The line's own values again (`id`, `type`, `order_id`, `unit_price`, `subtotal` and so on). Always an object.","type":"object"},"id":{"example":"Owr88lhAk28aqL","type":"string"},"inventory_status":{"description":"Stock status of the line.","type":["string","null"]},"job":{"additionalProperties":true,"type":"object"},"lock_version":{"description":"The line's own lock version (a microsecond timestamp).","type":["integer","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_unique_key":{"description":"The order's `unique_key`. The line's own `unique_key` is not in the answer: use `id`.","example":"ord_EXAMPLEuniqueKey","type":"string"},"position":{"example":200000,"type":"integer"},"pricing":{"additionalProperties":true,"type":"object"},"pricing_rule_applied":{"description":"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.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"11.05","type":"string"},"after_total":{"description":"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.","example":{"dp":6,"value":11050000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: that starting price, as a decimal string with at least 2 decimal places.","example":"8.50","type":"string"},"base_type":{"description":"Full summary only: what the rule started from: the supplier price for catalog lines, the product's own price for other lines.","enum":["supplier_price","base_price"],"type":"string"},"normal_price":{"description":"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`.","example":"11.05","type":["string","null"]},"original_total":{"description":"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.","example":{"dp":6,"value":8500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The line keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`product` on a line.","example":"product","type":"string"}},"type":["object","null"]},"product":{"additionalProperties":true,"type":"object"},"quantity":{"additionalProperties":true,"description":"The quantity, trailing zeros dropped: 10 is `{ \"value\": 10, \"dp\": 0 }`.","type":"object"},"subtotal":{"description":"`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.","example":{"dp":4,"value":1250000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"trashed":{"description":"true when the line was deleted.","example":false,"type":"boolean"},"type":{"description":"The kind of line: db_catalog, user_simple, db_variant, custom or fee.","example":"user_simple","type":"string"},"unit_price":{"description":"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.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"}},"type":"object"},"lock_version":{"description":"The order's lock versions after this call. Each is a whole number (a microsecond timestamp) that changes on every save, or null.","properties":{"order":{"properties":{"invoice_lock_version":{"type":["integer","null"]},"job_lock_version":{"type":["integer","null"]},"order_item_lock_version":{"type":["integer","null"]},"order_lock_version":{"description":"The order's own `lock_version`.","type":["integer","null"]},"payment_lock_version":{"type":["integer","null"]},"shipment_lock_version":{"type":["integer","null"]}},"type":"object"}},"required":["order"],"type":"object"},"object_type":{"const":"order_item","example":"order_item","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a line item","tags":["Sales order line items"],"x-yoprint-docs":{"errors":[{"fix":"Read `error.fields`; send whole numbers in `value` and the decimal places in `dp` (for example `{\"value\": 1250, \"dp\": 2}` for 12.50).","status":422,"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":"Use an id from Products, or a catalog item id.","status":422,"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 a job id from this order's jobs.","status":422,"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":"Fix the job's services in the web app, then retry.","status":422,"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":"Resume it in Products, or choose another product.","status":422,"when":"The product, or its size or color, is phased out or deleted (`product_phased_out`, `product_deleted`, `variant_phased_out`, `variant_deleted`)."},{"fix":"Check the amount and its decimal places.","status":422,"when":"A price, quantity or calculated total is out of range (`amount_out_of_range`)."},{"fix":"Ask the team owner for sales order edit permission, or assign the user to the order.","status":403,"when":"The API key's role can't edit this order (`user_is_not_authorized`)."},{"fix":"Check the id.","status":404,"when":"The order or line does not exist in this team: `error.code` is null and `error.message` says \"No query results for …\"."},{"fix":"Keep the types, or delete the line and add a new one.","status":422,"when":"You sent a different `product.type` (`cart_item_validation_error`), or a `pricing.type` that is not the one for the line's kind (`validation_failed`, `error.fields` names `pricing.type`)."}],"group":"Sales","notes":["Sending the line's current values changes nothing and answers `NONE` with `has_changes: false`, except on an order that keeps its invoice up to date automatically: there a body with `quantity`, `pricing` or `job` is recalculated and answers `UPDATED`.","Use the bulk operation to change several lines in one save."],"permission":"Needs permission to edit this sales order or quote:\n\n- The team owner\n- A role with `update_all_order`\n- A role with `update_self_order`, when the order was created by or is assigned to the API key's user\n- The person who created a draft, with `create_order`\n\nQuotes use the same sales order permissions.","related":["v2_public_order_item_show","v2_public_order_item_bulk","v2_public_order_item_destroy"],"rules":["`product.type`, when sent, must equal the line's own: 422 `cart_item_validation_error` \"Cannot update the product type. It should be the same as the existing product type. …\". `pricing.type`, when sent, must be the one for the line's kind: 422 `validation_failed` on `pricing.type`.","Every object you send needs its `type`, for example `{\"pricing\": {\"type\": \"fee\", ...}}`; otherwise 422 \"The pricing.type field is required.\"","When `pricing.product.override` changes, a `pricing.product.total` you send is taken as the new amount (up to 6 decimal places); leave `total` out and the stored amount is kept.","Lines an integration brought in only accept `job` and `position` changes.","A simple-product line from the older editor has `product.type` `db_simple`, which an update can't send: leave `product` out when you change such a line.","Moving a line to another job, or changing its quantity, is refused while that job's decoration setup needs repair."],"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.","Lowering the quantity releases stock reservations and removes the excess from the order's shipments and invoices; raising it on a published sales order reserves more."]}}},"/v2/api/store/{team_slug}/v2/sales_order/poll_pending_payment":{"post":{"description":"**Internal.** Built for YoPrint's own apps, not for integrations. Don't build on it.\n\nMeant to check a pending card payment from Charge a card (with its `poll_token`). Today every call fails with HTTP 500 (`{\"message\": \"Server Error\"}`), because the route has no place for the pending payment's id. YoPrint checks pending payments in the background anyway; read the order's payments instead.","operationId":"v2_public_sales_order_payment_gateway_polling","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"poll_token":"token-from-execute"},"schema":{"properties":{"poll_token":{"description":"The `poll_token` from Charge a card.","type":"string"}},"required":["poll_token"],"type":"object"}}},"required":true},"responses":{"200":{"description":"Never sent: this route always fails with HTTP 500."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Check a pending card payment (not usable)","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"List the order's payments instead.","status":500,"when":"Always, as described above."}],"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_sales_order_payment_index"],"status":"internal"},"x-internal":true}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/all_approvals":{"get":{"description":"Returns every approval on a sales order or quote: the order approvals and the artwork approvals of its jobs.\n\nAn order approval asks the customer to approve the whole sales order or quote. They open it from the email or the customer portal, type their name as a signature, and approve it or ask for changes. Artwork approvals for single jobs are separate (List all approvals of an order shows both).\n\nShopify orders return an empty list. An old (version 1) order answers 404 here, as an unknown order does. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_approval_all_approvals","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"approved_by":"customer","approved_by_contact_id":null,"approved_by_user":null,"completed":false,"created_at":"2026-11-03T09:00:00+00:00","customer_last_viewed_contact_id":null,"customer_last_viewed_date":null,"id":"xTKi8BqFVVmlL6","notes_to_customer":"Please review the sizes and colors.","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","status":"sent-to-customer","type":"order"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"An approval.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List all approvals of an order, jobs included","tags":["Sales order approvals"],"x-yoprint-docs":{"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_approval_index","v1_public_approvals_filter"]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/approval":{"get":{"description":"Returns the order approvals of a sales order or quote, without job artwork approvals.\n\nAn order approval asks the customer to approve the whole sales order or quote. They open it from the email or the customer portal, type their name as a signature, and approve it or ask for changes. Artwork approvals for single jobs are separate (List all approvals of an order shows both).\n\nShopify orders return an empty list. An old (version 1) order answers 404 here, as an unknown order does. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_approval_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"approved_by":"customer","approved_by_contact_id":null,"approved_by_user":null,"completed":false,"created_at":"2026-11-03T09:00:00+00:00","customer_last_viewed_contact_id":null,"customer_last_viewed_date":null,"id":"xTKi8BqFVVmlL6","notes_to_customer":"Please review the sizes and colors.","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","status":"sent-to-customer","type":"order"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"An approval.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the order approvals of an order","tags":["Sales order approvals"],"x-yoprint-docs":{"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_approval_all_approvals","v2_public_order_approval_store"]}},"post":{"description":"Creates an order approval on a published sales order or quote and, unless you say otherwise, emails it to the customer.\n\nAn order approval asks the customer to approve the whole sales order or quote. They open it from the email or the customer portal, type their name as a signature, and approve it or ask for changes. Artwork approvals for single jobs are separate (List all approvals of an order shows both).\n\nWith `send_later: true`, or when the order has no customer, the approval is created but not emailed: its `status` is `pending`. Send it later from the web app or with the `send_approval_reminder` action. An emailed approval comes back as `sent-to-customer`.\n\nEmail limit: if your team makes more than 60 of these calls in a minute, or goes over the daily email limit for its plan, YoPrint blocks email sending for your whole team until YoPrint support lifts the block. Never call this in a loop.\n\nThe answer is the new approval. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_approval_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"notes_to_customer":"Please review the sizes and colors.","send_later":false},"schema":{"properties":{"notes_to_customer":{"description":"A note shown to the customer with the approval.","type":"string"},"send_later":{"description":"true to create the approval without emailing it. Default false.","type":"boolean"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"approved_by":"customer","approved_by_contact_id":null,"approved_by_user":null,"completed":false,"created_at":"2026-11-03T09:00:00+00:00","customer_last_viewed_contact_id":null,"customer_last_viewed_date":null,"id":"xTKi8BqFVVmlL6","notes_to_customer":"Please review the sizes and colors.","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","status":"sent-to-customer","type":"order"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"An approval.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Ask the customer to approve an order","tags":["Sales order approvals"],"x-yoprint-docs":{"errors":[{"fix":"Publish first, complete or delete the pending approval, or use `send_later`.","status":422,"when":"A draft, a second pending approval, a Shopify order, or no email recipient."}],"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_approval_complete","v2_public_order_single_action","v2_public_order_approval_destroy"],"rules":["The order must be published: drafts are refused (\"No Permission - you cannot add approval to an order/quote mode: draft\").","An order can have only one pending order approval: \"An Order/Quote can only has one pending approval.\"","When emailing (an order with a customer, without `send_later`), someone on the order must have an email address (422 `approval_email_no_recipient`); otherwise send it with `send_later: true`.","Shopify orders refuse approvals."],"side_effects":["Without `send_later`, on an order with a customer: emails the approval to the customer, and both the approval's `status` and the order's `approval_status` become `sent-to-customer`.","With `send_later: true`, or on an order without a customer: nothing is emailed, the approval is `pending` and the order's `approval_status` is `requested`.","The email's link opens the approval for the contact it was sent to: when that contact answers in the customer portal, the approval's `approved_by` is `contact`, with `approved_by_contact_id`.","Customer Portal pages the order's customer has open refresh (a live update, not an email)."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/approval/{hash_id2}":{"delete":{"description":"Deletes an order approval that is not completed yet. A completed approval can't be deleted: the call fails. `{hash_id2}` is the approval's `id`. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_approval_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The approval's `id` (a hash id).","example":"xTKi8BqFVVmlL6","in":"path","name":"hash_id2","required":true,"schema":{"example":"xTKi8BqFVVmlL6","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"description":"No data.","type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete an order approval","tags":["Sales order approvals"],"x-yoprint-docs":{"errors":[{"fix":"Leave completed approvals in place.","status":500,"when":"The approval is completed (an error with no code)."},{"fix":"Shopify orders have no approvals.","status":422,"when":"A Shopify order: \"Shopify orders do not support approval workflows in YoPrint.\""},{"fix":"Use a current sales order's or quote's `id`.","status":404,"when":"The order or approval isn't found, or the order is an old (version 1) order."}],"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_approval_store"],"rules":["Only approvals that are not completed. Shopify orders refuse approval changes.","An old (version 1) order answers 404 here, as an unknown order does."],"side_effects":["Customer Portal pages the order's customer has open refresh (a live update, not an email)."]}},"get":{"description":"Returns one order approval. `{hash_id2}` is the approval's `id`. An old (version 1) order answers 404 here, as an unknown order does. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_approval_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The approval's `id` (a hash id).","example":"xTKi8BqFVVmlL6","in":"path","name":"hash_id2","required":true,"schema":{"example":"xTKi8BqFVVmlL6","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"approved_by":"customer","approved_by_contact_id":null,"approved_by_user":null,"completed":false,"created_at":"2026-11-03T09:00:00+00:00","customer_last_viewed_contact_id":null,"customer_last_viewed_date":null,"id":"xTKi8BqFVVmlL6","notes_to_customer":"Please review the sizes and colors.","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","status":"sent-to-customer","type":"order"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"An approval.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get an order approval","tags":["Sales order approvals"],"x-yoprint-docs":{"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_approval_index"]}},"put":{"description":"Changes the notes of an approval that is not completed yet. `{hash_id2}` is the approval's `id`. The answer is the approval. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_approval_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The approval's `id` (a hash id).","example":"xTKi8BqFVVmlL6","in":"path","name":"hash_id2","required":true,"schema":{"example":"xTKi8BqFVVmlL6","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"notes_to_customer":"Updated proof attached."},"schema":{"properties":{"notes_from_customer":{"description":"The customer's note.","type":"string"},"notes_to_customer":{"description":"The note shown to the customer.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"approved_by":"customer","approved_by_contact_id":null,"approved_by_user":null,"completed":false,"created_at":"2026-11-03T09:00:00+00:00","customer_last_viewed_contact_id":null,"customer_last_viewed_date":null,"id":"xTKi8BqFVVmlL6","notes_to_customer":"Updated proof attached.","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","status":"sent-to-customer","type":"order"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"An approval.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update an order approval","tags":["Sales order approvals"],"x-yoprint-docs":{"errors":[{"fix":"Create a new approval instead.","status":422,"when":"The approval is completed, or the order is a draft or a Shopify order."}],"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_approval_show"],"rules":["Only on published orders, and only while the approval is not completed: \"No Permission - you cannot edit a completed approval\"."],"side_effects":["Sends nothing to the customer. Customer Portal pages the order's customer has open refresh (a live update, not an email)."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/approval/{hash_id2}/complete":{"put":{"description":"Completes an approval on the customer's behalf: approved, or changes needed. Use it when the customer answered outside YoPrint, for example by phone.\n\n`signature` is the signer's name, as the customer would type it in the portal. Send `status: \"completed\"` to approve, or `status: \"need-changes\"` with `notes_from_customer` to ask for changes.\n\n`{hash_id2}` is the approval's `id`. The answer is the completed approval. A completed approval can't be edited or deleted. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_approval_complete","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The approval's `id` (a hash id).","example":"xTKi8BqFVVmlL6","in":"path","name":"hash_id2","required":true,"schema":{"example":"xTKi8BqFVVmlL6","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"approve":{"summary":"Approve","value":{"signature":"Alex Rivera","status":"completed"}},"changes":{"summary":"Ask for changes","value":{"notes_from_customer":"Make the logo larger.","signature":"Alex Rivera","status":"need-changes"}}},"schema":{"properties":{"notes_from_customer":{"description":"The customer's note. Required with `need-changes`.","type":"string"},"signature":{"description":"The signer's name.","type":"string"},"status":{"description":"`completed` approves; `need-changes` asks for changes. Always send it. If you leave it out, the approval is completed with no `status` (this answer shows `null`, later reads `\"\"`), the order's approval status becomes \"needs changes\" (not approved) and the notes check is skipped.","enum":["completed","need-changes"],"type":"string"}},"required":["signature"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"approved_by":"user","approved_by_contact_id":null,"approved_by_user":"PydH0WtBhSeiNU","completed":true,"completed_at":"2026-11-04T09:00:00+00:00","created_at":"2026-11-03T09:00:00+00:00","customer_last_viewed_contact_id":null,"customer_last_viewed_date":null,"id":"xTKi8BqFVVmlL6","notes_to_customer":"Please review the sizes and colors.","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","signature":"Alex Rivera","status":"completed","type":"order"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"An approval.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Record the customer's answer to an order approval","tags":["Sales order approvals"],"x-yoprint-docs":{"errors":[{"fix":"Check the approval first and send a signature.","status":422,"when":"Already completed, a draft or Shopify order, a missing signature, or `need-changes` without notes."},{"fix":"Use a current sales order's or quote's `id`.","status":404,"when":"The order or approval isn't found, or the order is an old (version 1) order."}],"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_approval_store","v2_public_order_approval_show"],"rules":["Only on published orders, and only once: a completed approval can't be completed again.","`need-changes` needs `notes_from_customer`: \"Notes are required when requesting order changes.\""],"side_effects":["Sets the order's approval status to approved or need changes, and records the API key's user as the approver (`approved_by` `user`, `approved_by_contact_id` null).","Emails the team that the approval was completed, adds it to the activity feed, and sends the `order_approval.approved` or `order_approval.change_requested` webhook.","Customer Portal pages the order's customer has open refresh (a live update, not an email)."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/assign_user":{"get":{"description":"Returns the team members in the order's Assigned To list. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_assign_user_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"avatar_url":null,"email":"alex@example.com","id":"PydH0WtBhSeiNU","name":"Alex Rivera","timezone":"America/Chicago"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the people assigned to an order","tags":["Sales order assignees"],"x-yoprint-docs":{"group":"Sales","permission":"Any member of the team.","related":["v2_public_assign_user_add","v2_public_assign_user_remove"]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/assign_user/add":{"put":{"description":"Adds a team member to the order's Assigned To list. Assigning someone already assigned changes nothing.\n\nAssigned people whose role sees only their own orders can then see and work on this one.\n\nThe answer is the full list. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_assign_user_add","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"action":"assign","user_id":"PydH0WtBhSeiNU"},"schema":{"properties":{"action":{"description":"Required. Send `assign`; the path decides what happens.","enum":["assign","unassign"],"type":"string"},"user_id":{"description":"The team member's `id`, from the team's users.","type":"string"}},"required":["action","user_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"avatar_url":null,"email":"alex@example.com","id":"PydH0WtBhSeiNU","name":"Alex Rivera","timezone":"America/Chicago"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Assign a team member to an order","tags":["Sales order assignees"],"x-yoprint-docs":{"errors":[{"fix":"Send both fields.","status":422,"when":"`action` or `user_id` is missing, or `action` is not `assign` or `unassign` (`validation_failed`)."},{"fix":"Use an id from the team's users.","status":404,"when":"The user is not a member of this team."},{"fix":"Ask the team owner for sales order edit permission.","status":403,"when":"The API key's role can't edit this order."}],"group":"Sales","permission":"Needs permission to edit this order: the team owner, a role with `update_all_order`, or `update_self_order` for orders the user created or is assigned to.","related":["v2_public_assign_user_remove","v1_public_user_index"],"rules":["`user_id` must be a member of the team; otherwise 404."],"side_effects":["Gives the member access to the order if their role sees only their own orders. No notification is sent."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/assign_user/remove":{"put":{"description":"Removes a team member from the order's Assigned To list. The answer is the remaining list. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_assign_user_remove","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"action":"unassign","user_id":"PydH0WtBhSeiNU"},"schema":{"properties":{"action":{"description":"Required. Send `unassign`; the path decides what happens.","enum":["assign","unassign"],"type":"string"},"user_id":{"description":"The team member's `id`, from the team's users.","type":"string"}},"required":["action","user_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove a team member from an order","tags":["Sales order assignees"],"x-yoprint-docs":{"errors":[{"fix":"Send both fields.","status":422,"when":"`action` or `user_id` is missing, or `action` is not `assign` or `unassign` (`validation_failed`)."},{"fix":"Use an id from the team's users.","status":404,"when":"The user is not a member of this team."},{"fix":"Ask the team owner for sales order edit permission.","status":403,"when":"The API key's role can't edit this order."}],"group":"Sales","permission":"Needs permission to edit this order: the team owner, a role with `update_all_order`, or `update_self_order` for orders the user created or is assigned to.","related":["v2_public_assign_user_add"],"side_effects":["A member whose role sees only their own orders loses access to this order, unless they created it."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/comment":{"post":{"description":"Comments are internal notes for your team on a published sales order or quote. The customer never sees them.\n\nAdds a comment as the API key's user. The answer is the comment. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_comment_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"comment":"Customer approved the proof by phone."},"schema":{"properties":{"comment":{"description":"The comment text.","minLength":1,"type":"string"}},"required":["comment"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"comment":"Customer approved the proof by phone.","id":"fFupqL9CYkMYgE","is_edited":false,"order_id":"V4keXwwxMQyXw7","trashed":false,"type":"user_comment","user_id":"PydH0WtBhSeiNU"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A comment.","properties":{"comment":{"example":"Customer approved the proof by phone.","type":"string"},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"fFupqL9CYkMYgE","type":"string"},"is_edited":{"type":"boolean"},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"trashed":{"type":"boolean"},"type":{"description":"`user_comment` for comments people write.","example":"user_comment","type":"string"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"user_id":{"description":"The author.","example":"PydH0WtBhSeiNU","type":["string","null"]}},"required":["id","comment"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add a comment to an order","tags":["Sales order comments"],"x-yoprint-docs":{"errors":[{"fix":"Send the comment text.","status":422,"when":"`comment` is missing or empty (`validation_failed`, with `error.fields.comment`)."},{"fix":"Publish the order first.","status":422,"when":"The order is not published (`validation_error`, \"No Permission - in mode: draft\")."}],"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_comment_index","v2_public_order_message_store"],"rules":["`comment` is required and must be a non-empty string.","Only on published orders: drafts are refused (\"No Permission - in mode: draft\")."],"side_effects":["Notifies the team members who follow the order's comments, in the app and by email. The customer is not told."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/comment/index":{"get":{"description":"Comments are internal notes for your team on a published sales order or quote. The customer never sees them.\n\nReturns the order's comments, without deleted ones. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_comment_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"comment":"Customer approved the proof by phone.","id":"fFupqL9CYkMYgE","is_edited":false,"order_id":"V4keXwwxMQyXw7","trashed":false,"type":"user_comment","user_id":"PydH0WtBhSeiNU"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A comment.","properties":{"comment":{"example":"Customer approved the proof by phone.","type":"string"},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"fFupqL9CYkMYgE","type":"string"},"is_edited":{"type":"boolean"},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"trashed":{"type":"boolean"},"type":{"description":"`user_comment` for comments people write.","example":"user_comment","type":"string"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"user_id":{"description":"The author.","example":"PydH0WtBhSeiNU","type":["string","null"]}},"required":["id","comment"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the comments of an order","tags":["Sales order comments"],"x-yoprint-docs":{"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_comment_store"]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/comment/{hash_id2}":{"delete":{"description":"Deletes a comment. You can bring it back with Restore. `{hash_id2}` is the comment's `id`. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_comment_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The comment's `id` (a hash id).","example":"fFupqL9CYkMYgE","in":"path","name":"hash_id2","required":true,"schema":{"example":"fFupqL9CYkMYgE","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"description":"No data.","type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a comment","tags":["Sales order comments"],"x-yoprint-docs":{"errors":[{"fix":"Comments exist only on published orders.","status":422,"when":"The order is not published."}],"group":"Sales","permission":"Any member of the team. Any member can delete any comment, not only their own.","related":["v2_public_order_comment_restore"],"rules":["Only on published orders."]}},"get":{"description":"Returns one comment. `{hash_id2}` is the comment's `id`. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_comment_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The comment's `id` (a hash id).","example":"fFupqL9CYkMYgE","in":"path","name":"hash_id2","required":true,"schema":{"example":"fFupqL9CYkMYgE","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"comment":"Customer approved the proof by phone.","id":"fFupqL9CYkMYgE","is_edited":false,"order_id":"V4keXwwxMQyXw7","trashed":false,"type":"user_comment","user_id":"PydH0WtBhSeiNU"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A comment.","properties":{"comment":{"example":"Customer approved the proof by phone.","type":"string"},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"fFupqL9CYkMYgE","type":"string"},"is_edited":{"type":"boolean"},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"trashed":{"type":"boolean"},"type":{"description":"`user_comment` for comments people write.","example":"user_comment","type":"string"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"user_id":{"description":"The author.","example":"PydH0WtBhSeiNU","type":["string","null"]}},"required":["id","comment"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a comment","tags":["Sales order comments"],"x-yoprint-docs":{"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_comment_index"]}},"put":{"description":"Meant to change a comment's text. Today it is refused for every order: a published order fails with \"Permission Denied - The Resource is already created\" and any other order with \"No Permission - in mode: ...\". Delete the comment and add a new one instead.\n\n`{hash_id2}` is the comment's `id`. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_comment_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The comment's `id` (a hash id).","example":"fFupqL9CYkMYgE","in":"path","name":"hash_id2","required":true,"schema":{"example":"fFupqL9CYkMYgE","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"comment":"Proof approved by phone on Monday."},"schema":{"properties":{"comment":{"description":"The new text.","type":"string"}},"required":["comment"],"type":"object"}}},"required":true},"responses":{"200":{"description":"Never sent today: every call is refused with 422."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Edit a comment","tags":["Sales order comments"],"x-yoprint-docs":{"errors":[{"fix":"Delete the comment and add a new one.","status":422,"when":"Always, as described above."}],"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_comment_destroy","v2_public_order_comment_store"]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/comment/{hash_id2}/restore":{"patch":{"description":"Brings back a deleted comment. `{hash_id2}` is the comment's `id`. The answer has no data. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_comment_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The comment's `id` (a hash id).","example":"fFupqL9CYkMYgE","in":"path","name":"hash_id2","required":true,"schema":{"example":"fFupqL9CYkMYgE","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"description":"No data.","type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a deleted comment","tags":["Sales order comments"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Comments exist only on published orders.","status":422,"when":"The order is not published."}],"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_comment_destroy"],"rules":["Only on published orders."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/credit/pay_with_customer_credit":{"post":{"description":"Uses the customer's credit balance to pay part of the order. Send a whole number of thousandths: `12500` is 12.50. See [Money and quantities](/concepts/money-and-quantities/). The answer is the order's new credit entry: `subtype` `TRANSFER`, `action` `ORDER_CREDIT_DEPOSIT`, `direction` `INCREASE`, a positive `amount` and no payment method. It can't be edited, deleted or refunded (`refundable_amount` 0). When the credit came from a Customer Portal payment, the entry also names that payment (`customer_payment_funding_id`, `customer_payment_sources`). `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_credit_pay_with_customer_credit","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"amount":50000},"schema":{"properties":{"amount":{"description":"How much credit to apply. Send a whole number of thousandths of the currency: `12500` is 12.50. Must not be 0. A number with decimals is refused with 422 `validation_failed`: `error.fields.amount` says \"The amount must be a whole number of thousandths of the currency unit, such as 12500 for 12.50.\".","type":"integer"},"reference_description":{"description":"A note for the record.","type":"string"}},"required":["amount"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"action":"ORDER_CREDIT_DEPOSIT","amount":50000,"credit_source":null,"customer_id":null,"date":"2026-11-03T09:00:00+00:00","direction":"INCREASE","id":"pA5Q6dGVTMUTxP","is_deletable":false,"is_editable":false,"order_id":"V4keXwwxMQyXw7","payment_gateway":null,"payment_method_id":null,"reference_description":"Applied payment From Customer Credit","reference_id":null,"refundable_amount":0,"related_transaction":null,"subtype":"TRANSFER","token":null,"type":"MANUAL","user_id":"PydH0WtBhSeiNU","voided":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A payment, refund or credit move. Customer Portal rows (`action` `CUSTOMER_CHECKOUT`, and credit applied from a Customer Portal payment) also carry `customer_payment_checkout_id`, `funding_transaction_id`, `customer_payment_application_id`, `customer_payment_source_kind`, `is_external_cash_movement` and `currency_iso`.","properties":{"action":{"description":"`ORDER_PAYMENT`, `ORDER_REFUND`, `ORDER_CREDIT_DEPOSIT` (paid from customer credit), `ORDER_CREDIT_WITHDRAW` (moved to customer credit), `ORDER_CREDIT_RECOVERY`, `ORDER_CREDIT_RESTORED`, `CUSTOMER_CHECKOUT` (paid in the customer portal, and its refunds), `CUSTOMER_CHECKOUT_CHARGEBACK` (a lost dispute), or the gateway: `STRIPE`, `SQUARE`, `SQUARE_V2`, `PAYPAL`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`. A `REFUND_REVERSAL` carries its refund's gateway.","example":"ORDER_PAYMENT","type":["string","null"]},"amount":{"description":"Signed: negative for `DECREASE` (a 25.00 refund is `-25000`). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"credit_source":{"additionalProperties":true,"description":"Where a customer credit record came from. Always present; null on an order's records.","type":["object","null"]},"credit_source_payment_id":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: the payment the credit was issued from.","type":["string","null"]},"customer_id":{"description":"Always null on an order's records.","type":["string","null"]},"customer_payment_funding_id":{"description":"Customer Portal payment rows and credit applied from one only: the customer payment it belongs to.","type":["string","null"]},"customer_payment_sources":{"description":"Customer Portal rows only: the customer payments the money came from, each with `customer_payment_funding_id`, `funding_transaction_id`, `amount` (a decimal string) and `currency_iso`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"date":{"description":"When it was recorded (the payment date you sent). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"delete_blocked_reason":{"description":"Recorded payments (`ORDER_PAYMENT`) and card payments only: why Delete a payment or refund refuses it, or null when it can be deleted. `code` is `credit_issued_from_payment` (with `amount`, a decimal string) or `provider_payment_not_removable`; `message` is the refusal's text.","properties":{"amount":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}},"type":["object","null"]},"direction":{"description":"`INCREASE` (payments, payments from customer credit, `REFUND_REVERSAL`, `ORDER_CREDIT_RECOVERY`) or `DECREASE` (refunds and lost disputes, moves to customer credit, card voids, `ORDER_CREDIT_RESTORED`).","example":"INCREASE","type":"string"},"funding_payment_gateway":{"description":"Customer Portal rows only: the provider (`STRIPE`, `PAYPAL`, `SQUARE_V2`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`) or null.","type":["string","null"]},"has_open_hold":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and Customer Portal payments: true while a dispute (or, for a Customer Portal payment, a review) is open.","type":"boolean"},"id":{"example":"hAwWd7vPrqjuHD","type":"string"},"is_deletable":{"description":"false for card payments, Customer Portal payments, credit moves, card refunds, payments part of which moved to customer credit (and their refunds), refunds recorded against card payments, and the records YoPrint adds itself.","type":"boolean"},"is_editable":{"description":"true only for recorded payments (`ORDER_PAYMENT`).","type":"boolean"},"negative_credit_amount":{"description":"Card refunds only: credit issued from the payment that the customer had already spent and the refund took back anyway, leaving their credit negative (usually 0). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"payment_freeze_reason":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and direct Customer Portal payments: `chargeback_open` or `payment_under_review` while refunds and credit moves are refused, otherwise null.","type":["string","null"]},"payment_gateway":{"description":"The gateway (`STRIPE`, `SQUARE_V2` and so on) for card payments and refunds; for a Customer Portal payment its provider (null when unknown), and `CUSTOMER_CHECKOUT` or `CUSTOMER_CHECKOUT_CHARGEBACK` on its refunds and lost disputes; null otherwise.","type":["string","null"]},"payment_gateway_source":{"description":"Card payments and refunds only: Square v2's source type (for example `CARD`), otherwise null.","type":["string","null"]},"payment_method_id":{"description":"Refunds take their payment's; null for card payments and credit moves.","type":["string","null"]},"payment_notices":{"description":"List and Get only, on the same payments as `has_open_hold`: one notice per open dispute.","items":{"additionalProperties":true,"properties":{"amount":{"description":"The disputed amount as a decimal pair with `dp` 3, or null when the payment covered several orders.","type":["object","null"]},"code":{"description":"`dispute_open` or `dispute_under_review`; on Customer Portal payments also `payment_needs_attention`.","type":"string"},"currency_iso":{"type":"string"},"customer_payment_dispute_id":{"type":"string"},"customer_payment_funding_id":{"type":["string","null"]},"deadline_at":{"description":"When the response to the provider is due (ISO 8601), or null.","type":["string","null"]},"next_action":{"description":"For example `respond_to_provider` or `awaiting_provider`.","type":"string"},"provider":{"type":"string"},"provider_status":{"type":"string"},"stage":{"type":["string","null"]}},"type":"object"},"type":"array"},"recovery_kind":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: null on an order's records.","type":["string","null"]},"reference_description":{"type":["string","null"]},"reference_id":{"example":"CHK-1001","type":["string","null"]},"refundable_amount":{"description":"Payments only: the amount minus its refunds. Money moved to customer credit is not taken off here, though a refund can't include it. 0 for refunds, credit moves, payments from customer credit, and `CHARGE_IT_PRO` and `SQUARE` card payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"related_transaction":{"description":"For a refund, the `id` of the payment it refunds; for `REFUND_REVERSAL`, the payment; for `ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED`, the refund; null otherwise.","type":["string","null"]},"remove_unavailable":{"description":"Recorded payments only: `{ \"reason\": \"credit_issued\", \"amount\": <thousandths> }` when credit was issued from the payment, otherwise null.","type":["object","null"]},"restores_transaction_id":{"description":"`ORDER_CREDIT_RESTORED` only: the `ORDER_CREDIT_RECOVERY` record it gives back.","type":["string","null"]},"reversal_transaction_id":{"description":"Card refunds and `ORDER_CREDIT_RESTORED` only: the `REFUND_REVERSAL` record when the refund failed, or null.","type":["string","null"]},"reverses_transaction_id":{"description":"`REFUND_REVERSAL` only: the failed refund.","type":["string","null"]},"subtype":{"description":"`PAYMENT`, `REFUND` (also a lost dispute), `TRANSFER` (a customer credit move), `ORDER_PAYMENT_VOIDED_NEG_ADJ` (a voided card payment), `REFUND_REVERSAL` (a failed card refund given back to its payment), `ORDER_CREDIT_RECOVERY` (credit a refund took back) or `ORDER_CREDIT_RESTORED` (that credit given back when the refund failed).","example":"PAYMENT","type":"string"},"token":{"description":"The gateway's charge token; null for recorded payments.","type":["string","null"]},"type":{"description":"`MANUAL` (recorded in YoPrint) or `SYSTEM` (card and Customer Portal payments and refunds, Shopify payments, adjustments).","example":"MANUAL","type":"string"},"user_id":{"description":"The team member who recorded it.","type":["string","null"]},"voided":{"type":"boolean"}},"required":["id","amount"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/PaymentMutationUnprocessableEntityResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Pay an order from the customer's credit","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Check the customer's credit first.","status":422,"when":"Zero, more than the available credit, an `amount` with decimals (`validation_failed`), or a draft order."},{"fix":"Wait for the provider's decision, then try again.","status":422,"when":"A payment is frozen by an open dispute or review (`customer_payment_disputed_funds_unavailable` or `invoice_payment_funding_withheld`, with `error.reason`)."},{"fix":"Ask the team owner for View Sales Order Pricing and permission to edit this order, or to be assigned to it.","status":403,"when":"Your role can't see this order's finances or change it. This 403 has a short body, `{\"message\": \"No permission to change this order payment.\"}`, with no `success` or `error`."}],"group":"Invoices and payments","permission":"Needs permission to see this order's finances and to change it: the team owner; or a role with `view_order_finance` (View Sales Order Pricing) and `view_all_order` (or `view_self_order`, for orders the user created or is assigned to), and `update_all_order` (or `update_self_order`, for orders the user created or is assigned to). Otherwise 403 with a short body, `{\"message\": \"No permission to change this order payment.\"}`. The order must be published.","related":["v2_public_sales_order_credit_refund_to_customer_credit"],"rules":["The amount can't be 0 (\"Amount To refund cannot be Zero\") or more than the customer's available credit (\"Amount To refund is greater than the order payment total\"): the messages reuse refund wording. Its sign is ignored.","Available credit leaves out credit held by a frozen payment (an open dispute or review). When only that held credit would cover the amount, the refusal is the freeze 422 (`customer_payment_disputed_funds_unavailable` or `invoice_payment_funding_withheld`, with `error.reason`, `error.provider` and `error.provider_label`).","Only published orders: otherwise 422 \"Action Not Allow\"."],"side_effects":["Lowers the customer's credit and records the credit entry on the order.","Sends the `payment_received.any_amount` webhook; also `payment_received.deposit_amount` when the order's paid total now exactly equals its deposit amount, and `payment_received.full_amount` when the balance due (invoiced total minus paid) is now exactly 0. A payment that goes past the deposit, or overpays, sends neither of those two."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/credit/refund_all_to_customer_credit":{"patch":{"description":"Moves everything paid on the order to the customer's credit. Deleting a published order does the same. The answer has no data. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_credit_refund_all_to_customer_credit","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"description":"No data.","type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/PaymentMutationUnprocessableEntityResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Move all of an order's payments to customer credit","tags":["Payments"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Check the order's payments first.","status":422,"when":"Nothing paid, or a draft order (\"Action Not Allow\")."},{"fix":"Wait for the provider's decision, then try again.","status":422,"when":"A payment is frozen by an open dispute or review (`customer_payment_disputed_funds_unavailable` or `invoice_payment_funding_withheld`, with `error.reason`)."},{"fix":"Ask the team owner for View Sales Order Pricing and permission to edit this order, or to be assigned to it.","status":403,"when":"Your role can't see this order's finances or change it. This 403 has a short body, `{\"message\": \"No permission to change this order payment.\"}`, with no `success` or `error`."}],"group":"Invoices and payments","permission":"Needs permission to see this order's finances and to change it: the team owner; or a role with `view_order_finance` (View Sales Order Pricing) and `view_all_order` (or `view_self_order`, for orders the user created or is assigned to), and `update_all_order` (or `update_self_order`, for orders the user created or is assigned to). Otherwise 403 with a short body, `{\"message\": \"No permission to change this order payment.\"}`. The order must be published.","related":["v2_public_sales_order_credit_refund_to_customer_credit"],"rules":["The order must have money paid on it: otherwise 422 \"Insufficient Order Balance\".","Nothing moves while any payment holding money on the order is frozen by an open dispute or review: the freeze 422 (`customer_payment_disputed_funds_unavailable` or `invoice_payment_funding_withheld`, with `error.reason`)."],"side_effects":["Money from a Customer Portal payment goes back to that payment's credit. Deletes all the order's payment links (allocations), then raises the customer's credit by what the payments still hold (after refunds and earlier moves) and sets the order's paid amount to 0; updates invoices and customer totals."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/credit/refund_to_customer_credit":{"post":{"description":"Takes some of what the customer paid on this order and keeps it as their credit, to use on another order. Send a whole number of thousandths: `12500` is 12.50. See [Money and quantities](/concepts/money-and-quantities/). The answer is the order's new credit entry: `subtype` `TRANSFER`, `action` `ORDER_CREDIT_WITHDRAW`, `direction` `DECREASE` and a **negative** `amount` (25.00 is `-25000`). `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_credit_refund_to_customer_credit","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"amount":25000,"reference_description":"Overpayment"},"schema":{"properties":{"amount":{"description":"How much to move. Send a whole number of thousandths of the currency: `12500` is 12.50. Must not be 0. A number with decimals is refused with 422 `validation_failed`: `error.fields.amount` says \"The amount must be a whole number of thousandths of the currency unit, such as 12500 for 12.50.\".","type":"integer"},"reference_description":{"description":"A note for the record.","type":"string"}},"required":["amount"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"action":"ORDER_CREDIT_WITHDRAW","amount":-25000,"credit_source":null,"customer_id":null,"date":"2026-11-03T09:00:00+00:00","direction":"DECREASE","id":"t0flTyfijq67bD","is_deletable":false,"is_editable":false,"order_id":"V4keXwwxMQyXw7","payment_gateway":null,"payment_method_id":null,"reference_description":"Overpayment","reference_id":null,"refundable_amount":0,"related_transaction":null,"subtype":"TRANSFER","token":null,"type":"MANUAL","user_id":"PydH0WtBhSeiNU","voided":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A payment, refund or credit move. Customer Portal rows (`action` `CUSTOMER_CHECKOUT`, and credit applied from a Customer Portal payment) also carry `customer_payment_checkout_id`, `funding_transaction_id`, `customer_payment_application_id`, `customer_payment_source_kind`, `is_external_cash_movement` and `currency_iso`.","properties":{"action":{"description":"`ORDER_PAYMENT`, `ORDER_REFUND`, `ORDER_CREDIT_DEPOSIT` (paid from customer credit), `ORDER_CREDIT_WITHDRAW` (moved to customer credit), `ORDER_CREDIT_RECOVERY`, `ORDER_CREDIT_RESTORED`, `CUSTOMER_CHECKOUT` (paid in the customer portal, and its refunds), `CUSTOMER_CHECKOUT_CHARGEBACK` (a lost dispute), or the gateway: `STRIPE`, `SQUARE`, `SQUARE_V2`, `PAYPAL`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`. A `REFUND_REVERSAL` carries its refund's gateway.","example":"ORDER_PAYMENT","type":["string","null"]},"amount":{"description":"Signed: negative for `DECREASE` (a 25.00 refund is `-25000`). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"credit_source":{"additionalProperties":true,"description":"Where a customer credit record came from. Always present; null on an order's records.","type":["object","null"]},"credit_source_payment_id":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: the payment the credit was issued from.","type":["string","null"]},"customer_id":{"description":"Always null on an order's records.","type":["string","null"]},"customer_payment_funding_id":{"description":"Customer Portal payment rows and credit applied from one only: the customer payment it belongs to.","type":["string","null"]},"customer_payment_sources":{"description":"Customer Portal rows only: the customer payments the money came from, each with `customer_payment_funding_id`, `funding_transaction_id`, `amount` (a decimal string) and `currency_iso`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"date":{"description":"When it was recorded (the payment date you sent). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"delete_blocked_reason":{"description":"Recorded payments (`ORDER_PAYMENT`) and card payments only: why Delete a payment or refund refuses it, or null when it can be deleted. `code` is `credit_issued_from_payment` (with `amount`, a decimal string) or `provider_payment_not_removable`; `message` is the refusal's text.","properties":{"amount":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}},"type":["object","null"]},"direction":{"description":"`INCREASE` (payments, payments from customer credit, `REFUND_REVERSAL`, `ORDER_CREDIT_RECOVERY`) or `DECREASE` (refunds and lost disputes, moves to customer credit, card voids, `ORDER_CREDIT_RESTORED`).","example":"INCREASE","type":"string"},"funding_payment_gateway":{"description":"Customer Portal rows only: the provider (`STRIPE`, `PAYPAL`, `SQUARE_V2`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`) or null.","type":["string","null"]},"has_open_hold":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and Customer Portal payments: true while a dispute (or, for a Customer Portal payment, a review) is open.","type":"boolean"},"id":{"example":"hAwWd7vPrqjuHD","type":"string"},"is_deletable":{"description":"false for card payments, Customer Portal payments, credit moves, card refunds, payments part of which moved to customer credit (and their refunds), refunds recorded against card payments, and the records YoPrint adds itself.","type":"boolean"},"is_editable":{"description":"true only for recorded payments (`ORDER_PAYMENT`).","type":"boolean"},"negative_credit_amount":{"description":"Card refunds only: credit issued from the payment that the customer had already spent and the refund took back anyway, leaving their credit negative (usually 0). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"payment_freeze_reason":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and direct Customer Portal payments: `chargeback_open` or `payment_under_review` while refunds and credit moves are refused, otherwise null.","type":["string","null"]},"payment_gateway":{"description":"The gateway (`STRIPE`, `SQUARE_V2` and so on) for card payments and refunds; for a Customer Portal payment its provider (null when unknown), and `CUSTOMER_CHECKOUT` or `CUSTOMER_CHECKOUT_CHARGEBACK` on its refunds and lost disputes; null otherwise.","type":["string","null"]},"payment_gateway_source":{"description":"Card payments and refunds only: Square v2's source type (for example `CARD`), otherwise null.","type":["string","null"]},"payment_method_id":{"description":"Refunds take their payment's; null for card payments and credit moves.","type":["string","null"]},"payment_notices":{"description":"List and Get only, on the same payments as `has_open_hold`: one notice per open dispute.","items":{"additionalProperties":true,"properties":{"amount":{"description":"The disputed amount as a decimal pair with `dp` 3, or null when the payment covered several orders.","type":["object","null"]},"code":{"description":"`dispute_open` or `dispute_under_review`; on Customer Portal payments also `payment_needs_attention`.","type":"string"},"currency_iso":{"type":"string"},"customer_payment_dispute_id":{"type":"string"},"customer_payment_funding_id":{"type":["string","null"]},"deadline_at":{"description":"When the response to the provider is due (ISO 8601), or null.","type":["string","null"]},"next_action":{"description":"For example `respond_to_provider` or `awaiting_provider`.","type":"string"},"provider":{"type":"string"},"provider_status":{"type":"string"},"stage":{"type":["string","null"]}},"type":"object"},"type":"array"},"recovery_kind":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: null on an order's records.","type":["string","null"]},"reference_description":{"type":["string","null"]},"reference_id":{"example":"CHK-1001","type":["string","null"]},"refundable_amount":{"description":"Payments only: the amount minus its refunds. Money moved to customer credit is not taken off here, though a refund can't include it. 0 for refunds, credit moves, payments from customer credit, and `CHARGE_IT_PRO` and `SQUARE` card payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"related_transaction":{"description":"For a refund, the `id` of the payment it refunds; for `REFUND_REVERSAL`, the payment; for `ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED`, the refund; null otherwise.","type":["string","null"]},"remove_unavailable":{"description":"Recorded payments only: `{ \"reason\": \"credit_issued\", \"amount\": <thousandths> }` when credit was issued from the payment, otherwise null.","type":["object","null"]},"restores_transaction_id":{"description":"`ORDER_CREDIT_RESTORED` only: the `ORDER_CREDIT_RECOVERY` record it gives back.","type":["string","null"]},"reversal_transaction_id":{"description":"Card refunds and `ORDER_CREDIT_RESTORED` only: the `REFUND_REVERSAL` record when the refund failed, or null.","type":["string","null"]},"reverses_transaction_id":{"description":"`REFUND_REVERSAL` only: the failed refund.","type":["string","null"]},"subtype":{"description":"`PAYMENT`, `REFUND` (also a lost dispute), `TRANSFER` (a customer credit move), `ORDER_PAYMENT_VOIDED_NEG_ADJ` (a voided card payment), `REFUND_REVERSAL` (a failed card refund given back to its payment), `ORDER_CREDIT_RECOVERY` (credit a refund took back) or `ORDER_CREDIT_RESTORED` (that credit given back when the refund failed).","example":"PAYMENT","type":"string"},"token":{"description":"The gateway's charge token; null for recorded payments.","type":["string","null"]},"type":{"description":"`MANUAL` (recorded in YoPrint) or `SYSTEM` (card and Customer Portal payments and refunds, Shopify payments, adjustments).","example":"MANUAL","type":"string"},"user_id":{"description":"The team member who recorded it.","type":["string","null"]},"voided":{"type":"boolean"}},"required":["id","amount"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/PaymentMutationUnprocessableEntityResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Move part of an order's payments to customer credit","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Check the order's payments first.","status":422,"when":"Nothing paid, zero, an `amount` with decimals (`validation_failed`), too much (`issue_credit_amount_above_available` when a frozen payment holds the rest), or a draft order."},{"fix":"Wait for the provider's decision, then try again.","status":422,"when":"A payment is frozen by an open dispute or review (`customer_payment_disputed_funds_unavailable` or `invoice_payment_funding_withheld`, with `error.reason`)."},{"fix":"Ask the team owner for View Sales Order Pricing and permission to edit this order, or to be assigned to it.","status":403,"when":"Your role can't see this order's finances or change it. This 403 has a short body, `{\"message\": \"No permission to change this order payment.\"}`, with no `success` or `error`."}],"group":"Invoices and payments","permission":"Needs permission to see this order's finances and to change it: the team owner; or a role with `view_order_finance` (View Sales Order Pricing) and `view_all_order` (or `view_self_order`, for orders the user created or is assigned to), and `update_all_order` (or `update_self_order`, for orders the user created or is assigned to). Otherwise 403 with a short body, `{\"message\": \"No permission to change this order payment.\"}`. The order must be published.","related":["v2_public_sales_order_credit_refund_all_to_customer_credit","v2_public_sales_order_credit_pay_with_customer_credit"],"rules":["The order must have money paid on it: otherwise 422 \"Insufficient Order Balance\".","Only money not allocated to an invoice can move. Payments are allocated when they are recorded, so delete those payment links first, or use Move all of an order's payments to customer credit. Otherwise 422 \"Amount To refund is greater than the order payment total\"; 0 gives \"Amount To refund cannot be Zero\". The sign is ignored.","Money of a frozen payment (an open dispute or review) never moves. With nothing else left, the freeze 422 refuses it; when the amount is more than the rest, 422 `issue_credit_amount_above_available` (\"Amount To refund is greater than the money available on this order. Part of it is held by an open dispute.\"), with `error.available_amount` in thousandths.","Money the order holds from a Customer Portal payment is moved first, as credit tied to that payment, then the rest. If too little ordinary money is left, the call is refused with 422 `validation_error` and the message \"CUSTOMER_PAYMENT_SOURCE_FUNDS_UNAVAILABLE\".","Only published orders: otherwise 422 \"Action Not Allow\"."],"side_effects":["Raises the customer's credit and lowers the order's paid amount; updates invoices and customer totals."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/job":{"get":{"description":"Returns the jobs of a sales order or quote, in the order's job order (`position`, as Rearrange sets it): their production status, dates, decoration services, work pipelines and mockups. A job groups the lines produced together, and its decoration services set their decoration price.\n\nEach job file carries its latest approval in `current_approval`; add `?omit_media_approval_items=1` to leave out that approval's `items` when you don't need them.\n\n`{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_job_index_for_order","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"Send `1` (or `true`, `on`, `yes`) to leave `items` out of each job file's `current_approval`, which makes the answer much smaller for jobs with many files on one approval. Every other key stays, in the same order, and the job's `pending_approval` keeps its items. Leave it out and the answer is unchanged. Only the query string counts: a body field of this name is ignored.","example":"1","in":"query","name":"omit_media_approval_items","required":false,"schema":{"enum":["1","true","on","yes"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"assigned_users":[],"id":"K6iF8n29iwOZnj","is_rush":false,"mockup":[],"name":"Front logo","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","pipelines":[],"pricing_total":{"dp":6,"value":0},"production_file":[],"scoped_id":"JOB-1001","services":[],"status":{"color":"#9e9e9e","customer_label":"Pending","id":"YOqAGjroQEo2ZK","label":"Artwork","position":1,"role":"job","trashed":false,"type":"start"},"status_id":"YOqAGjroQEo2ZK"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A job.","properties":{"assigned_users":{"items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"K6iF8n29iwOZnj","type":"string"},"impression_count":{"description":"Item count times decoration locations.","type":["string","number","integer","null"]},"inventory_status":{"type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Total quantity of the job's lines (a decimal string or number).","type":["string","number","integer","null"]},"mockup":{"description":"Mockups.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"name":{"example":"Front logo","type":["string","null"]},"note":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pending_approval":{"additionalProperties":true,"description":"The job's open approval (the first one not yet answered), or null. It always keeps its `items`, with or without `omit_media_approval_items`.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"pipelines":{"description":"Work pipelines (production steps).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"position":{"type":["integer","null"]},"pricing_original_total":{"description":"The same before pricing rules. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null when no rule did. List the jobs of a sales order or quote, Get one job and Rearrange the jobs answer with the full summary below. Other answers carry only `type`, the two ids and the two totals.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"2.00","type":"string"},"after_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2000000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","example":"2.50","type":"string"},"base_type":{"description":"Full summary only: always `service_price` on a job.","enum":["service_price"],"type":"string"},"normal_price":{"description":"Full summary only: the price with no rule; on a job the same as `base`.","example":"2.50","type":["string","null"]},"original_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`service` on a job.","example":"service","type":"string"}},"type":["object","null"]},"pricing_total":{"description":"Decoration price per unit that the job adds to each of its lines. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"is_rush":{"type":"boolean"},"name":{"type":["string","null"]},"object_type":{"type":"string"},"status_id":{"type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number people see, such as `JOB-1001`.","example":"JOB-1001","type":"string"},"services":{"description":"Decoration services: `service_id`, `location_*`, `option`, `position`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"services_still_valid":{"description":"false when the job's decoration services need repair.","type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status, as the status operations return it.","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_id":{"description":"The job's production status.","example":"YOqAGjroQEo2ZK","type":"string"},"unique_key":{"example":"job_EXAMPLEuniqueKey","type":["string","null"]}},"required":["id","order_id","scoped_id","status_id"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the jobs of a sales order or quote","tags":["Jobs"],"x-yoprint-docs":{"group":"Production","permission":"Any member of the team.","related":["v2_public_job_store","v2_public_job_show","v2_public_order_item_store"]}},"post":{"description":"Adds a job to a sales order or quote. Add the job first, then add line items linked to it (`job: {\"type\": \"linked\", \"id\": ...}`): every line on the job takes its decoration price.\n\nA job can carry, all optional:\n\n- `service`: decoration services from Settings, each at a print location with one of the service's price options (services are not listed on the public API: copy `service_id` and `option` from an existing job or job preset);\n- `pipeline`: work pipelines (production steps), each with a starting status;\n- `mockup` and `production_file`: files you uploaded first, shown on the job.\n\nEach `service`, `pipeline` and `mockup` entry needs `action: \"create\"`, or it is skipped silently; a `production_file` entry without `action` is refused with 422. To tie a mockup to a service, give the service a temporary `id` of your own (for example `tmpid-1`) and use it in the mockup's `job_service`.\n\nThe job gets the team's next job number and the order's production dates. The answer is the job.\n\nWorks on drafts and published orders. In any other state the call answers **HTTP 200** with `{\"status\": 500, \"success\": false, \"error\": {\"code\": \"action_not_allowed\", \"message\": null}}` and changes nothing: check `success`, not only the HTTP status. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_job_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"decorated":{"summary":"A job with a decoration service (put in your own service id and option name, copied from an existing job)","value":{"name":"Front logo","service":[{"action":"create","id":"tmpid-1","location":{"name":"Front","type":"custom"},"option":"2 Color","position":1,"service_id":"15tmts0ZixfHL7"}]}},"simple":{"summary":"A job with a name only","value":{"name":"Team shirts"}}},"schema":{"properties":{"draft_session_id":{"description":"Used by the web app's mockup designer. Leave it out.","type":"string"},"draft_session_mockup":{"description":"Used by the web app's mockup designer. Leave it out.","items":{"type":"object"},"type":"array"},"has_service":{"description":"Ignored; kept for older clients.","type":"boolean"},"is_rush":{"type":"boolean"},"mockup":{"description":"Mockup images, uploaded first.","items":{"properties":{"action":{"description":"Send `create` on every entry: a service, pipeline or mockup without it is skipped silently; a production file without it is refused.","enum":["create"],"type":"string"},"id":{"description":"The upload's `id`.","type":"string"},"job_service":{"description":"The temporary service `id` (or ids) this mockup belongs to."},"name":{"type":"string"},"position":{"type":"integer"},"show_in_pdf":{"description":"Show it on the order PDF.","type":"boolean"}},"required":["action","id","show_in_pdf","position"],"type":"object"},"type":"array"},"name":{"description":"The job's name, for example \"Front logo\".","type":["string","null"]},"note":{"description":"An internal note.","type":"string"},"pipeline":{"description":"Work pipelines (production steps).","items":{"properties":{"action":{"description":"Send `create` on every entry: a service, pipeline or mockup without it is skipped silently; a production file without it is refused.","enum":["create"],"type":"string"},"assigned_users":{"description":"A user id, or a list of user ids, to assign."},"due_date":{"description":"Due date (ISO 8601 date or date-time), or null. Send together with `start_date`.","format":"date-time","type":["string","null"]},"name":{"type":"string"},"pipeline_id":{"description":"A work pipeline id from Settings.","type":"string"},"position":{"type":"integer"},"start_date":{"description":"Start date (ISO 8601 date or date-time), or null. Send together with `due_date`.","format":"date-time","type":["string","null"]},"status_id":{"description":"The pipeline's starting status id.","type":"string"}},"required":["action","pipeline_id","status_id"],"type":"object"},"type":"array"},"position":{"description":"Where the job sits among the order's jobs. Leave it out to add it last.","type":"integer"},"production_file":{"description":"Production files, uploaded first.","items":{"properties":{"action":{"description":"Send `create` on every entry: a service, pipeline or mockup without it is skipped silently; a production file without it is refused.","enum":["create"],"type":"string"},"id":{"description":"The upload's `id`.","type":"string"},"job_service":{"description":"The temporary service `id` (or ids) this file belongs to."},"name":{"type":"string"},"position":{"type":"integer"}},"required":["action","id","position"],"type":"object"},"type":"array"},"scoped_id":{"description":"Accepted but ignored: the job gets the team's next job number. To change it afterwards, use Change a job number.","type":"string"},"service":{"description":"Decoration services.","items":{"properties":{"action":{"description":"Send `create` on every entry: a service, pipeline or mockup without it is skipped silently; a production file without it is refused.","enum":["create"],"type":"string"},"customer_note":{"description":"A note the customer sees.","type":"string"},"id":{"description":"Your temporary id for this service, to reference it from mockups.","type":"string"},"location":{"properties":{"id":{"description":"A print location id.","type":"string"},"name":{"description":"A custom location name.","type":"string"},"type":{"description":"`database` for a saved print location (send `id`), `custom` for a free name (send `name`).","enum":["database","custom"],"type":"string"}},"type":"object"},"note":{"type":"string"},"option":{"description":"One of the service's price option names, exactly as the service has it (the match is exact, case included), such as `2 Color`. Copy it from `services[].option` on an existing job or job preset. Another name, or none, is refused with 422 `job_validation_error` \"Service does not contain such option …\".","type":"string"},"position":{"description":"Order among the job's services. Required with `id`.","type":"integer"},"service_id":{"description":"A decoration service id. Services are not listed on the public API: copy `service_id` from a job's `services` (Get one job of an order) or from a job preset (List job presets).","type":"string"}},"required":["action","service_id"],"type":"object"},"type":"array"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"accepted":{"summary":"Done","value":{"data":{"assigned_users":[],"id":"zmmzqMwhyJn20A","is_rush":false,"mockup":[],"name":"Team shirts","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","pipelines":[],"pricing_total":{"dp":6,"value":0},"production_file":[],"scoped_id":"JOB-1003","services":[],"status":{"color":"#9e9e9e","customer_label":"Pending","id":"YOqAGjroQEo2ZK","label":"Artwork","position":1,"role":"job","trashed":false,"type":"start"},"status_id":"YOqAGjroQEo2ZK"},"status":200,"success":true}},"refused":{"summary":"Refused with HTTP 200: `success` is false","value":{"error":{"code":"action_not_allowed","message":null},"status":500,"success":false}}},"schema":{"oneOf":[{"properties":{"data":{"additionalProperties":true,"description":"A job.","properties":{"assigned_users":{"items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"K6iF8n29iwOZnj","type":"string"},"impression_count":{"description":"Item count times decoration locations.","type":["string","number","integer","null"]},"inventory_status":{"type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Total quantity of the job's lines (a decimal string or number).","type":["string","number","integer","null"]},"mockup":{"description":"Mockups.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"name":{"example":"Front logo","type":["string","null"]},"note":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pending_approval":{"additionalProperties":true,"description":"The job's open approval (the first one not yet answered), or null. It always keeps its `items`, with or without `omit_media_approval_items`.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"pipelines":{"description":"Work pipelines (production steps).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"position":{"type":["integer","null"]},"pricing_original_total":{"description":"The same before pricing rules. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null when no rule did. List the jobs of a sales order or quote, Get one job and Rearrange the jobs answer with the full summary below. Other answers carry only `type`, the two ids and the two totals.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"2.00","type":"string"},"after_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2000000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","example":"2.50","type":"string"},"base_type":{"description":"Full summary only: always `service_price` on a job.","enum":["service_price"],"type":"string"},"normal_price":{"description":"Full summary only: the price with no rule; on a job the same as `base`.","example":"2.50","type":["string","null"]},"original_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`service` on a job.","example":"service","type":"string"}},"type":["object","null"]},"pricing_total":{"description":"Decoration price per unit that the job adds to each of its lines. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"is_rush":{"type":"boolean"},"name":{"type":["string","null"]},"object_type":{"type":"string"},"status_id":{"type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number people see, such as `JOB-1001`.","example":"JOB-1001","type":"string"},"services":{"description":"Decoration services: `service_id`, `location_*`, `option`, `position`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"services_still_valid":{"description":"false when the job's decoration services need repair.","type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status, as the status operations return it.","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_id":{"description":"The job's production status.","example":"YOqAGjroQEo2ZK","type":"string"},"unique_key":{"example":"job_EXAMPLEuniqueKey","type":["string","null"]}},"required":["id","order_id","scoped_id","status_id"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"const":true,"example":true,"type":"boolean"}},"required":["success","status","data"],"title":"Success","type":"object"},{"$ref":"#/components/schemas/ErrorResponse"}]}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add a job to a sales order or quote","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Copy the option name from `services[].option` on an existing job or job preset that uses the service.","status":422,"when":"`option` is not one of the service's option names, exactly: `job_validation_error` \"Service does not contain such option …\" (the name you sent)."},{"fix":"Copy `service_id` from an existing job or job preset.","status":422,"when":"The service is not one of the team's (\"Service Not Found:…\"), or a required field is missing (`job_validation_error`)."},{"fix":"Check `success` in every reply, and the order's `internal_status`.","status":200,"when":"The order is neither a draft nor published: `success: false`, `error.code` `action_not_allowed` (the body's `status` says 500)."},{"fix":"Ask the team owner for sales order edit permission.","status":403,"when":"The API key's role can't edit this order."}],"group":"Production","permission":"Needs permission to edit this sales order or quote:\n\n- The team owner\n- A role with `update_all_order`\n- A role with `update_self_order`, when the order was created by or is assigned to the API key's user\n- The person who created a draft, with `create_order`\n\nQuotes use the same sales order permissions.","related":["v2_public_job_create_with_template","v2_public_order_item_store","v2_public_job_update","v1_public_async_upload_store","v2_public_job_show","v1_public_job_preset_index"],"rules":["Each `service`, `pipeline` and `mockup` entry needs `action: \"create\"`, or it is skipped silently. A `production_file` entry without `action` is refused with 422 `validation_failed`.","A service must exist in the team's Settings (\"Service Not Found\") and `option` must be one of its options (\"Service does not contain such option ...\").","A pipeline needs `pipeline_id` and `status_id`; its `start_date` and `due_date` go together.","`scoped_id` is ignored: jobs always take the team's next job number."],"side_effects":["Recalculates the decoration pricing of the order's jobs and the order totals.","Refreshes the order for people who have it open in the web app. On a published order, Customer Portal pages the customer has open refresh."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/job/rearrange":{"put":{"description":"Puts the order's jobs in a new order.\n\nSend the complete new order in `job_ids` and the order you started from in `expected_job_ids`, both listing every job of the order. If someone changed the jobs meanwhile, the call fails with 409 `job_order_changed`: read the jobs again and retry. Sending the order the jobs already have succeeds and changes nothing.\n\nOnly job positions (and update times) change; prices and line-item positions stay. The answer is the full job list in its saved order. Each job file carries its latest approval in `current_approval`; add `?omit_media_approval_items=1` to leave out that approval's `items` when you don't need them.\n\n`{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_job_rearrange","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"Send `1` (or `true`, `on`, `yes`) to leave `items` out of each job file's `current_approval`, which makes the answer much smaller for jobs with many files on one approval. Every other key stays, in the same order, and the job's `pending_approval` keeps its items. Leave it out and the answer is unchanged. Only the query string counts: a body field of this name is ignored.","example":"1","in":"query","name":"omit_media_approval_items","required":false,"schema":{"enum":["1","true","on","yes"],"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"expected_job_ids":["K6iF8n29iwOZnj","I3hKS5NY8hhW8u"],"job_ids":["I3hKS5NY8hhW8u","K6iF8n29iwOZnj"]},"schema":{"properties":{"expected_job_ids":{"description":"Every job id of the order, in the order you read them, each once.","items":{"type":"string"},"minItems":1,"type":"array"},"job_ids":{"description":"Every job id of the order, in the new order, each once.","items":{"type":"string"},"minItems":1,"type":"array"}},"required":["job_ids","expected_job_ids"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"accepted":{"summary":"Done","value":{"data":[{"assigned_users":[],"id":"I3hKS5NY8hhW8u","is_rush":false,"mockup":[],"name":"Back print","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","pipelines":[],"position":1,"pricing_total":{"dp":6,"value":0},"production_file":[],"scoped_id":"JOB-1002","services":[],"status":{"color":"#9e9e9e","customer_label":"Pending","id":"YOqAGjroQEo2ZK","label":"Artwork","position":1,"role":"job","trashed":false,"type":"start"},"status_id":"YOqAGjroQEo2ZK"},{"assigned_users":[],"id":"K6iF8n29iwOZnj","is_rush":false,"mockup":[],"name":"Front logo","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","pipelines":[],"position":2,"pricing_total":{"dp":6,"value":0},"production_file":[],"scoped_id":"JOB-1001","services":[],"status":{"color":"#9e9e9e","customer_label":"Pending","id":"YOqAGjroQEo2ZK","label":"Artwork","position":1,"role":"job","trashed":false,"type":"start"},"status_id":"YOqAGjroQEo2ZK"}],"status":200,"success":true}},"refused":{"summary":"Refused with HTTP 200: `success` is false","value":{"error":{"code":"action_not_allowed","message":null},"status":500,"success":false}}},"schema":{"oneOf":[{"properties":{"data":{"description":"Every job of the order in its saved order, as List the jobs of a sales order or quote returns them. Positions are renumbered 1, 2, 3 and so on.","items":{"additionalProperties":true,"description":"A job.","properties":{"assigned_users":{"items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"K6iF8n29iwOZnj","type":"string"},"impression_count":{"description":"Item count times decoration locations.","type":["string","number","integer","null"]},"inventory_status":{"type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Total quantity of the job's lines (a decimal string or number).","type":["string","number","integer","null"]},"mockup":{"description":"Mockups.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"name":{"example":"Front logo","type":["string","null"]},"note":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pending_approval":{"additionalProperties":true,"description":"The job's open approval (the first one not yet answered), or null. It always keeps its `items`, with or without `omit_media_approval_items`.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"pipelines":{"description":"Work pipelines (production steps).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"position":{"type":["integer","null"]},"pricing_original_total":{"description":"The same before pricing rules. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null when no rule did. List the jobs of a sales order or quote, Get one job and Rearrange the jobs answer with the full summary below. Other answers carry only `type`, the two ids and the two totals.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"2.00","type":"string"},"after_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2000000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","example":"2.50","type":"string"},"base_type":{"description":"Full summary only: always `service_price` on a job.","enum":["service_price"],"type":"string"},"normal_price":{"description":"Full summary only: the price with no rule; on a job the same as `base`.","example":"2.50","type":["string","null"]},"original_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`service` on a job.","example":"service","type":"string"}},"type":["object","null"]},"pricing_total":{"description":"Decoration price per unit that the job adds to each of its lines. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"is_rush":{"type":"boolean"},"name":{"type":["string","null"]},"object_type":{"type":"string"},"status_id":{"type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number people see, such as `JOB-1001`.","example":"JOB-1001","type":"string"},"services":{"description":"Decoration services: `service_id`, `location_*`, `option`, `position`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"services_still_valid":{"description":"false when the job's decoration services need repair.","type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status, as the status operations return it.","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_id":{"description":"The job's production status.","example":"YOqAGjroQEo2ZK","type":"string"},"unique_key":{"example":"job_EXAMPLEuniqueKey","type":["string","null"]}},"required":["id","order_id","scoped_id","status_id"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"const":true,"example":true,"type":"boolean"}},"required":["success","status","data"],"title":"Success","type":"object"},{"$ref":"#/components/schemas/ErrorResponse"}]}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"409":{"content":{"application/json":{"example":{"error":{"code":"job_order_changed","message":"The job order has changed. Refresh the list and try again."},"status":409,"success":false},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"The job order or membership changed. Refresh the complete list before submitting a new proposal."},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Reorder the jobs of a sales order or quote","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Send every job of the order once in each list.","status":422,"when":"`job_ids` and `expected_job_ids` don't name the same jobs, or repeat one: `job_validation_error` \"Choose each job exactly once.\""},{"fix":"Read the jobs again and send a new proposal.","status":409,"when":"The jobs or their order changed since you read them (`job_order_changed`)."},{"fix":"Check `success` in every reply.","status":200,"when":"The order is neither a draft nor published: `success: false`, `error.code` `action_not_allowed`."},{"fix":"Ask the team owner for sales order edit permission.","status":403,"when":"The API key's role can't edit this order."}],"group":"Production","permission":"Needs the same permission as editing the order: Needs permission to edit this sales order or quote:\n\n- The team owner\n- A role with `update_all_order`\n- A role with `update_self_order`, when the order was created by or is assigned to the API key's user\n- The person who created a draft, with `create_order`\n\nQuotes use the same sales order permissions.","related":["v2_public_job_index_for_order"],"rules":["Both lists must name every job of the order exactly once.","Works on drafts and published orders only. Otherwise it answers **HTTP 200** with `success: false` and `error.code` `action_not_allowed`."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/job/{job_id}":{"get":{"description":"Returns one job of a sales order or quote, with its mockups. `{job_id}` is the job's `id` (or its `job_` unique key). Each job file carries its latest approval in `current_approval`; add `?omit_media_approval_items=1` to leave out that approval's `items` when you don't need them. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_job_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The job's `id` (a hash id), or its `unique_key` (`job_…`).","example":"K6iF8n29iwOZnj","in":"path","name":"job_id","required":true,"schema":{"example":"K6iF8n29iwOZnj","type":"string"}},{"description":"Send `1` (or `true`, `on`, `yes`) to leave `items` out of each job file's `current_approval`, which makes the answer much smaller for jobs with many files on one approval. Every other key stays, in the same order, and the job's `pending_approval` keeps its items. Leave it out and the answer is unchanged. Only the query string counts: a body field of this name is ignored.","example":"1","in":"query","name":"omit_media_approval_items","required":false,"schema":{"enum":["1","true","on","yes"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"id":"K6iF8n29iwOZnj","is_rush":false,"mockup":[],"name":"Front logo","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","pipelines":[],"pricing_total":{"dp":6,"value":0},"production_file":[],"scoped_id":"JOB-1001","services":[],"status":{"color":"#9e9e9e","customer_label":"Pending","id":"YOqAGjroQEo2ZK","label":"Artwork","position":1,"role":"job","trashed":false,"type":"start"},"status_id":"YOqAGjroQEo2ZK"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A job.","properties":{"assigned_users":{"items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"K6iF8n29iwOZnj","type":"string"},"impression_count":{"description":"Item count times decoration locations.","type":["string","number","integer","null"]},"inventory_status":{"type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Total quantity of the job's lines (a decimal string or number).","type":["string","number","integer","null"]},"mockup":{"description":"Mockups.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"name":{"example":"Front logo","type":["string","null"]},"note":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pending_approval":{"additionalProperties":true,"description":"The job's open approval (the first one not yet answered), or null. It always keeps its `items`, with or without `omit_media_approval_items`.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"pipelines":{"description":"Work pipelines (production steps).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"position":{"type":["integer","null"]},"pricing_original_total":{"description":"The same before pricing rules. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null when no rule did. List the jobs of a sales order or quote, Get one job and Rearrange the jobs answer with the full summary below. Other answers carry only `type`, the two ids and the two totals.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"2.00","type":"string"},"after_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2000000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","example":"2.50","type":"string"},"base_type":{"description":"Full summary only: always `service_price` on a job.","enum":["service_price"],"type":"string"},"normal_price":{"description":"Full summary only: the price with no rule; on a job the same as `base`.","example":"2.50","type":["string","null"]},"original_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`service` on a job.","example":"service","type":"string"}},"type":["object","null"]},"pricing_total":{"description":"Decoration price per unit that the job adds to each of its lines. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"is_rush":{"type":"boolean"},"name":{"type":["string","null"]},"object_type":{"type":"string"},"status_id":{"type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number people see, such as `JOB-1001`.","example":"JOB-1001","type":"string"},"services":{"description":"Decoration services: `service_id`, `location_*`, `option`, `position`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"services_still_valid":{"description":"false when the job's decoration services need repair.","type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status, as the status operations return it.","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_id":{"description":"The job's production status.","example":"YOqAGjroQEo2ZK","type":"string"},"unique_key":{"example":"job_EXAMPLEuniqueKey","type":["string","null"]}},"required":["id","order_id","scoped_id","status_id"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get one job of an order","tags":["Jobs"],"x-yoprint-docs":{"group":"Production","permission":"Any member of the team.","related":["v2_public_job_index_for_order"]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/job_template":{"post":{"description":"Adds a job to a sales order or quote from one of the team's job templates (job presets). The new job gets the template's name and note, its services (with their customer notes), its tasks, its teammates, and its mockups and production files (the copies share the stored file and keep their links to the copied services). Its production dates are the order's. Teammates who left the team, and tasks whose task preset was deleted, are left out without an error.\n\nThe answer is the new job. Works on drafts and published orders. In any other state the call answers **HTTP 200** with `{\"status\": 500, \"success\": false, \"error\": {\"code\": \"action_not_allowed\", \"message\": null}}` and changes nothing: check `success`, not only the HTTP status. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_job_create_with_template","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"id":"YnNYMPf7OE0HCS"},"schema":{"properties":{"id":{"description":"The job template's `id`.","type":"string"}},"required":["id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"accepted":{"summary":"Done","value":{"data":{"assigned_users":[],"id":"NhuUnptncwf77U","is_rush":false,"mockup":[],"name":"Front print","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","pipelines":[],"pricing_total":{"dp":6,"value":0},"production_file":[],"scoped_id":"JOB-1004","services":[],"status":{"color":"#9e9e9e","customer_label":"Pending","id":"YOqAGjroQEo2ZK","label":"Artwork","position":1,"role":"job","trashed":false,"type":"start"},"status_id":"YOqAGjroQEo2ZK"},"status":200,"success":true}},"refused":{"summary":"Refused with HTTP 200: `success` is false","value":{"error":{"code":"action_not_allowed","message":null},"status":500,"success":false}}},"schema":{"oneOf":[{"properties":{"data":{"additionalProperties":true,"description":"A job.","properties":{"assigned_users":{"items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"K6iF8n29iwOZnj","type":"string"},"impression_count":{"description":"Item count times decoration locations.","type":["string","number","integer","null"]},"inventory_status":{"type":["string","null"]},"is_rush":{"type":"boolean"},"item_count":{"description":"Total quantity of the job's lines (a decimal string or number).","type":["string","number","integer","null"]},"mockup":{"description":"Mockups.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"name":{"example":"Front logo","type":["string","null"]},"note":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":"string"},"pending_approval":{"additionalProperties":true,"description":"The job's open approval (the first one not yet answered), or null. It always keeps its `items`, with or without `omit_media_approval_items`.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"pipelines":{"description":"Work pipelines (production steps).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"position":{"type":["integer","null"]},"pricing_original_total":{"description":"The same before pricing rules. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_rule_applied":{"description":"The pricing rule that set the job's decoration price, or null when no rule did. List the jobs of a sales order or quote, Get one job and Rearrange the jobs answer with the full summary below. Other answers carry only `type`, the two ids and the two totals.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"2.00","type":"string"},"after_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2000000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: the decoration price the rule started from, as a decimal string.","example":"2.50","type":"string"},"base_type":{"description":"Full summary only: always `service_price` on a job.","enum":["service_price"],"type":"string"},"normal_price":{"description":"Full summary only: the price with no rule; on a job the same as `base`.","example":"2.50","type":["string","null"]},"original_total":{"description":"The job's decoration price 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.","example":{"dp":6,"value":2500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The job keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`service` on a job.","example":"service","type":"string"}},"type":["object","null"]},"pricing_total":{"description":"Decoration price per unit that the job adds to each of its lines. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"production_file":{"description":"Production files.","items":{"additionalProperties":true,"description":"A job file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"current_approval":{"additionalProperties":true,"description":"The latest approval this file was sent in, as the approval operations return it, or null. When you send `omit_media_approval_items=1` in the query string it has no `items` key; every other key stays.","properties":{"approved_by":{"description":"`contact` when a contact of the order's customer answered in the customer portal (see `approved_by_contact_id`), `user` when a team member recorded the answer (as Record the customer's answer does), `customer` otherwise, including before any answer.","enum":["contact","user","customer"],"type":"string"},"approved_by_contact_id":{"description":"The contact who answered in the customer portal, or null (always null when a team member recorded the answer).","type":["string","null"]},"approved_by_user":{"description":"The team member who recorded the answer, or null.","type":["string","null"]},"completed":{"description":"true once the customer (or you, for them) answered: approved or changes needed.","type":"boolean"},"completed_at":{"description":"When the customer answered. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_last_viewed_contact_id":{"description":"The contact who last opened it in the customer portal, or null when that isn't known.","type":["string","null"]},"customer_last_viewed_date":{"description":"When the customer last opened it. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"xTKi8BqFVVmlL6","type":"string"},"items":{"description":"Job approvals: the mockups under review.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"job_id":{"type":["string","null"]},"notes_from_customer":{"type":["string","null"]},"notes_to_customer":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"signature":{"description":"The signer's typed name.","type":["string","null"]},"status":{"description":"`pending` (created, not emailed), `sent-to-customer`, `viewed-by-customer`, `need-changes` or `completed` (approved). When it was completed without a `status`, the Record answer shows `null` and later reads show `\"\"`.","example":"sent-to-customer","type":["string","null"]},"type":{"description":"`order` for a whole-order approval, `job` for an artwork approval.","enum":["order","job"],"type":"string"}},"required":["id","type","status"],"type":["object","null"]},"current_approval_status":{"description":"`pending-approval` while the latest approval this file was sent in is open; once that approval is answered, this file's own result from it; null when the file was never sent for approval.","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"job_id":{"description":"The job.","example":"K6iF8n29iwOZnj","type":"string"},"job_service":{"description":"The ids of the job's decoration services this file belongs to.","items":{"type":"string"},"type":"array"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"is_rush":{"type":"boolean"},"name":{"type":["string","null"]},"object_type":{"type":"string"},"status_id":{"type":["string","null"]}},"type":"object"},"scoped_id":{"description":"The job number people see, such as `JOB-1001`.","example":"JOB-1001","type":"string"},"services":{"description":"Decoration services: `service_id`, `location_*`, `option`, `position`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"services_still_valid":{"description":"false when the job's decoration services need repair.","type":"boolean"},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status, as the status operations return it.","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_id":{"description":"The job's production status.","example":"YOqAGjroQEo2ZK","type":"string"},"unique_key":{"example":"job_EXAMPLEuniqueKey","type":["string","null"]}},"required":["id","order_id","scoped_id","status_id"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"const":true,"example":true,"type":"boolean"}},"required":["success","status","data"],"title":"Success","type":"object"},{"$ref":"#/components/schemas/ErrorResponse"}]}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add a job from a job template","tags":["Jobs"],"x-yoprint-docs":{"errors":[{"fix":"Send the job template's `id`.","status":422,"when":"`id` is missing or not an id (`validation_failed`)."},{"fix":"Fix the template in Settings > Job Presets.","status":422,"when":"The template uses a service, print location or task preset that can't be found in the team (`job_validation_error`, for example \"Service not found!\" or \"Pipeline not found!\")."},{"fix":"Use an id from the team's job templates.","status":404,"when":"The template does not exist in this team."},{"fix":"Check `success` in every reply, and the order's `internal_status`.","status":200,"when":"The order is neither a draft nor published: `success: false`, `error.code` `action_not_allowed` (the body's `status` says 500)."}],"group":"Production","permission":"Needs permission to edit this sales order or quote:\n\n- The team owner\n- A role with `update_all_order`\n- A role with `update_self_order`, when the order was created by or is assigned to the API key's user\n- The person who created a draft, with `create_order`\n\nQuotes use the same sales order permissions.","related":["v1_public_job_preset_index","v2_public_job_store"],"side_effects":["Recalculates the order's job pricing and refreshes the order for people who have it open in the web app. On a published order, Customer Portal pages the customer has open refresh."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/media":{"get":{"description":"Returns the files attached to a sales order or quote (the Files section in the web app). `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_media_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"collection":"default","created_at":"2026-11-03T09:00:00+00:00","file_name":"front-logo.png","id":"uAzgeGQMGvaVK3","is_image":true,"mime_type":"image/png","name":"Front logo","position":1,"show_in_pdf":null,"size":20480,"url":"https://example.com/files/front-logo.png"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the files of an order","tags":["Sales order files"],"x-yoprint-docs":{"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_media_attach"]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/media/attach":{"put":{"description":"Attaches files you have already uploaded to a sales order or quote.\n\nUpload each file first with the upload operation, then send the uploads' ids here. All of them are attached, or none.\n\nThe answer lists the attached files. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_media_attach","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"attachment":[{"id":"uAzgeGQMGvaVK3"}]},"schema":{"properties":{"attachment":{"items":{"properties":{"id":{"description":"The upload's `id`. Each id once.","type":"string"}},"required":["id"],"type":"object"},"minItems":1,"type":"array"}},"required":["attachment"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"collection":"default","created_at":"2026-11-03T09:00:00+00:00","file_name":"front-logo.png","id":"uAzgeGQMGvaVK3","is_image":true,"mime_type":"image/png","name":"Front logo","position":1,"show_in_pdf":null,"size":20480,"url":"https://example.com/files/front-logo.png"}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"The files attached by this call.","items":{"additionalProperties":true,"description":"A file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/MediaUploadValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Attach uploaded files to an order","tags":["Sales order files"],"x-yoprint-docs":{"errors":[{"fix":"Upload the file first and send its id once.","status":422,"when":"No ids, a repeated id, or an id that is not an upload."},{"fix":"Use the id the upload returned.","status":404,"when":"An upload id does not exist."}],"group":"Sales","permission":"Any member of the team.","related":["v1_public_async_upload_store","v2_public_order_media_index","v2_public_order_media_destroy"],"rules":["At least one id, no repeats.","Each id must be a finished upload: \"Please upload this media before attaching it to an order.\""],"side_effects":["Creates the files' previews and refreshes the order for people who have it open in the web app."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/media/{hash_id2}":{"delete":{"description":"Deletes a file from the order. `{hash_id2}` is the file's `id`. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_media_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The file's `id` (a hash id).","example":"uAzgeGQMGvaVK3","in":"path","name":"hash_id2","required":true,"schema":{"example":"uAzgeGQMGvaVK3","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"description":"No data.","type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a file from an order","tags":["Sales order files"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the order's files.","status":404,"when":"The file is not on this order."}],"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_media_index"],"side_effects":["Refreshes the order for people who have it open in the web app."]}},"get":{"description":"Returns one file of the order. `{hash_id2}` is the file's `id`. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_media_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The file's `id` (a hash id).","example":"uAzgeGQMGvaVK3","in":"path","name":"hash_id2","required":true,"schema":{"example":"uAzgeGQMGvaVK3","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"collection":"default","created_at":"2026-11-03T09:00:00+00:00","file_name":"front-logo.png","id":"uAzgeGQMGvaVK3","is_image":true,"mime_type":"image/png","name":"Front logo","position":1,"show_in_pdf":null,"size":20480,"url":"https://example.com/files/front-logo.png"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A file.","properties":{"collection":{"description":"`default` for an order's files; `mockup` or `production_file` for a job's.","type":"string"},"created_at":{"description":"When the file was uploaded (attaching it doesn't change this). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"dimensions":{"description":"Pixel size of an image; null otherwise.","properties":{"height":{"type":"integer"},"width":{"type":"integer"}},"type":["object","null"]},"file_name":{"example":"front-logo.png","type":"string"},"id":{"example":"uAzgeGQMGvaVK3","type":"string"},"is_image":{"type":"boolean"},"mime_type":{"example":"image/png","type":"string"},"name":{"example":"Front logo","type":"string"},"position":{"type":["integer","number","null"]},"preview_state":{"description":"`ready`: previews work. `processing`: a large image whose preview is still being made. `too_large`: over 120 megapixels, no preview. `none`: not an image.","enum":["ready","processing","too_large","failed","none"],"type":"string"},"show_in_pdf":{"description":"Mockups: shown on the order PDF. Null on files that never had it set, such as an order's files.","type":["boolean","null"]},"size":{"description":"Bytes.","type":["integer","null"]},"url":{"description":"Download link.","type":["string","null"]},"view_url":{"type":["string","null"]}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a file of an order","tags":["Sales order files"],"x-yoprint-docs":{"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_media_index"]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/message":{"get":{"description":"Returns the conversation with the customer on a sales order or quote, oldest first, with each message's attachments. Shopify orders are not found here. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_order_message_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"actor_name":"Alex Rivera","actor_type":"user","contact_id":null,"created_at":"2026-11-03T09:00:00+00:00","email":null,"id":"mD1A7NR38PtyNs","name":null,"order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","preview_message":"<p>Hi Alex, your order is ready for pickup.</p>","status":"pending","type":"outbound","user_id":"PydH0WtBhSeiNU"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A message.","properties":{"actor_name":{"description":"The writer's name, by `actor_type`: the team member, contact, customer, guest, participant or vendor; the team's name for `system`. Null when it can't be found.","example":"Alex Rivera","type":["string","null"]},"actor_type":{"description":"Who wrote it: `user` (a team member), `contact`, `customer`, `guest`, `participant`, `vendor` or `system`.","example":"user","type":["string","null"]},"contact_id":{"description":"The contact who sent it, for replies.","type":["string","null"]},"created_at":{"description":"Sent. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"delivery_summary":{"additionalProperties":true,"description":"Delivery state per recipient.","type":["object","null"]},"email":{"type":["string","null"]},"id":{"example":"mD1A7NR38PtyNs","type":"string"},"name":{"description":"Sender name, for replies from the customer; null on messages your team sends (read `actor_name`).","type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"preview_message":{"description":"The first 200 characters. An email's preview keeps its HTML.","type":["string","null"]},"status":{"type":["string","null"]},"type":{"type":["string","null"]},"user_id":{"description":"The team member who sent it.","type":["string","null"]}},"required":["id"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the messages of an order","tags":["Sales order messages"],"x-yoprint-docs":{"group":"Sales","permission":"Needs permission to message this order's customer: the team owner, `message_all_order`, or `message_self_order` for orders the user created or is assigned to.","related":["v2_public_order_message_store","v2_public_messages_index"]}},"post":{"description":"Sends a message about a published sales order or quote to its participants, by email or text message, and saves it in the order's conversation.\n\nAdd the people who should receive it as participants first, then send their participant ids in `participants`.\n\nEmail limit: if your team goes over the daily email limit for its plan (60 a day on a free plan or trial, more on paid plans), YoPrint blocks email sending for your whole team until YoPrint support lifts the block. Space out bulk sends.\n\nThe answer is the saved message. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here. Use this rather than the v1 version, which also accepts drafts.","operationId":"v2_public_order_message_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"internal_attachments":[{"type":"order"}],"message":"<p>Hi Alex, your order is ready for pickup.</p>","participants":[{"id":"LBbXMRNWVof2bd"}]},"schema":{"properties":{"internal_attachments":{"description":"Documents and files to attach.","items":{"properties":{"detail":{"type":"string"},"media_id":{"description":"The file's id. Required for `media` and `reference_media`.","type":"string"},"name":{"description":"The attachment's file name.","type":"string"},"options":{"properties":{"id":{"description":"For `single_compact_invoice`: the `id` of one of this order's invoices. Another order's invoice, or an invoice that can't be printed yet, is left out without an error, and the message is still sent.","type":"string"},"show_mockup":{"description":"For `so_jobs_with_mockup` and `so_jobs_without_mockup`: `true` puts each job's mockup pages in the job sheets, `false` leaves them out. It overrides the type's own choice. Text such as `\"true\"` or `\"off\"` is accepted too; any other value is refused with 422 `validation_failed`. Other types ignore it.","type":"boolean"}},"type":"object"},"type":{"description":"A PDF YoPrint makes: the order or quote (`order`, `order_compact`), all jobs with or without mockups, all invoices (`so_invoices`, `so_compact_invoices`) or one invoice (`single_compact_invoice`, with `options.id`). Or a file: `media` or `reference_media`, with `media_id`. On a quote, the invoice files are named \"Pro Forma Invoice\" by default.","enum":["order","order_compact","so_jobs_with_mockup","so_jobs_without_mockup","so_invoices","so_compact_invoices","single_compact_invoice","media","reference_media"],"type":"string"}},"required":["type"],"type":"object"},"type":"array"},"message":{"description":"The message. HTML for email; plain text for a text message.","type":"string"},"participants":{"description":"Who receives it: participant ids from this order's participants (not contact ids). Required, at least one. Every id must be a current participant of this order: one that isn't refuses the whole message with 422 `participant_not_on_record`, and nothing is sent. An id listed twice counts once.","items":{"properties":{"id":{"description":"A participant `id`.","type":"string"}},"required":["id"],"type":"object"},"maxItems":20,"type":"array"},"send_as_text_message":{"description":"true to send it as a text message (SMS) instead of email.","type":"boolean"}},"required":["message","participants"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"actor_name":"Alex Rivera","actor_type":"user","contact_id":null,"created_at":"2026-11-03T09:00:00+00:00","email":null,"id":"mD1A7NR38PtyNs","message":"<p>Hi Alex, your order is ready for pickup.</p>","name":null,"order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","preview_message":"<p>Hi Alex, your order is ready for pickup.</p>","retryable":false,"status":"pending","type":"outbound","user_id":"PydH0WtBhSeiNU"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A message.","properties":{"actor_name":{"description":"The writer's name, by `actor_type`: the team member, contact, customer, guest, participant or vendor; the team's name for `system`. Null when it can't be found.","example":"Alex Rivera","type":["string","null"]},"actor_type":{"description":"Who wrote it: `user` (a team member), `contact`, `customer`, `guest`, `participant`, `vendor` or `system`.","example":"user","type":["string","null"]},"contact_id":{"description":"The contact who sent it, for replies.","type":["string","null"]},"created_at":{"description":"Sent. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"delivery_summary":{"additionalProperties":true,"description":"Delivery state per recipient.","type":["object","null"]},"email":{"type":["string","null"]},"id":{"example":"mD1A7NR38PtyNs","type":"string"},"message":{"description":"The full message.","type":["string","null"]},"name":{"description":"Sender name, for replies from the customer; null on messages your team sends (read `actor_name`).","type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"preview_message":{"description":"The first 200 characters. An email's preview keeps its HTML.","type":["string","null"]},"retryable":{"description":"true when a failed delivery can be retried.","type":"boolean"},"status":{"type":["string","null"]},"type":{"type":["string","null"]},"user_id":{"description":"The team member who sent it.","type":["string","null"]}},"required":["id"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Send a message to the customer","tags":["Sales order messages"],"x-yoprint-docs":{"errors":[{"fix":"Add participants with an email address or SMS consent, or publish the order.","status":422,"when":"An empty `participants` list, a participant who can't receive the channel, a draft or deleted order, or the team's email limit is reached."},{"fix":"List this order's participants and send only their ids; add anyone missing as a participant first.","status":422,"when":"A participant id is not a current participant of this order: another order's participant, a removed one, or an unknown id (`error.code` `participant_not_on_record`). Nothing is saved or sent."},{"fix":"Ask YoPrint support to turn email on, or lift the block.","status":422,"when":"The team can't send email: `email_feature_not_enabled_in_trial`, or over the daily limit."},{"fix":"Ask the team owner for message permission.","status":403,"when":"The role can't message this order's customer."}],"group":"Messages and activity","notes":["Ask before sending on someone's behalf: the customer receives it at once."],"permission":"Needs permission to message this order's customer: the team owner, `message_all_order`, or `message_self_order` for orders the user created or is assigned to.","related":["v1_public_sales_order_participant_store","v2_public_order_message_index","v2_public_messages_show"],"rules":["Only published orders: drafts are refused (\"No Permission - the resource is not yet created\").","`participants` must be a non-empty list: an empty or missing list is refused with 422 \"Participants are required\".","Every participant id must belong to this order and not be removed: an id of another order's participant, a removed participant or an unknown id refuses the whole message with 422 `participant_not_on_record` (\"A recipient is not on this record. Refresh the page and choose the recipients again.\"), and nothing is saved or sent. Use ids from this order's participant list.","Each participant must be able to receive the channel: email needs an email address (`participant_cannot_receive_email`), a text message needs `can_receive_sms`.","By email, every listed participant with an email address is sent the message, whatever their `status` or `can_receive_mail`. By text message, only those with `can_receive_sms` and status `all` or `message`. Leave out anyone who should not receive it.","At most 20 participants per message.","Deleted orders and Shopify orders refuse messages.","Messages count toward the team's daily email limit (60 a day on the free plan, and on a trial only once YoPrint support has turned email on for it; 280, 380 or 800 on paid plans depending on the subscription's age). Going over it blocks the team's email until YoPrint support lifts the block. A trial without email turned on, or a team without an active plan, gets 422 `email_feature_not_enabled_in_trial`."],"side_effects":["Sends the message to the participants by email (or text message) after it is saved, with the attachments. An email's link to the conversation opens it for the contact it was sent to.","The message is sent as the API key's user.","When the message shows in the customer portal (a published order that isn't from Shopify, with customer messages on), Customer Portal pages the order's customer has open refresh."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment":{"get":{"description":"Returns every money record on an order, newest first and all at once (no pagination): payments, refunds, customer credit moves (`subtype` `TRANSFER`), voided card payments, Shopify payments, and payments the customer made in the customer portal (`action` `CUSTOMER_CHECKOUT`) with their refunds and lost disputes (`CUSTOMER_CHECKOUT_CHARGEBACK`). It also lists the records YoPrint adds itself: credit a refund took back (`ORDER_CREDIT_RECOVERY`), credit given back when that refund failed (`ORDER_CREDIT_RESTORED`), and money returned to a payment when its card refund failed (`REFUND_REVERSAL`). Refunds and other money out have a negative `amount`.\n\nCard payments also say whether they are frozen by a dispute (`has_open_hold`, `payment_freeze_reason`, `payment_notices`). `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_payment_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"action":"ORDER_REFUND","amount":-25000,"credit_source":null,"customer_id":null,"date":"2026-11-05T00:00:00+00:00","direction":"DECREASE","id":"t3FdSWWe9TLyAR","is_deletable":true,"is_editable":false,"order_id":"V4keXwwxMQyXw7","payment_gateway":null,"payment_method_id":"Kst6z3ULXLBrmN","reference_description":"Returned two shirts","reference_id":null,"refundable_amount":0,"related_transaction":"hAwWd7vPrqjuHD","subtype":"REFUND","token":null,"type":"MANUAL","user_id":"PydH0WtBhSeiNU","voided":false},{"action":"ORDER_PAYMENT","amount":75000,"credit_source":null,"customer_id":null,"date":"2026-11-03T00:00:00+00:00","delete_blocked_reason":null,"direction":"INCREASE","id":"hAwWd7vPrqjuHD","is_deletable":true,"is_editable":true,"order_id":"V4keXwwxMQyXw7","payment_gateway":null,"payment_method_id":"Kst6z3ULXLBrmN","reference_description":null,"reference_id":"CHK-1001","refundable_amount":50000,"related_transaction":null,"remove_unavailable":null,"subtype":"PAYMENT","token":null,"type":"MANUAL","user_id":"PydH0WtBhSeiNU","voided":false}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"Newest first.","items":{"additionalProperties":true,"description":"A payment, refund or credit move. Customer Portal rows (`action` `CUSTOMER_CHECKOUT`, and credit applied from a Customer Portal payment) also carry `customer_payment_checkout_id`, `funding_transaction_id`, `customer_payment_application_id`, `customer_payment_source_kind`, `is_external_cash_movement` and `currency_iso`.","properties":{"action":{"description":"`ORDER_PAYMENT`, `ORDER_REFUND`, `ORDER_CREDIT_DEPOSIT` (paid from customer credit), `ORDER_CREDIT_WITHDRAW` (moved to customer credit), `ORDER_CREDIT_RECOVERY`, `ORDER_CREDIT_RESTORED`, `CUSTOMER_CHECKOUT` (paid in the customer portal, and its refunds), `CUSTOMER_CHECKOUT_CHARGEBACK` (a lost dispute), or the gateway: `STRIPE`, `SQUARE`, `SQUARE_V2`, `PAYPAL`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`. A `REFUND_REVERSAL` carries its refund's gateway.","example":"ORDER_PAYMENT","type":["string","null"]},"amount":{"description":"Signed: negative for `DECREASE` (a 25.00 refund is `-25000`). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"credit_source":{"additionalProperties":true,"description":"Where a customer credit record came from. Always present; null on an order's records.","type":["object","null"]},"credit_source_payment_id":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: the payment the credit was issued from.","type":["string","null"]},"customer_id":{"description":"Always null on an order's records.","type":["string","null"]},"customer_payment_funding_id":{"description":"Customer Portal payment rows and credit applied from one only: the customer payment it belongs to.","type":["string","null"]},"customer_payment_sources":{"description":"Customer Portal rows only: the customer payments the money came from, each with `customer_payment_funding_id`, `funding_transaction_id`, `amount` (a decimal string) and `currency_iso`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"date":{"description":"When it was recorded (the payment date you sent). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"delete_blocked_reason":{"description":"Recorded payments (`ORDER_PAYMENT`) and card payments only: why Delete a payment or refund refuses it, or null when it can be deleted. `code` is `credit_issued_from_payment` (with `amount`, a decimal string) or `provider_payment_not_removable`; `message` is the refusal's text.","properties":{"amount":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}},"type":["object","null"]},"direction":{"description":"`INCREASE` (payments, payments from customer credit, `REFUND_REVERSAL`, `ORDER_CREDIT_RECOVERY`) or `DECREASE` (refunds and lost disputes, moves to customer credit, card voids, `ORDER_CREDIT_RESTORED`).","example":"INCREASE","type":"string"},"funding_payment_gateway":{"description":"Customer Portal rows only: the provider (`STRIPE`, `PAYPAL`, `SQUARE_V2`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`) or null.","type":["string","null"]},"has_open_hold":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and Customer Portal payments: true while a dispute (or, for a Customer Portal payment, a review) is open.","type":"boolean"},"id":{"example":"hAwWd7vPrqjuHD","type":"string"},"is_deletable":{"description":"false for card payments, Customer Portal payments, credit moves, card refunds, payments part of which moved to customer credit (and their refunds), refunds recorded against card payments, and the records YoPrint adds itself.","type":"boolean"},"is_editable":{"description":"true only for recorded payments (`ORDER_PAYMENT`).","type":"boolean"},"negative_credit_amount":{"description":"Card refunds only: credit issued from the payment that the customer had already spent and the refund took back anyway, leaving their credit negative (usually 0). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"payment_freeze_reason":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and direct Customer Portal payments: `chargeback_open` or `payment_under_review` while refunds and credit moves are refused, otherwise null.","type":["string","null"]},"payment_gateway":{"description":"The gateway (`STRIPE`, `SQUARE_V2` and so on) for card payments and refunds; for a Customer Portal payment its provider (null when unknown), and `CUSTOMER_CHECKOUT` or `CUSTOMER_CHECKOUT_CHARGEBACK` on its refunds and lost disputes; null otherwise.","type":["string","null"]},"payment_gateway_source":{"description":"Card payments and refunds only: Square v2's source type (for example `CARD`), otherwise null.","type":["string","null"]},"payment_method_id":{"description":"Refunds take their payment's; null for card payments and credit moves.","type":["string","null"]},"payment_notices":{"description":"List and Get only, on the same payments as `has_open_hold`: one notice per open dispute.","items":{"additionalProperties":true,"properties":{"amount":{"description":"The disputed amount as a decimal pair with `dp` 3, or null when the payment covered several orders.","type":["object","null"]},"code":{"description":"`dispute_open` or `dispute_under_review`; on Customer Portal payments also `payment_needs_attention`.","type":"string"},"currency_iso":{"type":"string"},"customer_payment_dispute_id":{"type":"string"},"customer_payment_funding_id":{"type":["string","null"]},"deadline_at":{"description":"When the response to the provider is due (ISO 8601), or null.","type":["string","null"]},"next_action":{"description":"For example `respond_to_provider` or `awaiting_provider`.","type":"string"},"provider":{"type":"string"},"provider_status":{"type":"string"},"stage":{"type":["string","null"]}},"type":"object"},"type":"array"},"recovery_kind":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: null on an order's records.","type":["string","null"]},"reference_description":{"type":["string","null"]},"reference_id":{"example":"CHK-1001","type":["string","null"]},"refundable_amount":{"description":"Payments only: the amount minus its refunds. Money moved to customer credit is not taken off here, though a refund can't include it. 0 for refunds, credit moves, payments from customer credit, and `CHARGE_IT_PRO` and `SQUARE` card payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"related_transaction":{"description":"For a refund, the `id` of the payment it refunds; for `REFUND_REVERSAL`, the payment; for `ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED`, the refund; null otherwise.","type":["string","null"]},"remove_unavailable":{"description":"Recorded payments only: `{ \"reason\": \"credit_issued\", \"amount\": <thousandths> }` when credit was issued from the payment, otherwise null.","type":["object","null"]},"restores_transaction_id":{"description":"`ORDER_CREDIT_RESTORED` only: the `ORDER_CREDIT_RECOVERY` record it gives back.","type":["string","null"]},"reversal_transaction_id":{"description":"Card refunds and `ORDER_CREDIT_RESTORED` only: the `REFUND_REVERSAL` record when the refund failed, or null.","type":["string","null"]},"reverses_transaction_id":{"description":"`REFUND_REVERSAL` only: the failed refund.","type":["string","null"]},"subtype":{"description":"`PAYMENT`, `REFUND` (also a lost dispute), `TRANSFER` (a customer credit move), `ORDER_PAYMENT_VOIDED_NEG_ADJ` (a voided card payment), `REFUND_REVERSAL` (a failed card refund given back to its payment), `ORDER_CREDIT_RECOVERY` (credit a refund took back) or `ORDER_CREDIT_RESTORED` (that credit given back when the refund failed).","example":"PAYMENT","type":"string"},"token":{"description":"The gateway's charge token; null for recorded payments.","type":["string","null"]},"type":{"description":"`MANUAL` (recorded in YoPrint) or `SYSTEM` (card and Customer Portal payments and refunds, Shopify payments, adjustments).","example":"MANUAL","type":"string"},"user_id":{"description":"The team member who recorded it.","type":["string","null"]},"voided":{"type":"boolean"}},"required":["id","amount"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the payments of a sales order","tags":["Payments"],"x-yoprint-docs":{"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_sales_order_manual_payment_store","v2_public_sales_order_payment_show"]}},"post":{"description":"Records a payment you received outside YoPrint, such as cash, a check or a bank transfer. No money moves: it is a record.\n\nSend a whole number of thousandths: `12500` is 12.50. See [Money and quantities](/concepts/money-and-quantities/). Send the payment date in `date` (or `created_at`).\n\nThe payment is allocated to the order's invoices. The answer is the payment. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_manual_payment_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"amount":75000,"date":"2026-11-03","payment_method_id":"Kst6z3ULXLBrmN","reference_id":"CHK-1001"},"schema":{"properties":{"amount":{"description":"The payment as a whole number of thousandths of the currency: `12500` is 12.50 and `75000` is 75.00. A number with decimals, such as `12.5`, is refused with 422. The sign is ignored.","type":"integer"},"created_at":{"description":"Same as `date`; `date` wins when both are sent.","format":"date","type":"string"},"date":{"description":"When it was paid (ISO 8601). Send `date` or `created_at`.","format":"date","type":"string"},"payment_method_id":{"description":"A payment method id from the team's payment methods, for example Cash.","type":"string"},"reference_description":{"type":"string"},"reference_id":{"description":"Your reference, such as a check number.","type":"string"}},"required":["amount"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"action":"ORDER_PAYMENT","amount":75000,"credit_source":null,"customer_id":null,"date":"2026-11-03T00:00:00+00:00","delete_blocked_reason":null,"direction":"INCREASE","id":"hAwWd7vPrqjuHD","is_deletable":true,"is_editable":true,"order_id":"V4keXwwxMQyXw7","payment_gateway":null,"payment_method_id":"Kst6z3ULXLBrmN","reference_description":null,"reference_id":"CHK-1001","refundable_amount":75000,"related_transaction":null,"remove_unavailable":null,"subtype":"PAYMENT","token":null,"type":"MANUAL","user_id":"PydH0WtBhSeiNU","voided":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A payment, refund or credit move. Customer Portal rows (`action` `CUSTOMER_CHECKOUT`, and credit applied from a Customer Portal payment) also carry `customer_payment_checkout_id`, `funding_transaction_id`, `customer_payment_application_id`, `customer_payment_source_kind`, `is_external_cash_movement` and `currency_iso`.","properties":{"action":{"description":"`ORDER_PAYMENT`, `ORDER_REFUND`, `ORDER_CREDIT_DEPOSIT` (paid from customer credit), `ORDER_CREDIT_WITHDRAW` (moved to customer credit), `ORDER_CREDIT_RECOVERY`, `ORDER_CREDIT_RESTORED`, `CUSTOMER_CHECKOUT` (paid in the customer portal, and its refunds), `CUSTOMER_CHECKOUT_CHARGEBACK` (a lost dispute), or the gateway: `STRIPE`, `SQUARE`, `SQUARE_V2`, `PAYPAL`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`. A `REFUND_REVERSAL` carries its refund's gateway.","example":"ORDER_PAYMENT","type":["string","null"]},"amount":{"description":"Signed: negative for `DECREASE` (a 25.00 refund is `-25000`). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"credit_source":{"additionalProperties":true,"description":"Where a customer credit record came from. Always present; null on an order's records.","type":["object","null"]},"credit_source_payment_id":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: the payment the credit was issued from.","type":["string","null"]},"customer_id":{"description":"Always null on an order's records.","type":["string","null"]},"customer_payment_funding_id":{"description":"Customer Portal payment rows and credit applied from one only: the customer payment it belongs to.","type":["string","null"]},"customer_payment_sources":{"description":"Customer Portal rows only: the customer payments the money came from, each with `customer_payment_funding_id`, `funding_transaction_id`, `amount` (a decimal string) and `currency_iso`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"date":{"description":"When it was recorded (the payment date you sent). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"delete_blocked_reason":{"description":"Recorded payments (`ORDER_PAYMENT`) and card payments only: why Delete a payment or refund refuses it, or null when it can be deleted. `code` is `credit_issued_from_payment` (with `amount`, a decimal string) or `provider_payment_not_removable`; `message` is the refusal's text.","properties":{"amount":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}},"type":["object","null"]},"direction":{"description":"`INCREASE` (payments, payments from customer credit, `REFUND_REVERSAL`, `ORDER_CREDIT_RECOVERY`) or `DECREASE` (refunds and lost disputes, moves to customer credit, card voids, `ORDER_CREDIT_RESTORED`).","example":"INCREASE","type":"string"},"funding_payment_gateway":{"description":"Customer Portal rows only: the provider (`STRIPE`, `PAYPAL`, `SQUARE_V2`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`) or null.","type":["string","null"]},"has_open_hold":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and Customer Portal payments: true while a dispute (or, for a Customer Portal payment, a review) is open.","type":"boolean"},"id":{"example":"hAwWd7vPrqjuHD","type":"string"},"is_deletable":{"description":"false for card payments, Customer Portal payments, credit moves, card refunds, payments part of which moved to customer credit (and their refunds), refunds recorded against card payments, and the records YoPrint adds itself.","type":"boolean"},"is_editable":{"description":"true only for recorded payments (`ORDER_PAYMENT`).","type":"boolean"},"negative_credit_amount":{"description":"Card refunds only: credit issued from the payment that the customer had already spent and the refund took back anyway, leaving their credit negative (usually 0). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"payment_freeze_reason":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and direct Customer Portal payments: `chargeback_open` or `payment_under_review` while refunds and credit moves are refused, otherwise null.","type":["string","null"]},"payment_gateway":{"description":"The gateway (`STRIPE`, `SQUARE_V2` and so on) for card payments and refunds; for a Customer Portal payment its provider (null when unknown), and `CUSTOMER_CHECKOUT` or `CUSTOMER_CHECKOUT_CHARGEBACK` on its refunds and lost disputes; null otherwise.","type":["string","null"]},"payment_gateway_source":{"description":"Card payments and refunds only: Square v2's source type (for example `CARD`), otherwise null.","type":["string","null"]},"payment_method_id":{"description":"Refunds take their payment's; null for card payments and credit moves.","type":["string","null"]},"payment_notices":{"description":"List and Get only, on the same payments as `has_open_hold`: one notice per open dispute.","items":{"additionalProperties":true,"properties":{"amount":{"description":"The disputed amount as a decimal pair with `dp` 3, or null when the payment covered several orders.","type":["object","null"]},"code":{"description":"`dispute_open` or `dispute_under_review`; on Customer Portal payments also `payment_needs_attention`.","type":"string"},"currency_iso":{"type":"string"},"customer_payment_dispute_id":{"type":"string"},"customer_payment_funding_id":{"type":["string","null"]},"deadline_at":{"description":"When the response to the provider is due (ISO 8601), or null.","type":["string","null"]},"next_action":{"description":"For example `respond_to_provider` or `awaiting_provider`.","type":"string"},"provider":{"type":"string"},"provider_status":{"type":"string"},"stage":{"type":["string","null"]}},"type":"object"},"type":"array"},"recovery_kind":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: null on an order's records.","type":["string","null"]},"reference_description":{"type":["string","null"]},"reference_id":{"example":"CHK-1001","type":["string","null"]},"refundable_amount":{"description":"Payments only: the amount minus its refunds. Money moved to customer credit is not taken off here, though a refund can't include it. 0 for refunds, credit moves, payments from customer credit, and `CHARGE_IT_PRO` and `SQUARE` card payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"related_transaction":{"description":"For a refund, the `id` of the payment it refunds; for `REFUND_REVERSAL`, the payment; for `ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED`, the refund; null otherwise.","type":["string","null"]},"remove_unavailable":{"description":"Recorded payments only: `{ \"reason\": \"credit_issued\", \"amount\": <thousandths> }` when credit was issued from the payment, otherwise null.","type":["object","null"]},"restores_transaction_id":{"description":"`ORDER_CREDIT_RESTORED` only: the `ORDER_CREDIT_RECOVERY` record it gives back.","type":["string","null"]},"reversal_transaction_id":{"description":"Card refunds and `ORDER_CREDIT_RESTORED` only: the `REFUND_REVERSAL` record when the refund failed, or null.","type":["string","null"]},"reverses_transaction_id":{"description":"`REFUND_REVERSAL` only: the failed refund.","type":["string","null"]},"subtype":{"description":"`PAYMENT`, `REFUND` (also a lost dispute), `TRANSFER` (a customer credit move), `ORDER_PAYMENT_VOIDED_NEG_ADJ` (a voided card payment), `REFUND_REVERSAL` (a failed card refund given back to its payment), `ORDER_CREDIT_RECOVERY` (credit a refund took back) or `ORDER_CREDIT_RESTORED` (that credit given back when the refund failed).","example":"PAYMENT","type":"string"},"token":{"description":"The gateway's charge token; null for recorded payments.","type":["string","null"]},"type":{"description":"`MANUAL` (recorded in YoPrint) or `SYSTEM` (card and Customer Portal payments and refunds, Shopify payments, adjustments).","example":"MANUAL","type":"string"},"user_id":{"description":"The team member who recorded it.","type":["string","null"]},"voided":{"type":"boolean"}},"required":["id","amount"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Record a payment on a sales order","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Publish the order and send `amount` and `date`.","status":422,"when":"A draft order (`validation_error`, \"Payment Action Not Allowed - due to order internal state\"), a missing `amount` or date, an `amount` with decimals, an unknown payment method, or a Shopify order deleted in Shopify (`shopify_order_deleted_externally`)."}],"group":"Invoices and payments","permission":"Any member of the team. The order must be published.","related":["v2_public_sales_order_payment_index","v2_public_sales_order_manual_payment_refund","v1_public_payment_method_index"],"rules":["Only published orders: \"Payment Action Not Allowed - due to order internal state\".","`amount` is a whole number of thousandths, and `date` or `created_at` is required (an ISO 8601 date or date-time; `date` wins). The sign of `amount` is ignored (-12500 records 12.50). An `amount` that is not a whole number, such as `12.5`, is refused with 422 `validation_failed` and nothing is recorded: `error.fields.amount` says \"The amount must be a whole number of thousandths of the currency unit, such as 12500 for 12.50.\".","`payment_method_id` must be one of the team's payment methods.","Refused when the Shopify order was deleted in Shopify."],"side_effects":["Updates the order's paid amount and balance, its invoices, and the customer's totals. Customer Portal pages the order's customer has open refresh.","Sends the `payment_received.any_amount` webhook; also `payment_received.deposit_amount` when the order's paid total now exactly equals its deposit amount, and `payment_received.full_amount` when the balance due (invoiced total minus paid) is now exactly 0. A payment that goes past the deposit, or overpays, sends neither of those two.","Adds an entry to the activity feed. No receipt is emailed."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment/{id}/refund":{"put":{"description":"Records that you gave back some or all of a payment outside YoPrint. No money moves. For a card payment, use Refund a card payment through the gateway instead: this operation only records a refund and does not return money. `{id}` is the payment's `id`.\n\nSend a whole number of thousandths: `12500` is 12.50. See [Money and quantities](/concepts/money-and-quantities/). The refund uses the payment's method. The answer is the refund: `subtype` `REFUND`, `direction` `DECREASE`, a **negative** `amount` (25.00 is `-25000`), `refundable_amount` 0, and the payment's `id` in `related_transaction`. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_manual_payment_refund","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The payment's `id` (a hash id).","example":"hAwWd7vPrqjuHD","in":"path","name":"id","required":true,"schema":{"example":"hAwWd7vPrqjuHD","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"amount":25000,"date":"2026-11-05","reference_description":"Returned two shirts"},"schema":{"properties":{"amount":{"description":"The refund as a whole number of thousandths of the currency: `12500` is 12.50. A number with decimals is refused with 422. The sign is ignored and the answer shows the refund as negative.","type":"integer"},"created_at":{"format":"date","type":"string"},"date":{"description":"When it was refunded. Send `date` or `created_at`.","format":"date","type":"string"},"reference_description":{"type":"string"},"reference_id":{"type":"string"}},"required":["amount"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"action":"ORDER_REFUND","amount":-25000,"credit_source":null,"customer_id":null,"date":"2026-11-05T00:00:00+00:00","direction":"DECREASE","id":"t3FdSWWe9TLyAR","is_deletable":true,"is_editable":false,"order_id":"V4keXwwxMQyXw7","payment_gateway":null,"payment_method_id":"Kst6z3ULXLBrmN","reference_description":"Returned two shirts","reference_id":null,"refundable_amount":0,"related_transaction":"hAwWd7vPrqjuHD","subtype":"REFUND","token":null,"type":"MANUAL","user_id":"PydH0WtBhSeiNU","voided":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A payment, refund or credit move. Customer Portal rows (`action` `CUSTOMER_CHECKOUT`, and credit applied from a Customer Portal payment) also carry `customer_payment_checkout_id`, `funding_transaction_id`, `customer_payment_application_id`, `customer_payment_source_kind`, `is_external_cash_movement` and `currency_iso`.","properties":{"action":{"description":"`ORDER_PAYMENT`, `ORDER_REFUND`, `ORDER_CREDIT_DEPOSIT` (paid from customer credit), `ORDER_CREDIT_WITHDRAW` (moved to customer credit), `ORDER_CREDIT_RECOVERY`, `ORDER_CREDIT_RESTORED`, `CUSTOMER_CHECKOUT` (paid in the customer portal, and its refunds), `CUSTOMER_CHECKOUT_CHARGEBACK` (a lost dispute), or the gateway: `STRIPE`, `SQUARE`, `SQUARE_V2`, `PAYPAL`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`. A `REFUND_REVERSAL` carries its refund's gateway.","example":"ORDER_PAYMENT","type":["string","null"]},"amount":{"description":"Signed: negative for `DECREASE` (a 25.00 refund is `-25000`). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"credit_source":{"additionalProperties":true,"description":"Where a customer credit record came from. Always present; null on an order's records.","type":["object","null"]},"credit_source_payment_id":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: the payment the credit was issued from.","type":["string","null"]},"customer_id":{"description":"Always null on an order's records.","type":["string","null"]},"customer_payment_funding_id":{"description":"Customer Portal payment rows and credit applied from one only: the customer payment it belongs to.","type":["string","null"]},"customer_payment_sources":{"description":"Customer Portal rows only: the customer payments the money came from, each with `customer_payment_funding_id`, `funding_transaction_id`, `amount` (a decimal string) and `currency_iso`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"date":{"description":"When it was recorded (the payment date you sent). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"delete_blocked_reason":{"description":"Recorded payments (`ORDER_PAYMENT`) and card payments only: why Delete a payment or refund refuses it, or null when it can be deleted. `code` is `credit_issued_from_payment` (with `amount`, a decimal string) or `provider_payment_not_removable`; `message` is the refusal's text.","properties":{"amount":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}},"type":["object","null"]},"direction":{"description":"`INCREASE` (payments, payments from customer credit, `REFUND_REVERSAL`, `ORDER_CREDIT_RECOVERY`) or `DECREASE` (refunds and lost disputes, moves to customer credit, card voids, `ORDER_CREDIT_RESTORED`).","example":"INCREASE","type":"string"},"funding_payment_gateway":{"description":"Customer Portal rows only: the provider (`STRIPE`, `PAYPAL`, `SQUARE_V2`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`) or null.","type":["string","null"]},"has_open_hold":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and Customer Portal payments: true while a dispute (or, for a Customer Portal payment, a review) is open.","type":"boolean"},"id":{"example":"hAwWd7vPrqjuHD","type":"string"},"is_deletable":{"description":"false for card payments, Customer Portal payments, credit moves, card refunds, payments part of which moved to customer credit (and their refunds), refunds recorded against card payments, and the records YoPrint adds itself.","type":"boolean"},"is_editable":{"description":"true only for recorded payments (`ORDER_PAYMENT`).","type":"boolean"},"negative_credit_amount":{"description":"Card refunds only: credit issued from the payment that the customer had already spent and the refund took back anyway, leaving their credit negative (usually 0). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"payment_freeze_reason":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and direct Customer Portal payments: `chargeback_open` or `payment_under_review` while refunds and credit moves are refused, otherwise null.","type":["string","null"]},"payment_gateway":{"description":"The gateway (`STRIPE`, `SQUARE_V2` and so on) for card payments and refunds; for a Customer Portal payment its provider (null when unknown), and `CUSTOMER_CHECKOUT` or `CUSTOMER_CHECKOUT_CHARGEBACK` on its refunds and lost disputes; null otherwise.","type":["string","null"]},"payment_gateway_source":{"description":"Card payments and refunds only: Square v2's source type (for example `CARD`), otherwise null.","type":["string","null"]},"payment_method_id":{"description":"Refunds take their payment's; null for card payments and credit moves.","type":["string","null"]},"payment_notices":{"description":"List and Get only, on the same payments as `has_open_hold`: one notice per open dispute.","items":{"additionalProperties":true,"properties":{"amount":{"description":"The disputed amount as a decimal pair with `dp` 3, or null when the payment covered several orders.","type":["object","null"]},"code":{"description":"`dispute_open` or `dispute_under_review`; on Customer Portal payments also `payment_needs_attention`.","type":"string"},"currency_iso":{"type":"string"},"customer_payment_dispute_id":{"type":"string"},"customer_payment_funding_id":{"type":["string","null"]},"deadline_at":{"description":"When the response to the provider is due (ISO 8601), or null.","type":["string","null"]},"next_action":{"description":"For example `respond_to_provider` or `awaiting_provider`.","type":"string"},"provider":{"type":"string"},"provider_status":{"type":"string"},"stage":{"type":["string","null"]}},"type":"object"},"type":"array"},"recovery_kind":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: null on an order's records.","type":["string","null"]},"reference_description":{"type":["string","null"]},"reference_id":{"example":"CHK-1001","type":["string","null"]},"refundable_amount":{"description":"Payments only: the amount minus its refunds. Money moved to customer credit is not taken off here, though a refund can't include it. 0 for refunds, credit moves, payments from customer credit, and `CHARGE_IT_PRO` and `SQUARE` card payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"related_transaction":{"description":"For a refund, the `id` of the payment it refunds; for `REFUND_REVERSAL`, the payment; for `ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED`, the refund; null otherwise.","type":["string","null"]},"remove_unavailable":{"description":"Recorded payments only: `{ \"reason\": \"credit_issued\", \"amount\": <thousandths> }` when credit was issued from the payment, otherwise null.","type":["object","null"]},"restores_transaction_id":{"description":"`ORDER_CREDIT_RESTORED` only: the `ORDER_CREDIT_RECOVERY` record it gives back.","type":["string","null"]},"reversal_transaction_id":{"description":"Card refunds and `ORDER_CREDIT_RESTORED` only: the `REFUND_REVERSAL` record when the refund failed, or null.","type":["string","null"]},"reverses_transaction_id":{"description":"`REFUND_REVERSAL` only: the failed refund.","type":["string","null"]},"subtype":{"description":"`PAYMENT`, `REFUND` (also a lost dispute), `TRANSFER` (a customer credit move), `ORDER_PAYMENT_VOIDED_NEG_ADJ` (a voided card payment), `REFUND_REVERSAL` (a failed card refund given back to its payment), `ORDER_CREDIT_RECOVERY` (credit a refund took back) or `ORDER_CREDIT_RESTORED` (that credit given back when the refund failed).","example":"PAYMENT","type":"string"},"token":{"description":"The gateway's charge token; null for recorded payments.","type":["string","null"]},"type":{"description":"`MANUAL` (recorded in YoPrint) or `SYSTEM` (card and Customer Portal payments and refunds, Shopify payments, adjustments).","example":"MANUAL","type":"string"},"user_id":{"description":"The team member who recorded it.","type":["string","null"]},"voided":{"type":"boolean"}},"required":["id","amount"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Record a refund of a payment","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Refund at most the payment's amount minus its refunds and the credit already spent.","status":422,"when":"Too large an amount, an `amount` with decimals, no date, a draft order, a Shopify order deleted in Shopify, or credit linked to a Customer Portal payment (`customer_payment_parent_refund_required`)."},{"fix":"Use the payment's `id`.","status":500,"when":"`{id}` is a refund or a credit move, not a payment (`{\"message\": \"Server Error\"}`)."}],"group":"Invoices and payments","permission":"Any member of the team. The order must be published.","related":["v2_public_sales_order_payment_gateway_refund","v2_public_sales_order_payment_index"],"rules":["The refund can't be more than the payment's amount minus its refunds and minus the customer credit issued from it that the customer has already spent: \"Refund Amount greater than what payment can be refunded\". Shopify orders skip this check.","Only published orders: \"Payment Action Not Allowed - due to order internal state\".","`{id}` must be a payment: a refund or a credit move gives HTTP 500, and credit linked to a Customer Portal payment gives 422 `customer_payment_parent_refund_required` (\"Refund this credit through its original customer payment.\"). The sign of `amount` is ignored and 0 is accepted. An `amount` that is not a whole number is refused with 422 `validation_failed`: `error.fields.amount` says \"The amount must be a whole number of thousandths of the currency unit, such as 12500 for 12.50.\".","A payment synced from an integration (Shopify) is refused: \"Cannot refund external object from API.\""],"side_effects":["Updates the order's balance, invoices and customer totals, and sends the `payment.refund_issued` webhook.","The refunded money comes first from the payment's money not allocated to invoices, then from customer credit issued from this payment that is still unspent (which lowers the customer's credit, and adds an `ORDER_CREDIT_RECOVERY` record to the order), then from its invoices, newest first.","On a Customer Portal payment, its card surcharge on the invoice is reduced to match."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment/{payment_gateway}/pre_execute":{"post":{"description":"**Internal.** Built for YoPrint's own apps, not for integrations. Don't build on it.\n\nCard payments run through the team's connected payment gateway and charge real money. They are built for YoPrint's own payment screens, which collect the card with the provider's browser library: the card token or confirmation in the body comes from that library.\n\nStarts a card payment where the gateway needs a first step. `stripe` answers `payment_intent_id` and `client_secret` to confirm in the browser. `charge_it_pro` starts a Charge It Pro sale (on the team's terminal unless `skip_terminal` is true) and answers Charge It Pro's reply plus `internal_id`, which Charge a card needs. `square`, `square_v2`, `paypal` and `authorize_net` have no first step.\n\n`{payment_gateway}` is the gateway: `stripe`, `square`, `square_v2`, `paypal`, `authorize_net` or `charge_it_pro`. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_payment_gateway_pre_execute","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The payment gateway.","example":"stripe","in":"path","name":"payment_gateway","required":true,"schema":{"enum":["stripe","square","square_v2","paypal","authorize_net","charge_it_pro"],"example":"stripe","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"amount":85000},"schema":{"properties":{"amount":{"description":"The amount to charge. Send a whole number of thousandths: `12500` is 12.50. Required for every gateway.","type":"integer"},"internal_id":{"description":"`charge_it_pro` only, optional: a UUID to use as the pending payment's `internal_id`. Anything that isn't a UUID is refused with 422 \"The internal id must be a valid UUID.\"","format":"uuid","type":["string","null"]},"locking_token":{"description":"`charge_it_pro` only: your one-time token for this payment.","type":["string","null"]},"skip_terminal":{"description":"`charge_it_pro` only.","type":"boolean"},"surcharge":{"description":"Optional card surcharge included in `amount`, read only when the team charges one. It must not be negative; it is taken off `amount` for the minimum check.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["amount"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"client_secret":"client-secret-from-stripe","payment_intent_id":"pi_example_1001"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"What the gateway needs next; `stripe` shown. Other gateways return their own fields.","properties":{"client_secret":{"description":"`stripe`: the secret for Stripe.js.","type":"string"},"payment_intent_id":{"description":"`stripe`: the payment intent to confirm.","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Prepare a card payment","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Connect the gateway in Settings and send its fields.","status":422,"when":"`square_v2` without a Square v2 connection (`gateway_not_setup`), `square` when the team's old Square connection is switched off (`using_deprecated_old_square_gateway`), a missing gateway field, the provider refused (for example `payment_capture_failed`), or a Shopify order deleted in Shopify (`shopify_order_deleted_externally`)."},{"fix":"Use one of the gateway names.","status":404,"when":"An unknown `{payment_gateway}` or order (`page_not_found` or \"No query results for …\")."},{"fix":"Call Charge a card directly.","status":422,"when":"The gateway has no first step (`square`, `square_v2`, `paypal`, `authorize_net`): `payment_pre_execute_failed` \"Pre Execution Not Supported\"."},{"fix":"Send at least 1.00 (`1000`) in thousandths.","status":422,"when":"`amount` is missing or not a whole number (`validation_failed`), less than 1.00 after the surcharge (`payment_below_minimum`), or the surcharge is negative (`payment_surcharge_invalid`)."},{"fix":"Check the order id.","status":422,"when":"A valid order id that no longer exists: \"Cannot Start Transaction: Sales Order Not Found\"."}],"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_sales_order_payment_gateway_execute"],"rules":["`amount` is required for every gateway, as a whole number of thousandths (422 `validation_failed` otherwise). This is checked before the gateway is: for `square`, `square_v2`, `paypal` and `authorize_net` a missing `amount` is 422 `validation_failed`, not \"Pre Execution Not Supported\".","The amount to charge, less any `surcharge`, must be at least 1.00 in the order's currency: otherwise 422 `payment_below_minimum` (\"Enter at least USD 1.00.\", with the order's currency code), and `error.payment_amount_policy` gives `currency`, `minimum_payment` (a decimal pair, `{ \"value\": \"1000\", \"dp\": 3 }`) and `minimum_remaining_balance` (null). A negative `surcharge` is 422 `payment_surcharge_invalid` (\"The payment surcharge cannot be negative.\"). The provider's own limits still apply.","`stripe` also checks the amount against its own minimum and maximum charge for the currency.","The order's state is not checked here."],"side_effects":["`stripe`: creates a payment intent with the provider; no money moves yet. `charge_it_pro`: starts a sale with Charge It Pro."],"status":"internal"},"x-internal":true}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment/{payment_reference}":{"delete":{"description":"Deletes a payment or refund record from the order. Card payments can't be deleted: refund them, or move their money to customer credit. `{payment_reference}` is the record's `id`. The answer has no data. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_manual_payment_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The payment or refund's `id` (a hash id).","example":"hAwWd7vPrqjuHD","in":"path","name":"payment_reference","required":true,"schema":{"example":"hAwWd7vPrqjuHD","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"description":"No data.","type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a payment or refund","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Record a refund instead.","status":422,"when":"A draft order, or a record that can't be deleted (`credit_issued_from_payment`, `provider_payment_not_removable`, `customer_payment_source_immutable`; see rules)."}],"group":"Invoices and payments","permission":"Any member of the team. The order must be published.","related":["v2_public_sales_order_payment_index"],"rules":["Only published orders: \"Payment Action Not Allowed - due to order internal state\".","A recorded payment part of which was moved to customer credit is refused with 422 `credit_issued_from_payment` (\"25.00 of credit was issued from this payment, so it can't be removed.\"), even after that credit is applied back. A refund of such a payment, and a refund recorded against a card payment, get \"Cannot Delete Transaction\". A payment's `delete_blocked_reason` says in advance.","Card payments are refused with 422 `provider_payment_not_removable` (\"Payments made through a payment provider can't be removed. Use Issue credit or Refund instead.\"); a voided one gets \"Transaction Already Processed\".","A Customer Portal payment, or credit linked to one, can't be changed here: 422 `customer_payment_source_immutable` (\"This credit is linked to its original customer payment and cannot be edited or deleted.\").","Payments from customer credit, moves to customer credit and card refunds can't be deleted: 422 with a message starting \"This Middleware\".","A record synced from an integration (Shopify) is refused: \"Cannot delete external object from API.\""],"side_effects":["Updates the order's balance, invoices and customer totals; deleting a payment removes payment links left empty."]}},"get":{"description":"Returns one money record of the order (a payment, refund or credit move), with the same fields as the list, dispute fields included. `{payment_reference}` is its `id`. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_payment_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The payment's `id` (a hash id).","example":"hAwWd7vPrqjuHD","in":"path","name":"payment_reference","required":true,"schema":{"example":"hAwWd7vPrqjuHD","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"action":"ORDER_PAYMENT","amount":75000,"credit_source":null,"customer_id":null,"date":"2026-11-03T00:00:00+00:00","delete_blocked_reason":null,"direction":"INCREASE","id":"hAwWd7vPrqjuHD","is_deletable":true,"is_editable":true,"order_id":"V4keXwwxMQyXw7","payment_gateway":null,"payment_method_id":"Kst6z3ULXLBrmN","reference_description":null,"reference_id":"CHK-1001","refundable_amount":75000,"related_transaction":null,"remove_unavailable":null,"subtype":"PAYMENT","token":null,"type":"MANUAL","user_id":"PydH0WtBhSeiNU","voided":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A payment, refund or credit move. Customer Portal rows (`action` `CUSTOMER_CHECKOUT`, and credit applied from a Customer Portal payment) also carry `customer_payment_checkout_id`, `funding_transaction_id`, `customer_payment_application_id`, `customer_payment_source_kind`, `is_external_cash_movement` and `currency_iso`.","properties":{"action":{"description":"`ORDER_PAYMENT`, `ORDER_REFUND`, `ORDER_CREDIT_DEPOSIT` (paid from customer credit), `ORDER_CREDIT_WITHDRAW` (moved to customer credit), `ORDER_CREDIT_RECOVERY`, `ORDER_CREDIT_RESTORED`, `CUSTOMER_CHECKOUT` (paid in the customer portal, and its refunds), `CUSTOMER_CHECKOUT_CHARGEBACK` (a lost dispute), or the gateway: `STRIPE`, `SQUARE`, `SQUARE_V2`, `PAYPAL`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`. A `REFUND_REVERSAL` carries its refund's gateway.","example":"ORDER_PAYMENT","type":["string","null"]},"amount":{"description":"Signed: negative for `DECREASE` (a 25.00 refund is `-25000`). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"credit_source":{"additionalProperties":true,"description":"Where a customer credit record came from. Always present; null on an order's records.","type":["object","null"]},"credit_source_payment_id":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: the payment the credit was issued from.","type":["string","null"]},"customer_id":{"description":"Always null on an order's records.","type":["string","null"]},"customer_payment_funding_id":{"description":"Customer Portal payment rows and credit applied from one only: the customer payment it belongs to.","type":["string","null"]},"customer_payment_sources":{"description":"Customer Portal rows only: the customer payments the money came from, each with `customer_payment_funding_id`, `funding_transaction_id`, `amount` (a decimal string) and `currency_iso`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"date":{"description":"When it was recorded (the payment date you sent). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"delete_blocked_reason":{"description":"Recorded payments (`ORDER_PAYMENT`) and card payments only: why Delete a payment or refund refuses it, or null when it can be deleted. `code` is `credit_issued_from_payment` (with `amount`, a decimal string) or `provider_payment_not_removable`; `message` is the refusal's text.","properties":{"amount":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}},"type":["object","null"]},"direction":{"description":"`INCREASE` (payments, payments from customer credit, `REFUND_REVERSAL`, `ORDER_CREDIT_RECOVERY`) or `DECREASE` (refunds and lost disputes, moves to customer credit, card voids, `ORDER_CREDIT_RESTORED`).","example":"INCREASE","type":"string"},"funding_payment_gateway":{"description":"Customer Portal rows only: the provider (`STRIPE`, `PAYPAL`, `SQUARE_V2`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`) or null.","type":["string","null"]},"has_open_hold":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and Customer Portal payments: true while a dispute (or, for a Customer Portal payment, a review) is open.","type":"boolean"},"id":{"example":"hAwWd7vPrqjuHD","type":"string"},"is_deletable":{"description":"false for card payments, Customer Portal payments, credit moves, card refunds, payments part of which moved to customer credit (and their refunds), refunds recorded against card payments, and the records YoPrint adds itself.","type":"boolean"},"is_editable":{"description":"true only for recorded payments (`ORDER_PAYMENT`).","type":"boolean"},"negative_credit_amount":{"description":"Card refunds only: credit issued from the payment that the customer had already spent and the refund took back anyway, leaving their credit negative (usually 0). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"payment_freeze_reason":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and direct Customer Portal payments: `chargeback_open` or `payment_under_review` while refunds and credit moves are refused, otherwise null.","type":["string","null"]},"payment_gateway":{"description":"The gateway (`STRIPE`, `SQUARE_V2` and so on) for card payments and refunds; for a Customer Portal payment its provider (null when unknown), and `CUSTOMER_CHECKOUT` or `CUSTOMER_CHECKOUT_CHARGEBACK` on its refunds and lost disputes; null otherwise.","type":["string","null"]},"payment_gateway_source":{"description":"Card payments and refunds only: Square v2's source type (for example `CARD`), otherwise null.","type":["string","null"]},"payment_method_id":{"description":"Refunds take their payment's; null for card payments and credit moves.","type":["string","null"]},"payment_notices":{"description":"List and Get only, on the same payments as `has_open_hold`: one notice per open dispute.","items":{"additionalProperties":true,"properties":{"amount":{"description":"The disputed amount as a decimal pair with `dp` 3, or null when the payment covered several orders.","type":["object","null"]},"code":{"description":"`dispute_open` or `dispute_under_review`; on Customer Portal payments also `payment_needs_attention`.","type":"string"},"currency_iso":{"type":"string"},"customer_payment_dispute_id":{"type":"string"},"customer_payment_funding_id":{"type":["string","null"]},"deadline_at":{"description":"When the response to the provider is due (ISO 8601), or null.","type":["string","null"]},"next_action":{"description":"For example `respond_to_provider` or `awaiting_provider`.","type":"string"},"provider":{"type":"string"},"provider_status":{"type":"string"},"stage":{"type":["string","null"]}},"type":"object"},"type":"array"},"recovery_kind":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: null on an order's records.","type":["string","null"]},"reference_description":{"type":["string","null"]},"reference_id":{"example":"CHK-1001","type":["string","null"]},"refundable_amount":{"description":"Payments only: the amount minus its refunds. Money moved to customer credit is not taken off here, though a refund can't include it. 0 for refunds, credit moves, payments from customer credit, and `CHARGE_IT_PRO` and `SQUARE` card payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"related_transaction":{"description":"For a refund, the `id` of the payment it refunds; for `REFUND_REVERSAL`, the payment; for `ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED`, the refund; null otherwise.","type":["string","null"]},"remove_unavailable":{"description":"Recorded payments only: `{ \"reason\": \"credit_issued\", \"amount\": <thousandths> }` when credit was issued from the payment, otherwise null.","type":["object","null"]},"restores_transaction_id":{"description":"`ORDER_CREDIT_RESTORED` only: the `ORDER_CREDIT_RECOVERY` record it gives back.","type":["string","null"]},"reversal_transaction_id":{"description":"Card refunds and `ORDER_CREDIT_RESTORED` only: the `REFUND_REVERSAL` record when the refund failed, or null.","type":["string","null"]},"reverses_transaction_id":{"description":"`REFUND_REVERSAL` only: the failed refund.","type":["string","null"]},"subtype":{"description":"`PAYMENT`, `REFUND` (also a lost dispute), `TRANSFER` (a customer credit move), `ORDER_PAYMENT_VOIDED_NEG_ADJ` (a voided card payment), `REFUND_REVERSAL` (a failed card refund given back to its payment), `ORDER_CREDIT_RECOVERY` (credit a refund took back) or `ORDER_CREDIT_RESTORED` (that credit given back when the refund failed).","example":"PAYMENT","type":"string"},"token":{"description":"The gateway's charge token; null for recorded payments.","type":["string","null"]},"type":{"description":"`MANUAL` (recorded in YoPrint) or `SYSTEM` (card and Customer Portal payments and refunds, Shopify payments, adjustments).","example":"MANUAL","type":"string"},"user_id":{"description":"The team member who recorded it.","type":["string","null"]},"voided":{"type":"boolean"}},"required":["id","amount"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get one payment of a sales order","tags":["Payments"],"x-yoprint-docs":{"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_sales_order_payment_index"]}},"post":{"description":"**Internal.** Built for YoPrint's own apps, not for integrations. Don't build on it.\n\nCard payments run through the team's connected payment gateway and charge real money. They are built for YoPrint's own payment screens, which collect the card with the provider's browser library: the card token or confirmation in the body comes from that library.\n\nCompletes a card payment and records it on the order. `charge_it_pro` answers `status` `pending` with `poll_id` (its `internal_id`) and `poll_token`, and YoPrint records the payment when the sale finishes, checking the provider in the background. Every other gateway records the payment now and answers `status` `success`, with `poll_id` and `poll_token` as empty strings.\n\nThe path segment shown as `{payment_reference}` is the gateway name here. `{payment_gateway}` is the gateway: `stripe`, `square`, `square_v2`, `paypal`, `authorize_net` or `charge_it_pro`. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_payment_gateway_execute","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The payment gateway (this path segment is a gateway name here, not a payment id).","example":"stripe","in":"path","name":"payment_reference","required":true,"schema":{"enum":["stripe","square","square_v2","paypal","authorize_net","charge_it_pro"],"example":"stripe","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"locking_token":"pay-1001-a","order_id":"V4keXwwxMQyXw7","payment_intent_id":"pi_example_1001"},"schema":{"properties":{"amount":{"description":"The amount to charge. Send a whole number of thousandths: `12500` is 12.50. Required for `square`, `square_v2` (not with `square_token` `cash`), `paypal`, and `authorize_net`; checked before the provider is called. `stripe` and `charge_it_pro` take the amount from Prepare a card payment.","type":"integer"},"authorizenet_token":{"description":"`authorize_net`: the card token.","type":"string"},"internal_id":{"description":"`charge_it_pro`: the pending payment from Prepare.","type":"string"},"locking_token":{"description":"Your one-time token for this payment attempt. Required.","type":"string"},"order_id":{"description":"The order's `id` again. Required.","type":"string"},"payment_intent_id":{"description":"`stripe`: the confirmed payment intent from Prepare.","type":"string"},"paypal_order_id":{"description":"`paypal`: the approved PayPal order.","type":"string"},"square_token":{"description":"`square`: the card token.","type":"string"},"surcharge":{"description":"Optional card surcharge included in `amount`, when the team charges one; the order must have an invoice. It must not be negative.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["locking_token","order_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"poll_id":"","poll_token":"","status":"success"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"poll_id":{"description":"For `pending`: the pending payment's id.","type":"string"},"poll_token":{"description":"For `pending`: a token for polling.","type":"string"},"status":{"description":"`success`, or `pending` while the provider finishes.","example":"success","type":"string"}},"required":["status"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Charge a card through the payment gateway","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Connect the gateway in Settings and send its fields.","status":422,"when":"`square_v2` without a Square v2 connection (`gateway_not_setup`), `square` when the team's old Square connection is switched off (`using_deprecated_old_square_gateway`), a missing gateway field, the provider refused (for example `payment_capture_failed`), or a Shopify order deleted in Shopify (`shopify_order_deleted_externally`)."},{"fix":"Use one of the gateway names.","status":404,"when":"An unknown `{payment_gateway}` or order (`page_not_found` or \"No query results for …\")."},{"fix":"Send at least 1.00 (`1000`) in thousandths.","status":422,"when":"`amount` is missing or not a whole number (`validation_failed`), less than 1.00 after the surcharge (`payment_below_minimum`), or the surcharge is negative (`payment_surcharge_invalid`). Nothing is charged."}],"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_sales_order_payment_gateway_pre_execute","v2_public_sales_order_payment_gateway_refund"],"rules":["`locking_token` and `order_id` are required, plus the gateway's own field.","For `square`, `square_v2` (except `square_token` `cash`), `paypal` and `authorize_net`, `amount` is checked before the provider is called, so nothing is charged when it fails: it is required as a whole number of thousandths. The amount to charge, less any `surcharge`, must be at least 1.00 in the order's currency: otherwise 422 `payment_below_minimum` (\"Enter at least USD 1.00.\", with the order's currency code), and `error.payment_amount_policy` gives `currency`, `minimum_payment` (a decimal pair, `{ \"value\": \"1000\", \"dp\": 3 }`) and `minimum_remaining_balance` (null). A negative `surcharge` is 422 `payment_surcharge_invalid` (\"The payment surcharge cannot be negative.\"). The provider's own limits still apply.","`square_v2` records the payment only when Square answers `COMPLETED`; any other Square status is 422 `payment_capture_failed`.","`charge_it_pro` refuses a pending payment that isn't this order's, or that belongs to a Customer Portal payment: 422 `payment_capture_failed` \"Payment Failure: We cannot find the pending payment record\".","A payment the provider already recorded is refused: \"Transaction Already Processed\".","The order must be published, but YoPrint checks only when it records the payment, after the provider has charged: on a draft order the charge goes through and the answer is 422 \"Payment Action Not Allowed - due to order internal state\". Publish first."],"side_effects":["`square`, `square_v2`, `authorize_net` and `paypal` capture the charge here (real money moves); for `stripe` the browser already confirmed the charge, and this call checks and records it.","Records the payment and updates the order, invoices and customer totals. Customer Portal pages the order's customer has open refresh.","Sends the `payment_received.any_amount` webhook; also `payment_received.deposit_amount` when the order's paid total now exactly equals its deposit amount, and `payment_received.full_amount` when the balance due (invoiced total minus paid) is now exactly 0. A payment that goes past the deposit, or overpays, sends neither of those two.","A dispute the provider later reports on a `stripe`, `paypal` or `square_v2` payment freezes it: refunds and moves to customer credit are refused until the provider decides (see Refund a card payment)."],"status":"internal"},"x-internal":true},"put":{"description":"Changes a recorded payment's date, references and, for a payment recorded in YoPrint, its payment method. The amount can't change: delete the payment and record it again. `{payment_reference}` is the payment's `id`. The answer is the payment. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_manual_payment_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The payment's `id` (a hash id).","example":"hAwWd7vPrqjuHD","in":"path","name":"payment_reference","required":true,"schema":{"example":"hAwWd7vPrqjuHD","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"date":"2026-11-04","reference_id":"CHK-1002"},"schema":{"properties":{"amount":{"description":"Optional. If you send it, it must equal the record's own `amount` in thousandths (negative for refunds and credit moves); anything else is refused.","type":"integer"},"created_at":{"format":"date","type":"string"},"date":{"description":"The payment date (ISO 8601). Send `date` or `created_at`.","format":"date","type":"string"},"payment_method_id":{"description":"Recorded payments (`ORDER_PAYMENT`) only: one of the team's payment methods, or null to clear it. Ignored on other records.","type":["string","null"]},"reference_description":{"description":"A note; null clears it.","type":["string","null"]},"reference_id":{"description":"Your reference; null clears it.","type":["string","null"]}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"action":"ORDER_PAYMENT","amount":75000,"credit_source":null,"customer_id":null,"date":"2026-11-04T00:00:00+00:00","delete_blocked_reason":null,"direction":"INCREASE","id":"hAwWd7vPrqjuHD","is_deletable":true,"is_editable":true,"order_id":"V4keXwwxMQyXw7","payment_gateway":null,"payment_method_id":"Kst6z3ULXLBrmN","reference_description":null,"reference_id":"CHK-1002","refundable_amount":75000,"related_transaction":null,"remove_unavailable":null,"subtype":"PAYMENT","token":null,"type":"MANUAL","user_id":"PydH0WtBhSeiNU","voided":false},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A payment, refund or credit move. Customer Portal rows (`action` `CUSTOMER_CHECKOUT`, and credit applied from a Customer Portal payment) also carry `customer_payment_checkout_id`, `funding_transaction_id`, `customer_payment_application_id`, `customer_payment_source_kind`, `is_external_cash_movement` and `currency_iso`.","properties":{"action":{"description":"`ORDER_PAYMENT`, `ORDER_REFUND`, `ORDER_CREDIT_DEPOSIT` (paid from customer credit), `ORDER_CREDIT_WITHDRAW` (moved to customer credit), `ORDER_CREDIT_RECOVERY`, `ORDER_CREDIT_RESTORED`, `CUSTOMER_CHECKOUT` (paid in the customer portal, and its refunds), `CUSTOMER_CHECKOUT_CHARGEBACK` (a lost dispute), or the gateway: `STRIPE`, `SQUARE`, `SQUARE_V2`, `PAYPAL`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`. A `REFUND_REVERSAL` carries its refund's gateway.","example":"ORDER_PAYMENT","type":["string","null"]},"amount":{"description":"Signed: negative for `DECREASE` (a 25.00 refund is `-25000`). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"credit_source":{"additionalProperties":true,"description":"Where a customer credit record came from. Always present; null on an order's records.","type":["object","null"]},"credit_source_payment_id":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: the payment the credit was issued from.","type":["string","null"]},"customer_id":{"description":"Always null on an order's records.","type":["string","null"]},"customer_payment_funding_id":{"description":"Customer Portal payment rows and credit applied from one only: the customer payment it belongs to.","type":["string","null"]},"customer_payment_sources":{"description":"Customer Portal rows only: the customer payments the money came from, each with `customer_payment_funding_id`, `funding_transaction_id`, `amount` (a decimal string) and `currency_iso`.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"date":{"description":"When it was recorded (the payment date you sent). ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"delete_blocked_reason":{"description":"Recorded payments (`ORDER_PAYMENT`) and card payments only: why Delete a payment or refund refuses it, or null when it can be deleted. `code` is `credit_issued_from_payment` (with `amount`, a decimal string) or `provider_payment_not_removable`; `message` is the refusal's text.","properties":{"amount":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}},"type":["object","null"]},"direction":{"description":"`INCREASE` (payments, payments from customer credit, `REFUND_REVERSAL`, `ORDER_CREDIT_RECOVERY`) or `DECREASE` (refunds and lost disputes, moves to customer credit, card voids, `ORDER_CREDIT_RESTORED`).","example":"INCREASE","type":"string"},"funding_payment_gateway":{"description":"Customer Portal rows only: the provider (`STRIPE`, `PAYPAL`, `SQUARE_V2`, `AUTHORIZE_NET`, `CHARGE_IT_PRO`) or null.","type":["string","null"]},"has_open_hold":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and Customer Portal payments: true while a dispute (or, for a Customer Portal payment, a review) is open.","type":"boolean"},"id":{"example":"hAwWd7vPrqjuHD","type":"string"},"is_deletable":{"description":"false for card payments, Customer Portal payments, credit moves, card refunds, payments part of which moved to customer credit (and their refunds), refunds recorded against card payments, and the records YoPrint adds itself.","type":"boolean"},"is_editable":{"description":"true only for recorded payments (`ORDER_PAYMENT`).","type":"boolean"},"negative_credit_amount":{"description":"Card refunds only: credit issued from the payment that the customer had already spent and the refund took back anyway, leaving their credit negative (usually 0). Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":["string","null"]},"payment_freeze_reason":{"description":"List and Get only, on `STRIPE`, `PAYPAL` and `SQUARE_V2` card payments and direct Customer Portal payments: `chargeback_open` or `payment_under_review` while refunds and credit moves are refused, otherwise null.","type":["string","null"]},"payment_gateway":{"description":"The gateway (`STRIPE`, `SQUARE_V2` and so on) for card payments and refunds; for a Customer Portal payment its provider (null when unknown), and `CUSTOMER_CHECKOUT` or `CUSTOMER_CHECKOUT_CHARGEBACK` on its refunds and lost disputes; null otherwise.","type":["string","null"]},"payment_gateway_source":{"description":"Card payments and refunds only: Square v2's source type (for example `CARD`), otherwise null.","type":["string","null"]},"payment_method_id":{"description":"Refunds take their payment's; null for card payments and credit moves.","type":["string","null"]},"payment_notices":{"description":"List and Get only, on the same payments as `has_open_hold`: one notice per open dispute.","items":{"additionalProperties":true,"properties":{"amount":{"description":"The disputed amount as a decimal pair with `dp` 3, or null when the payment covered several orders.","type":["object","null"]},"code":{"description":"`dispute_open` or `dispute_under_review`; on Customer Portal payments also `payment_needs_attention`.","type":"string"},"currency_iso":{"type":"string"},"customer_payment_dispute_id":{"type":"string"},"customer_payment_funding_id":{"type":["string","null"]},"deadline_at":{"description":"When the response to the provider is due (ISO 8601), or null.","type":["string","null"]},"next_action":{"description":"For example `respond_to_provider` or `awaiting_provider`.","type":"string"},"provider":{"type":"string"},"provider_status":{"type":"string"},"stage":{"type":["string","null"]}},"type":"object"},"type":"array"},"recovery_kind":{"description":"`ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED` only: null on an order's records.","type":["string","null"]},"reference_description":{"type":["string","null"]},"reference_id":{"example":"CHK-1001","type":["string","null"]},"refundable_amount":{"description":"Payments only: the amount minus its refunds. Money moved to customer credit is not taken off here, though a refund can't include it. 0 for refunds, credit moves, payments from customer credit, and `CHARGE_IT_PRO` and `SQUARE` card payments. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"related_transaction":{"description":"For a refund, the `id` of the payment it refunds; for `REFUND_REVERSAL`, the payment; for `ORDER_CREDIT_RECOVERY` and `ORDER_CREDIT_RESTORED`, the refund; null otherwise.","type":["string","null"]},"remove_unavailable":{"description":"Recorded payments only: `{ \"reason\": \"credit_issued\", \"amount\": <thousandths> }` when credit was issued from the payment, otherwise null.","type":["object","null"]},"restores_transaction_id":{"description":"`ORDER_CREDIT_RESTORED` only: the `ORDER_CREDIT_RECOVERY` record it gives back.","type":["string","null"]},"reversal_transaction_id":{"description":"Card refunds and `ORDER_CREDIT_RESTORED` only: the `REFUND_REVERSAL` record when the refund failed, or null.","type":["string","null"]},"reverses_transaction_id":{"description":"`REFUND_REVERSAL` only: the failed refund.","type":["string","null"]},"subtype":{"description":"`PAYMENT`, `REFUND` (also a lost dispute), `TRANSFER` (a customer credit move), `ORDER_PAYMENT_VOIDED_NEG_ADJ` (a voided card payment), `REFUND_REVERSAL` (a failed card refund given back to its payment), `ORDER_CREDIT_RECOVERY` (credit a refund took back) or `ORDER_CREDIT_RESTORED` (that credit given back when the refund failed).","example":"PAYMENT","type":"string"},"token":{"description":"The gateway's charge token; null for recorded payments.","type":["string","null"]},"type":{"description":"`MANUAL` (recorded in YoPrint) or `SYSTEM` (card and Customer Portal payments and refunds, Shopify payments, adjustments).","example":"MANUAL","type":"string"},"user_id":{"description":"The team member who recorded it.","type":["string","null"]},"voided":{"type":"boolean"}},"required":["id","amount"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a recorded payment","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Send `date`.","status":422,"when":"No date was sent, an unknown payment method, or a Shopify order deleted in Shopify (`shopify_order_deleted_externally`)."},{"fix":"Leave `amount` out, or delete the payment and record it again.","status":422,"when":"A different `amount` (`payment_amount_not_editable`)."},{"fix":"Change it from the customer payment in the web app.","status":422,"when":"A Customer Portal payment or credit linked to one (`customer_payment_source_immutable`)."},{"fix":"Change it in the integration.","status":422,"when":"The record was synced from an integration such as Shopify (`validation_error`, \"Cannot update external object from API.\")."}],"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_sales_order_payment_show"],"rules":["`date` or `created_at` is required; `date` wins.","Only `reference_id`, `reference_description`, the date and, on a recorded payment, `payment_method_id` change; other fields are ignored.","An `amount` different from the record's own is refused: 422 `payment_amount_not_editable` (\"A payment's amount can't be edited. Remove the payment and add it again with the right amount.\"). Sending the same amount is fine.","A Customer Portal payment, or credit linked to one, can't be changed here: 422 `customer_payment_source_immutable` (\"This credit is linked to its original customer payment and cannot be edited or deleted.\").","Works on any other record of the order, whatever its `is_editable` says, and on drafts too, except records synced from an integration (Shopify): \"Cannot update external object from API.\" On customer credit moves only `reference_description` changes."],"side_effects":["When a recorded payment's date, method, reference or note really changes: the change is kept in the payment's history, and on a team connected to QuickBooks the next sync writes the new date and the reference and note (as the memo) to the same QuickBooks payment. The payment method isn't sent to QuickBooks."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment_gateway_refund/{id}":{"put":{"description":"Refunds a card payment through the gateway that took it: real money goes back to the card. `{id}` is the card payment's `id`; card payments the customer made in the customer portal can be refunded here too. Send a whole number of thousandths: `12500` is 12.50. See [Money and quantities](/concepts/money-and-quantities/). Always send `amount`: without it the call fails with HTTP 500 before the gateway is called. The answer has no data. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_payment_gateway_refund","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The card payment's `id` (a hash id).","example":"JMQ642WFe4sANJ","in":"path","name":"id","required":true,"schema":{"example":"JMQ642WFe4sANJ","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"amount":25000,"locking_token":"refund-1001-a"},"schema":{"properties":{"amount":{"description":"How much to refund, in thousandths. Required in practice: see above.","minimum":1,"type":"integer"},"intent":{"description":"Accepted and not used: the refund is the same whatever you send. Any other value is refused with 422.","enum":["provider_refund_only","cancel_and_return_credit","return_to_source_credit"],"type":"string"},"locking_token":{"description":"Your one-time token for this refund. Required.","type":"string"}},"required":["locking_token","amount"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"description":"No data.","type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Refund a card payment through the gateway","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Check the payment, or refund it in the provider's dashboard and record it with Record a refund.","status":422,"when":"Another order's payment, a record that isn't a card payment, a Charge It Pro payment or a Customer Portal payment its provider can't refund (`refund_failed`); a payment from Customer Portal credit (`customer_payment_parent_refund_required`)."},{"fix":"Read the message; check the payment in the provider's dashboard.","status":422,"when":"The provider refused (`refund_processing_failed`). For Stripe the message says why (for example a disputed charge, or more than is left to refund) and `error.data` has `provider` `stripe` and `provider_error_code`."},{"fix":"Wait for the provider's decision, then try again.","status":422,"when":"A payment is frozen by an open dispute or review (`customer_payment_disputed_funds_unavailable` or `invoice_payment_funding_withheld`, with `error.reason`)."},{"fix":"Wait for settlement, or refund it in the provider's dashboard.","status":422,"when":"An Authorize.Net payment that hasn't settled (`invoice_payment_refund_requires_settlement`, `invoice_payment_refund_provider_state_invalid`), or the Customer Portal payment's provider account changed (`invoice_payment_provider_identity_mismatch`)."},{"fix":"Refund at most the payment's `refundable_amount` plus unspent credit issued from it.","status":422,"when":"More than the payment can refund (`validation_error`, \"Refund Amount greater than what payment can be refunded\"). This is found after the provider refunded: check the provider before you do anything else."},{"fix":"Send `amount` and a card payment `id` (`payment_gateway` not null).","status":500,"when":"No `amount`, an id that is no record of the team, or a payment through the old Square connection (`{\"message\": \"Server Error\"}`)."}],"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_sales_order_manual_payment_refund"],"rules":["The payment must be a card payment of this order: \"Payment does not belong to the requested sales order\" (`refund_failed`). Another kind of record of this order gets \"This transaction does not support a provider refund.\" (`refund_failed`), and a payment from customer credit that came from a Customer Portal payment gets 422 `customer_payment_parent_refund_required` (\"Open the original customer payment to review the source allocation and request a refund.\").","The gateway must support refunds: Charge It Pro payments get \"Payment Gateway Refund is not supported\" (`refund_failed`). A Customer Portal payment can be refunded only when it went through `stripe`, `paypal`, `square_v2` or `authorize_net`: otherwise \"This Customer Portal payment does not support a provider refund.\" (`refund_failed`).","A payment is frozen while a dispute its provider reported is open or under review, or while a Customer Portal payment has an open review case. Its money can't then be refunded through YoPrint or moved to customer credit: 422 `customer_payment_disputed_funds_unavailable` (\"A dispute is open on this payment. Refunds and Issue credit are paused until <provider> decides.\") or `invoice_payment_funding_withheld` (\"This payment has an open case to review. Refunds and Issue credit are paused until it's settled.\"), with `error.reason` (`chargeback_open` or `payment_under_review`), `error.provider` and `error.provider_label`. A payment's `payment_freeze_reason` shows it.","The amount can be at most what the payment can still refund plus the customer credit issued from it that is still unspent: \"Refund Amount greater than what payment can be refunded\" (`validation_error`). This is checked when the refund is recorded, after the provider refunded.","Authorize.Net refunds only settled payments: 422 `invoice_payment_refund_requires_settlement` (\"Wait until Authorize.Net settles this payment before refunding it.\") while it settles, and `invoice_payment_refund_provider_state_invalid` (with `error.provider_status`) in any other state.","The order must be published, but that is checked when the refund is recorded, after the provider refunded."],"side_effects":["Refunds the card through the provider.","Records the refund (as made by the API key's user) and sends the `payment.refund_issued` webhook.","Customer credit issued from this payment and still unspent is taken back first, which lowers the customer's credit; the order gets an `ORDER_CREDIT_RECOVERY` record for it.","On a Customer Portal payment, its card surcharge on the invoice is reduced to match.","If the provider later reports that the refund failed, the refund stays and a `REFUND_REVERSAL` record gives the payment its money back; the order's history notes it.","Customer Portal pages the order's customer has open refresh."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment_link":{"get":{"description":"A payment link (Allocations in the web app) records which invoices a payment pays: it splits payments received on the order across the order's invoices. It is not a link the customer pays through.\n\nReturns the order's payment links with their totals (`total` is a decimal pair, usually with `dp` 4: 50.00 is `{ \"value\": 500000, \"dp\": 4 }`). A Shopify order deleted in Shopify answers 422 `shopify_order_deleted_externally`. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_payment_link_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"created_at":"2026-11-03T09:00:00+00:00","id":"SmIWUp2A3mG3bA","note":null,"order_id":"V4keXwwxMQyXw7","total":{"dp":4,"value":500000},"updated_at":"2026-11-03T09:00:00+00:00"}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"The order's payment links, not paginated.","items":{"additionalProperties":true,"description":"A payment link.","properties":{"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"SmIWUp2A3mG3bA","type":"string"},"note":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"total":{"description":"Total this link allocates. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]}},"required":["id","order_id","total"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the payment links of a sales order","tags":["Payment links"],"x-yoprint-docs":{"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_sales_order_payment_link_create","v2_public_payment_link_show"]}},"post":{"description":"A payment link (Allocations in the web app) records which invoices a payment pays: it splits payments received on the order across the order's invoices. It is not a link the customer pays through.\n\nAllocates amounts of the order's payments to its invoices. Each entry in `unallocated_transactions` names a payment (`transaction_id`), an invoice of this order (`invoice_id`) and an amount (`total.value`, in thousandths: `12500` is 12.50; `dp` is ignored).\n\nThe answer is the payment link. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_payment_link_create","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"note":"Split deposit","unallocated_transactions":[{"action":"create","invoice_id":"QRbvVd2ZKcvSTB","total":{"dp":3,"value":50000},"transaction_id":"hAwWd7vPrqjuHD"}]},"schema":{"properties":{"note":{"type":"string"},"unallocated_transactions":{"items":{"properties":{"action":{"const":"create","type":"string"},"invoice_id":{"description":"An invoice of this order.","type":"string"},"total":{"properties":{"dp":{"description":"Ignored: `value` is always read as thousandths.","type":"integer"},"value":{"description":"Send a whole number of thousandths: `12500` is 12.50. YoPrint always reads this value as thousandths, whatever `dp` says.","type":"integer"}},"required":["value"],"type":"object"},"transaction_id":{"description":"A payment of this order, from the template.","type":"string"}},"required":["action","transaction_id","invoice_id"],"type":"object"},"minItems":1,"type":"array"}},"required":["unallocated_transactions"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"allocated_transactions":[{"id":"I9uyv9BtQiReQ6","invoice_id":"QRbvVd2ZKcvSTB","state":"existing","total":{"dp":3,"value":50000},"transaction_id":"hAwWd7vPrqjuHD","unallocated_amount":{"dp":3,"value":0}}],"created_at":"2026-11-03T09:00:00+00:00","id":"SmIWUp2A3mG3bA","note":"Split deposit","order_id":"V4keXwwxMQyXw7","total":{"dp":4,"value":500000},"updated_at":"2026-11-03T09:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"The payment link, as Get a payment link returns it.","properties":{"allocated_transactions":{"description":"One entry per payment and invoice.","items":{"additionalProperties":true,"properties":{"id":{"example":"I9uyv9BtQiReQ6","type":"string"},"invoice_id":{"example":"QRbvVd2ZKcvSTB","type":"string"},"state":{"description":"Always `existing`.","example":"existing","type":"string"},"total":{"description":"Allocated to this invoice. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 50000, \"dp\": 3 }` is 50.00). Fixed at 3 decimal places (`dp` 3). Read `dp` every time: it can differ between fields and records.","example":{"dp":3,"value":50000},"properties":{"dp":{"const":3,"type":"integer"},"value":{"type":["integer","string"]}},"required":["value","dp"],"type":"object"},"transaction_id":{"description":"The payment's `id`.","example":"hAwWd7vPrqjuHD","type":"string"},"unallocated_amount":{"description":"What the payment still has to allocate. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 50000, \"dp\": 3 }` is 50.00). Fixed at 3 decimal places (`dp` 3). Read `dp` every time: it can differ between fields and records.","example":{"dp":3,"value":50000},"properties":{"dp":{"const":3,"type":"integer"},"value":{"type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"type":"object"},"type":"array"},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"SmIWUp2A3mG3bA","type":"string"},"note":{"type":["string","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"total":{"description":"Total allocated. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]}},"required":["id","order_id","total"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/PaymentMutationUnprocessableEntityResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a payment link for a sales order","tags":["Payment links"],"x-yoprint-docs":{"errors":[{"fix":"Build the body from Get what a new payment link can allocate.","status":422,"when":"A draft order, or an entry without its ids."}],"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_sales_order_payment_link_get_create_template","v2_public_payment_link_update","v2_public_payment_link_show"],"rules":["Only published orders: otherwise 422 with the code \"Action Not Allow\".","At least one entry, each with `action: \"create\"`, `transaction_id` and `invoice_id`.","Entries whose payment or invoice is not on this order are skipped. So is an entry whose invoice has nothing left to pay, or whose amount is more than the payment's unallocated amount; an amount above the invoice's balance is cut to that balance. The link is created even if every entry is skipped.","`total.value` must be a whole number of thousandths (a fraction gives HTTP 500); without `total` the entry allocates 0."],"side_effects":["Changes which invoices count as paid; refreshes the order for people who have it open in the web app.","Updates the order's customer's balance totals in the background, and Customer Portal pages the customer has open refresh."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment_link/get_create_template":{"get":{"description":"A payment link (Allocations in the web app) records which invoices a payment pays: it splits payments received on the order across the order's invoices. It is not a link the customer pays through.\n\nReturns the order's payments that still have money to allocate (`unallocated_transactions`), to build the body of Create a payment link: each entry has the payment's `transaction_id` and `unallocated_amount` (thousandths, `dp` 3); add `action: \"create\"`, an `invoice_id` and the `total` to allocate. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_payment_link_get_create_template","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"note":null,"order_id":"V4keXwwxMQyXw7","unallocated_transactions":[{"invoice_id":null,"state":"new","total":{"dp":3,"value":0},"transaction_id":"hAwWd7vPrqjuHD","unallocated_amount":{"dp":3,"value":50000}}]},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A starting body for Create a payment link.","properties":{"note":{"description":"Always null.","type":"null"},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"unallocated_transactions":{"description":"Payments (recorded, card, and from customer credit) with money not yet allocated; `[]` when there are none. Add `action: \"create\"` and an `invoice_id` to each entry you send.","items":{"additionalProperties":true,"properties":{"invoice_id":{"description":"Always null: set it in your Create a payment link entry.","type":"null"},"state":{"description":"Always `new`.","example":"new","type":"string"},"total":{"description":"Always 0: put the amount to allocate here. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 50000, \"dp\": 3 }` is 50.00). Fixed at 3 decimal places (`dp` 3). Read `dp` every time: it can differ between fields and records.","example":{"dp":3,"value":50000},"properties":{"dp":{"const":3,"type":"integer"},"value":{"type":["integer","string"]}},"required":["value","dp"],"type":"object"},"transaction_id":{"description":"The payment's `id`.","example":"hAwWd7vPrqjuHD","type":"string"},"unallocated_amount":{"description":"What the payment still has to allocate. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 50000, \"dp\": 3 }` is 50.00). Fixed at 3 decimal places (`dp` 3). Read `dp` every time: it can differ between fields and records.","example":{"dp":3,"value":50000},"properties":{"dp":{"const":3,"type":"integer"},"value":{"type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["transaction_id","unallocated_amount"],"type":"object"},"type":"array"}},"required":["order_id","unallocated_transactions"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get what a new payment link can allocate","tags":["Payment links"],"x-yoprint-docs":{"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_sales_order_payment_link_create"]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/purchase_order_link":{"get":{"description":"Returns the purchase orders linked to a sales order or quote, in two lists:\n\n- `data.system`: purchase orders that buy stock for this order's lines (linked by YoPrint's stock workflow);\n- `data.manual`: purchase orders someone linked by hand.\n\n`{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_purchase_order_link_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"manual":[{"id":"8ppW5D3AVvZ5wb","name":"Blanks for SO1001","scoped_id":"PO0042","trashed":false}],"system":[]},"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"manual":{"description":"Purchase orders linked by hand.","items":{"additionalProperties":true,"description":"A purchase order.","properties":{"id":{"example":"8ppW5D3AVvZ5wb","type":"string"},"name":{"type":["string","null"]},"scoped_id":{"description":"The purchase order number.","example":"PO0042","type":"string"},"status_id":{"type":["string","null"]},"trashed":{"type":"boolean"},"vendor_id":{"type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"type":"object"},"type":"array"},"system":{"description":"Purchase orders that buy stock for this order's lines.","items":{"additionalProperties":true,"description":"A purchase order.","properties":{"id":{"example":"8ppW5D3AVvZ5wb","type":"string"},"name":{"type":["string","null"]},"scoped_id":{"description":"The purchase order number.","example":"PO0042","type":"string"},"status_id":{"type":["string","null"]},"trashed":{"type":"boolean"},"vendor_id":{"type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"type":"object"},"type":"array"}},"required":["system","manual"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"The order's purchase order links. This answer has no `status` key: only `success` and `data`."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the purchase orders linked to an order","tags":["Sales order purchase orders"],"x-yoprint-docs":{"group":"Sales","permission":"Any member of the team.","related":["v2_public_purchase_order_link_add","v2_public_purchase_order_link_remove"]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/purchase_order_link/add":{"put":{"description":"Links purchase orders to a sales order by hand, for reference. It does not move stock. Linking one that is already linked changes nothing.\n\nThe answer is both lists, as in List the linked purchase orders. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_purchase_order_link_add","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"item":[{"id":"8ppW5D3AVvZ5wb"}]},"schema":{"properties":{"item":{"items":{"properties":{"id":{"description":"A purchase order's `id`.","type":"string"}},"required":["id"],"type":"object"},"type":"array"}},"required":["item"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"manual":[{"id":"8ppW5D3AVvZ5wb","name":"Blanks for SO1001","scoped_id":"PO0042","trashed":false}],"system":[]},"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"manual":{"description":"Purchase orders linked by hand.","items":{"additionalProperties":true,"description":"A purchase order.","properties":{"id":{"example":"8ppW5D3AVvZ5wb","type":"string"},"name":{"type":["string","null"]},"scoped_id":{"description":"The purchase order number.","example":"PO0042","type":"string"},"status_id":{"type":["string","null"]},"trashed":{"type":"boolean"},"vendor_id":{"type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"type":"object"},"type":"array"},"system":{"description":"Purchase orders that buy stock for this order's lines.","items":{"additionalProperties":true,"description":"A purchase order.","properties":{"id":{"example":"8ppW5D3AVvZ5wb","type":"string"},"name":{"type":["string","null"]},"scoped_id":{"description":"The purchase order number.","example":"PO0042","type":"string"},"status_id":{"type":["string","null"]},"trashed":{"type":"boolean"},"vendor_id":{"type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"type":"object"},"type":"array"}},"required":["system","manual"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"The order's purchase order links. This answer has no `status` key: only `success` and `data`."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Link purchase orders to a sales order","tags":["Sales order purchase orders"],"x-yoprint-docs":{"errors":[{"fix":"Use ids from your purchase orders.","status":422,"when":"A purchase order id is not one of the team's."},{"fix":"Link to a sales order.","status":404,"when":"The order is a quote or does not exist."}],"group":"Sales","permission":"Any member of the team.","related":["v2_public_purchase_order_link_index","v2_public_purchase_order_link_remove"],"rules":["Sales orders only: quotes can't get new links.","Every purchase order must belong to the team: \"Invalid purchase order id for this team\"."],"side_effects":["Records the change in the order's history."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/purchase_order_link/remove":{"put":{"description":"Removes hand-made links between a sales order or quote and purchase orders. Links made by the stock workflow stay. The answer is both lists. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_purchase_order_link_remove","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"item":[{"id":"8ppW5D3AVvZ5wb"}]},"schema":{"properties":{"item":{"items":{"properties":{"id":{"description":"A purchase order's `id`.","type":"string"}},"required":["id"],"type":"object"},"type":"array"}},"required":["item"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"manual":[],"system":[]},"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"manual":{"description":"Purchase orders linked by hand.","items":{"additionalProperties":true,"description":"A purchase order.","properties":{"id":{"example":"8ppW5D3AVvZ5wb","type":"string"},"name":{"type":["string","null"]},"scoped_id":{"description":"The purchase order number.","example":"PO0042","type":"string"},"status_id":{"type":["string","null"]},"trashed":{"type":"boolean"},"vendor_id":{"type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"type":"object"},"type":"array"},"system":{"description":"Purchase orders that buy stock for this order's lines.","items":{"additionalProperties":true,"description":"A purchase order.","properties":{"id":{"example":"8ppW5D3AVvZ5wb","type":"string"},"name":{"type":["string","null"]},"scoped_id":{"description":"The purchase order number.","example":"PO0042","type":"string"},"status_id":{"type":["string","null"]},"trashed":{"type":"boolean"},"vendor_id":{"type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"type":"object"},"type":"array"}},"required":["system","manual"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"The order's purchase order links. This answer has no `status` key: only `success` and `data`."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Unlink purchase orders from an order","tags":["Sales order purchase orders"],"x-yoprint-docs":{"errors":[{"fix":"Use ids from the order's manual links.","status":422,"when":"A purchase order id is not one of the team's."}],"group":"Sales","permission":"Any member of the team.","related":["v2_public_purchase_order_link_index"],"side_effects":["Records the change in the order's history."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/shipment/delete_all":{"patch":{"deprecated":true,"description":"**Legacy (deprecated).** A newer operation does this better: use `v2_public_shipment_destroy` (DELETE /v2/api/store/{team_slug}/v2/shipment/{unique_key}) instead. Its answers say so in the `Deprecation` and `X-YoPrint-Successor` headers.\n\nRetired: this operation does nothing and always answers with the error code `depcreated` (HTTP 500). Delete shipments one at a time instead. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_shipment_destroy_all","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"description":"Never sent: this route always fails with HTTP 500."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete all shipments of an order (retired)","tags":["Shipments"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Delete each shipment with Delete a shipment.","status":500,"when":"Always: `{\"status\": 500, \"success\": false, \"error\": {\"code\": \"depcreated\", \"message\": null}}`."}],"group":"Shipping","permission":"Any member of the team.","prefer":"v2_public_shipment_destroy","related":["v2_public_shipment_destroy"],"status":"legacy"}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/shipment/{id}/assign":{"put":{"description":"Adds a team member to a shipment's assignees with `action: \"assign\"`, or removes them with `action: \"unassign\"`. The answer is the shipment's assignees. `{hash_id}` is the order's `id`; `{id}` is the shipment's `id`.","operationId":"v2_public_sales_order_shipment_assign","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The shipment's `id` (a hash id).","example":"qAKg4jO63uFqjs","in":"path","name":"id","required":true,"schema":{"example":"qAKg4jO63uFqjs","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"action":"assign","user_id":"PydH0WtBhSeiNU"},"schema":{"properties":{"action":{"enum":["assign","unassign"],"type":"string"},"user_id":{"description":"A team member's `id`.","type":"string"}},"required":["action","user_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"avatar_url":null,"email":"alex@example.com","id":"PydH0WtBhSeiNU","name":"Alex Rivera","timezone":"America/Chicago"}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"The shipment's assignees.","items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Assign or unassign a team member on a shipment","tags":["Shipments"],"x-yoprint-docs":{"errors":[{"fix":"Send both fields.","status":422,"when":"`action` or `user_id` is missing, `action` is not `assign` or `unassign`, or `user_id` is not a valid id (`validation_failed`)."},{"fix":"Check both ids.","status":404,"when":"The user is not a team member, or the shipment is not on this order."}],"group":"Shipping","permission":"Any member of the team.","related":["v2_public_sales_order_shipment_index_for_order"],"side_effects":["Customer Portal pages the order's customer has open refresh (a live update, not an email)."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/shipment/{id}/status":{"put":{"description":"Moves a shipment to another shipment status. `status_id` comes from the team's shipment statuses. `{hash_id}` is the order's `id`; `{id}` is the shipment's `id`.\n\n`notify_customer` matters only for Shopify shipments moving to a final status: it is then required, and Shopify creates the fulfillment and tells the customer when it is true. For other shipments it has no effect.\n\nThe answer is the shipment in the older shape, with its `status` and `items`, plus `previous_status_id` and `previous_status` (the status before this call).","operationId":"v2_public_sales_order_shipment_change_status","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The shipment's `id` (a hash id).","example":"qAKg4jO63uFqjs","in":"path","name":"id","required":true,"schema":{"example":"qAKg4jO63uFqjs","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"status_id":"lziIhzgc0acXFc"},"schema":{"properties":{"notify_customer":{"description":"Shopify shipments only; see above.","type":["boolean","null"]},"status_id":{"description":"A shipment status id.","type":"string"}},"required":["status_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"delivery_total":0,"id":"qAKg4jO63uFqjs","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","previous_status":{"color":"#2196f3","customer_label":"In Progress","id":"rfc8TboAnPpGAS","label":"Packing","position":2,"role":"shipment","trashed":false,"type":"in_progress"},"previous_status_id":"rfc8TboAnPpGAS","scoped_id":"SHIP-1001","shipping_address_id":"RNG2OuYC20YzXs","status":{"color":"#4caf50","customer_label":"Completed","id":"lziIhzgc0acXFc","label":"Shipped","position":3,"role":"shipment","trashed":false,"type":"end"},"status_id":"lziIhzgc0acXFc"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A shipment, in the older shape (app/Transformers/ShipmentTransformer.php, which always includes `status` and `items`).","properties":{"delivery_notes":{"type":["string","null"]},"delivery_total":{"description":"Older shipping total. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"id":{"example":"qAKg4jO63uFqjs","type":"string"},"items":{"description":"Shipment lines, in the older shape.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"previous_status":{"additionalProperties":true,"description":"A status, as the status operations return it.","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"previous_status_id":{"description":"The status before this call.","type":["string","null"]},"scoped_id":{"example":"SHIP-1001","type":"string"},"shipping_address_id":{"type":["string","null"]},"status":{"additionalProperties":true,"description":"A status, as the status operations return it.","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_id":{"example":"lziIhzgc0acXFc","type":"string"}},"required":["id","status_id"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change the status of a shipment","tags":["Shipments"],"x-yoprint-docs":{"errors":[{"fix":"Publish the order, or send `notify_customer`.","status":422,"when":"A draft order, or a Shopify shipment moving to its final status without `notify_customer` (`shopify_terminal_status_requires_fulfillment`)."},{"fix":"Use ids from this team and order.","status":404,"when":"The status or shipment is not found."}],"group":"Shipping","permission":"Any member of the team.","related":["v1_public_status_list_shipment","v2_public_sales_order_shipment_index_for_order"],"rules":["The order must be published: \"Publish this order before changing shipment status.\"","The status must be a shipment status of the team."],"side_effects":["Emails the team about the change and sends the `shipment.status_changed` webhook, only when the status really changes: picking the shipment's current status sends neither.","For a Shopify shipment moving to a final status, creates the fulfillment in Shopify, then emails the team and sends the webhook.","Customer Portal pages the order's customer has open refresh (also when the status didn't change)."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/shipment/{id}/validate_address":{"patch":{"description":"Checks the shipment's shipping address with UPS address validation, for supported countries, and saves the result on the address. An address already checked is not checked again. The answer is the shipment in the older shape, with its `status` and `items`. `{hash_id}` is the order's `id`; `{id}` is the shipment's `id`.","operationId":"v2_public_sales_order_shipment_validate_address","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The shipment's `id` (a hash id).","example":"qAKg4jO63uFqjs","in":"path","name":"id","required":true,"schema":{"example":"qAKg4jO63uFqjs","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"delivery_notes":"Leave at reception.","delivery_total":0,"id":"qAKg4jO63uFqjs","items":[],"order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","scoped_id":"SHIP-1001","shipping_address_id":"RNG2OuYC20YzXs","status":{"color":"#9e9e9e","customer_label":"Pending","id":"43J0pEwV4RKUdO","label":"To pack","position":1,"role":"shipment","trashed":false,"type":"start"},"status_id":"43J0pEwV4RKUdO"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A shipment, in the older shape (app/Transformers/ShipmentTransformer.php, which always includes `status` and `items`).","properties":{"delivery_notes":{"type":["string","null"]},"delivery_total":{"description":"Older shipping total. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"id":{"example":"qAKg4jO63uFqjs","type":"string"},"items":{"description":"Shipment lines, in the older shape.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"scoped_id":{"example":"SHIP-1001","type":"string"},"shipping_address_id":{"type":["string","null"]},"status":{"additionalProperties":true,"description":"A status, as the status operations return it.","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_id":{"example":"lziIhzgc0acXFc","type":"string"}},"required":["id","status_id"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Check a shipment's address with the carrier","tags":["Shipments"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Check the ids.","status":404,"when":"The shipment is not on this order."},{"fix":"Set the shipment's address first.","status":500,"when":"The shipment has no shipping address: the body is `{\"message\": \"Server Error\"}`."},{"fix":"Nothing to check: the order is gone in Shopify.","status":422,"when":"The Shopify order was deleted in Shopify (`shopify_order_deleted_externally`)."}],"group":"Shipping","permission":"Any member of the team.","related":["v2_public_sales_order_shipment_index_for_order"],"side_effects":["Calls the UPS address validation service once per address and saves the result on the address."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/square_terminal/create":{"post":{"description":"**Internal.** Built for YoPrint's own apps, not for integrations. Don't build on it.\n\nSends a payment request for this order to a Square Terminal device; the customer pays on the device. Needs the Square (v2) connection.\n\nSend a whole number of thousandths: `12500` is 12.50. See [Money and quantities](/concepts/money-and-quantities/). The answer has the checkout from Square, with its id. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_payment_square_terminal_create","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"amount":85000,"device_id":"device-1001"},"schema":{"properties":{"amount":{"description":"Send a whole number of thousandths: `12500` is 12.50. Must be at least 1.00 (`1000`) after any `surcharge`.","type":"integer"},"device_id":{"description":"The Square Terminal device id.","type":"string"},"surcharge":{"description":"Optional card surcharge included in `amount`, read only when the team charges one. It must not be negative; it is taken off `amount` for the minimum check.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["device_id","amount"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"amount_money":{"amount":8500,"currency":"USD"},"id":"checkout-1001","reference_id":"SO1001","status":"PENDING"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"Square's Terminal checkout, with empty fields left out (also `note`, `device_options`, `deadline_duration`, `created_at`, `updated_at`, `app_id`, `location_id`, `payment_type`).","properties":{"amount_money":{"additionalProperties":true,"properties":{"amount":{"description":"In Square's smallest unit (cents for USD): 125000 thousandths is 12500.","type":"integer"},"currency":{"example":"USD","type":"string"}},"type":"object"},"id":{"description":"Square's checkout id: use it to cancel.","example":"checkout-1001","type":"string"},"reference_id":{"description":"The order number, for example SO1001.","type":"string"},"status":{"description":"Square's checkout status, such as `PENDING`.","type":["string","null"]}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Start a Square Terminal checkout","tags":["Payments"],"x-yoprint-docs":{"errors":[{"fix":"Publish the order first.","status":500,"when":"A draft order: `error.code` \"Action Not Allow\"."},{"fix":"Connect Square in Settings.","status":422,"when":"Square v2 is not connected: `{\"message\": \"Square v2 Not Setup\"}`, with no envelope."},{"fix":"Check the device id.","status":422,"when":"Square refused: `payment_capture_failed`, with Square's errors in `error.data`."},{"fix":"Send at least 1.00 (`1000`) in thousandths.","status":422,"when":"`amount` is missing or not a whole number (`validation_failed`), less than 1.00 after the surcharge (`payment_below_minimum`), or the surcharge is negative (`payment_surcharge_invalid`)."}],"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_sales_order_payment_square_terminal_cancel"],"rules":["The amount is checked first: The amount to charge, less any `surcharge`, must be at least 1.00 in the order's currency: otherwise 422 `payment_below_minimum` (\"Enter at least USD 1.00.\", with the order's currency code), and `error.payment_amount_policy` gives `currency`, `minimum_payment` (a decimal pair, `{ \"value\": \"1000\", \"dp\": 3 }`) and `minimum_remaining_balance` (null). A negative `surcharge` is 422 `payment_surcharge_invalid` (\"The payment surcharge cannot be negative.\"). The provider's own limits still apply.","Then: only published orders (otherwise the error code \"Action Not Allow\", HTTP 500 today), and the team must have Square v2 connected (422 `{\"message\": \"Square v2 Not Setup\"}`)."],"side_effects":["Starts a checkout on the device through Square. Money moves when the customer pays."],"status":"internal"},"x-internal":true}},"/v2/api/store/{team_slug}/v2/sales_order/{hash_id}/square_terminal/{checkout_id}/cancel":{"patch":{"description":"**Internal.** Built for YoPrint's own apps, not for integrations. Don't build on it.\n\nCancels a Square Terminal checkout that is still waiting. `{checkout_id}` is the checkout id Square returned when it started. The answer has no data. `{hash_id}` is the order's `id` (for example `V4keXwwxMQyXw7`); the `ord_` unique key is not accepted here.","operationId":"v2_public_sales_order_payment_square_terminal_cancel","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"hash_id","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"Square's checkout id, from Start a Square Terminal checkout. Not a YoPrint hash id.","example":"checkout-1001","in":"path","name":"checkout_id","required":true,"schema":{"example":"checkout-1001","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"description":"No data.","type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Cancel a Square Terminal checkout","tags":["Payments"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Cancel it on the device.","status":500,"when":"Square could not cancel it (`unable_cancel_terminal_flow`)."},{"fix":"Connect Square in Settings.","status":422,"when":"Square v2 is not connected: `{\"message\": \"Square v2 Not Setup\"}`."}],"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_sales_order_payment_square_terminal_create"],"rules":["The order in the path isn't checked: any of the team's order ids works."],"status":"internal"},"x-internal":true}},"/v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}":{"delete":{"description":"Deletes a sales order or quote. You can bring it back with Restore.\n\nDeleting a published sales order also undoes its money and stock: payments on it are moved to the customer's credit (not on Shopify orders), its stock workflows are cancelled and its stock reservations released. Its invoices, jobs, shipments and messages are deleted with it, and its Shippo labels are voided.\n\nDeleting an order that is already deleted succeeds and changes nothing. The answer has no data.\n\n`{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.","operationId":"v2_public_order_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"order_unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"description":"No data.","type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a sales order or quote","tags":["Sales orders"],"x-yoprint-docs":{"errors":[{"fix":"Publish it first, then delete.","status":422,"when":"A Shopify-linked draft, or a draft with a bought shipping label."},{"fix":"Wait for the provider's decision, then delete.","status":422,"when":"A payment on the order is frozen by an open dispute or review (`customer_payment_disputed_funds_unavailable` or `invoice_payment_funding_withheld`)."},{"fix":"Ask the team owner for sales order edit permission.","status":403,"when":"The API key's role can't edit this order."},{"fix":"Check the id.","status":404,"when":"No such order in this team."}],"group":"Sales","permission":"Needs permission to edit this sales order or quote:\n\n- The team owner\n- A role with `update_all_order`\n- A role with `update_self_order`, when the order was created by or is assigned to the API key's user\n- The person who created a draft, with `create_order`\n\nQuotes use the same sales order permissions.","related":["v2_public_order_restore","v2_public_sales_order_credit_refund_all_to_customer_credit"],"rules":["A Shopify-linked draft can't be deleted until it is published: \"Publish this order before deleting a Shopify-linked order.\"","A draft with a shipping label bought through YoPrint can't be deleted: \"Publish this order before deleting an order with a shipping label.\"","An order (other than a Shopify order) can't be deleted while a payment holding money on it is frozen by an open dispute or review: 422 `customer_payment_disputed_funds_unavailable` (\"This order can't be deleted while a payment on it is under dispute. You can delete it once <provider> decides.\") or `invoice_payment_funding_withheld` (\"This order can't be deleted while a payment on it is under review. You can delete it once the review is finished.\"), with `error.reason`, `error.provider` and `error.provider_label`. Nothing changes."],"side_effects":["Moves every payment on a published order to the customer's credit (money from a Customer Portal payment goes back to that payment's credit). Shopify orders keep their payments.","Cancels stock workflows and releases stock reservations.","Deletes the order's invoices, jobs, shipments, packages and messages.","Voids Shippo labels bought for the order and asks Shippo for their refund (a provider call).","On a Shopify order, cancels the fulfillments YoPrint created in Shopify.","Sends the `order.deleted` webhook (`quote.deleted` for a quote), drafts included, and on a published order updates the customer's totals.","When the team syncs to QuickBooks Online automatically, queues a sync that removes the order's payments and invoices from QuickBooks."]}},"get":{"description":"Returns one sales order or quote with its line items (`items`), customer and message participants.\n\n`{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. Deleted orders are returned too (`trashed: true`).\n\nThe answer is the order: its `id` and `unique_key`, `scoped_id` (the number people see), `name`, `object_type` (`sales_order` or `quote`), `internal_status` (`draft` until published), `status_id` and `status`, the customer and addresses, dates, notes, `is_rush`, pricing settings and totals. The value of the order's lines is `order_item_cart_total`. `invoiced_total`, `invoiced_order_item_subtotal`, `invoiced_shipment_subtotal`, `invoiced_tax_subtotal` and `invoiced_discount_subtotal` count only what has been **invoiced** (0 until the order has an invoice). They are **decimal pairs** (`{ \"value\": 850000, \"dp\": 4 }` is 85.00; always read `dp`). `paid_amount`, `calc_deposit_total` and `unallocated_amount` are in **thousandths** (`135000` is 135.00). `deposit_total` is a **percentage ×1000** (`50000` is 50%). `calc_subtotal`, `calc_discount`, `calc_tax` and `calc_total` are deprecated thousandths copies of the invoiced totals: they still return, but use the decimal pair fields instead.","operationId":"v2_public_order_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"order_unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"calc_deposit_total":67500,"customer":{"id":"63KcENAAsKuipY","is_external":false,"name":"Northwind Apparel","tax_exempt":false},"customer_id":"63KcENAAsKuipY","customer_po_number":"PO-1188","deposit_amount_due":{"dp":4,"value":175000},"deposit_required":true,"deposit_total":50000,"due_date":"2026-11-14T00:00:00+00:00","id":"V4keXwwxMQyXw7","internal_status":"published","invoiced_discount_subtotal":{"dp":4,"value":0},"invoiced_order_item_subtotal":{"dp":4,"value":1250000},"invoiced_shipment_subtotal":{"dp":4,"value":0},"invoiced_tax_subtotal":{"dp":4,"value":100000},"invoiced_total":{"dp":4,"value":1350000},"is_rush":false,"issue_date":"2026-11-03T00:00:00+00:00","items":[{"id":"Owr88lhAk28aqL","job":{"id":"K6iF8n29iwOZnj","scoped_id":"JOB-1001","type":"linked","unique_key":"job_EXAMPLEuniqueKey"},"lock_version":1793696400234567,"order_id":"V4keXwwxMQyXw7","order_unique_key":"ord_EXAMPLEuniqueKey","position":200000,"pricing":{"product":{"override":true,"total":{"dp":6,"value":12500000}},"type":"product_cost_service"},"product":{"properties":{"customer_supplied":false,"id":"nqSB3HG1O2u5Jg"},"type":"user_simple"},"quantity":{"total":{"dp":0,"value":10},"type":"unit"},"subtotal":{"dp":4,"value":1250000},"trashed":false,"type":"user_simple","unit_price":{"dp":6,"value":12500000}}],"mode":"view","name":"Spring team shirts","object_type":"sales_order","order_balance_due":{"dp":4,"value":850000},"order_item_cart_total":{"dp":4,"value":1250000},"paid_amount":50000,"quote":false,"scoped_id":"SO1001","status":{"color":"#2196f3","customer_label":"In Progress","id":"52CuV8sWcDZLPm","label":"In production","position":2,"role":"order","trashed":false,"type":"in_progress"},"status_id":"52CuV8sWcDZLPm","total_qty_need_ordering":"0.00000000","trashed":false,"type":"order","unique_key":"ord_EXAMPLEuniqueKey"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A sales order or quote.","properties":{"approval_status":{"description":"`requested`, `sent-to-customer`, `viewed-by-customer`, `need-changes` or `approved`; null without approvals.","type":["string","null"]},"assigned_users":{"description":"The team members in the order's Assigned To list (always included).","items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"auto_invoice_managed":{"description":"true when YoPrint keeps one invoice in step with the order.","type":"boolean"},"auto_invoice_shipment_price_type":{"description":"`DONOTMANAGE`, `NONE`, `MARKUP` or `MARGIN`.","type":["string","null"]},"auto_invoice_shipment_rate":{"description":"The MARKUP or MARGIN percentage. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"auto_invoice_type":{"description":"How the automatic invoice is built. Always `single_invoice` today.","type":["string","null"]},"billing_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"billing_address_id":{"type":["string","null"]},"calc_deposit_total":{"description":"The deposit amount, rounded to 2 decimal places: the percentage of `order_item_cart_total`, or of the invoiced total once every line is invoiced (or the invoiced total reaches the order's); 0 unless `deposit_required`. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `invoiced_discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `invoiced_order_item_subtotal`, which already includes billed shipping. This older field adds `invoiced_shipment_subtotal` to it once more. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `invoiced_tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `invoiced_total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"client_note":{"description":"The Client Note.","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_by":{"description":"Created By (a team member id).","type":["string","null"]},"creator_name":{"type":["string","null"]},"cust_due_date":{"description":"Customer in-hands date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"Always present on order answers, lists included: the customer record, or null when the order has none. Get a sales order also nests the customer's contacts, addresses, brand profiles, tags, files and assigned users in it.","properties":{"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"id":{"example":"63KcENAAsKuipY","type":"string"},"is_external":{"description":"true for a customer synced from an integration.","type":"boolean"},"name":{"example":"Northwind Apparel","type":"string"},"tax_exempt":{"type":"boolean"}},"type":["object","null"]},"customer_billing_contact_id":{"description":"The id of the contact on the order (the same contact as `customer_contact_id`), or null.","type":["string","null"]},"customer_contact_id":{"type":["string","null"]},"customer_has_email":{"type":"boolean"},"customer_id":{"example":"63KcENAAsKuipY","type":["string","null"]},"customer_po_number":{"example":"PO-1188","type":["string","null"]},"customer_profile_id":{"description":"Brand profile.","type":["string","null"]},"deposit_amount_due":{"description":"Deposit still to pay (negative once overpaid). A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"deposit_due":{"description":"Deposit due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"deposit_required":{"type":"boolean"},"deposit_total":{"description":"The deposit as a **percentage** of the order. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","type":["integer","number","string","null"]},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"external_ids":{"description":"The order's links to records in other systems. An empty list when there are none.","items":{"additionalProperties":true,"description":"One link to a record in another system (Shopify, QuickBooks and so on): `id`, `external_integration_id`, `external_id`, `data`, `created_at`, `updated_at` and the nested `external_integration`.","type":"object"},"type":"array"},"external_type":{"description":"`shopify` for a Shopify order; null for YoPrint orders.","type":["string","null"]},"from_legacy":{"description":"true for an order that was moved over from the old format.","type":"boolean"},"full_amount_due":{"description":"Full payment due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"grouped_pdf":{"description":"PDF links, grouped: `Main` (only for roles with `view_order_finance`), `Job` (not on Shopify orders), `Shipment` and the team's templates.","items":{"additionalProperties":true,"properties":{"documents":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"label":{"example":"Main","type":"string"}},"type":"object"},"type":"array"},"has_external_integration_sync_error":{"description":"true when the last sync with an integration failed.","type":"boolean"},"has_invoice":{"description":"true when the order has at least one invoice, so a zero invoiced total can be told apart from no invoice.","type":"boolean"},"has_not_invoiced_items":{"description":"true when some line items are not on an invoice yet.","type":"boolean"},"has_over_invoiced_items":{"description":"true when some line items are invoiced for more than the order has.","type":"boolean"},"has_shipment_items_not_allocated":{"description":"true when some line items are not on a shipment yet.","type":"boolean"},"has_shipment_items_over_allocated":{"description":"true when some line items are on shipments for more than the order has.","type":"boolean"},"has_valid_invoice":{"description":"true when at least one of the order's invoices is in a valid state.","type":"boolean"},"has_valid_shipment":{"description":"true when at least one of the order's shipments is in a valid state.","type":"boolean"},"id":{"description":"The order's hash id: use it in every other call.","example":"V4keXwwxMQyXw7","type":"string"},"internal_status":{"description":"`draft` until published.","enum":["draft","published"],"type":"string"},"inventory_status":{"description":"Stock status of the order's lines: `not_committed`, `committed`, `partially_committed`, `not_applicable` or `pending`.","type":["string","null"]},"invoice_lock_version":{"description":"Changes whenever the order's invoices change.","type":["integer","string","null"]},"invoiced_discount_subtotal":{"description":"Discounts on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_order_item_subtotal":{"description":"The lines and shipping fees the order's invoices bill (the sum of their `cart_item_subtotal`); 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_shipment_subtotal":{"description":"The shipping fees in `invoiced_order_item_subtotal`; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_tax_subtotal":{"description":"Tax on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_total":{"description":"Total of the order's invoices. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"is_client_note_editable":{"description":"false for a Shopify order, whose client note comes from Shopify.","type":"boolean"},"is_external":{"description":"true for an order synced from an integration such as Shopify.","type":"boolean"},"is_legacy":{"description":"true for an order made in the old format.","type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"items":{"description":"The order's lines (Get only).","items":{"additionalProperties":true,"description":"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).","properties":{"_meta":{"additionalProperties":true,"description":"The line's own values again (`id`, `type`, `order_id`, `unit_price`, `subtotal` and so on). Always an object.","type":"object"},"id":{"example":"Owr88lhAk28aqL","type":"string"},"inventory_status":{"description":"Stock status of the line.","type":["string","null"]},"job":{"additionalProperties":true,"type":"object"},"lock_version":{"description":"The line's own lock version (a microsecond timestamp).","type":["integer","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_unique_key":{"description":"The order's `unique_key`. The line's own `unique_key` is not in the answer: use `id`.","example":"ord_EXAMPLEuniqueKey","type":"string"},"position":{"example":200000,"type":"integer"},"pricing":{"additionalProperties":true,"type":"object"},"pricing_rule_applied":{"description":"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.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"11.05","type":"string"},"after_total":{"description":"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.","example":{"dp":6,"value":11050000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: that starting price, as a decimal string with at least 2 decimal places.","example":"8.50","type":"string"},"base_type":{"description":"Full summary only: what the rule started from: the supplier price for catalog lines, the product's own price for other lines.","enum":["supplier_price","base_price"],"type":"string"},"normal_price":{"description":"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`.","example":"11.05","type":["string","null"]},"original_total":{"description":"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.","example":{"dp":6,"value":8500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The line keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`product` on a line.","example":"product","type":"string"}},"type":["object","null"]},"product":{"additionalProperties":true,"type":"object"},"quantity":{"additionalProperties":true,"description":"The quantity, trailing zeros dropped: 10 is `{ \"value\": 10, \"dp\": 0 }`.","type":"object"},"subtotal":{"description":"`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.","example":{"dp":4,"value":1250000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"trashed":{"description":"true when the line was deleted.","example":false,"type":"boolean"},"type":{"description":"The kind of line: db_catalog, user_simple, db_variant, custom or fee.","example":"user_simple","type":"string"},"unit_price":{"description":"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.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"}},"type":"object"},"type":"array"},"job_lock_version":{"description":"Changes whenever the order's jobs change.","type":["integer","string","null"]},"last_payment_request_date":{"description":"When a payment reminder was last emailed for the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"lock_version":{"description":"Changes on every save.","type":["integer","string","null"]},"mode":{"description":"Older flag: `create` for a draft, `view` once published.","enum":["create","view","edit"],"type":"string"},"name":{"example":"Spring team shirts","type":["string","null"]},"object_type":{"enum":["sales_order","quote"],"type":"string"},"order_balance_due":{"description":"Invoiced total minus paid. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_cart_total":{"description":"The value of the order's lines: the order's own total before invoicing. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_lock_version":{"description":"Changes whenever the order's line items change.","type":["integer","string","null"]},"order_margin_percentage":{"description":"Margin, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_markup_percentage":{"description":"Markup, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_profit":{"description":"Profit. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"paid_amount":{"description":"Paid so far. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"participants":{"description":"Who receives the order's messages (Get only).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"payment_lock_version":{"description":"Changes whenever the order's payments change.","type":["integer","string","null"]},"payment_term_id":{"type":["string","null"]},"pricing_group_id":{"type":["string","null"]},"pricing_strategy":{"description":"`job_separately`, `job_together` or `service_loc_together`.","type":["string","null"]},"prod_note":{"description":"The production note.","type":["string","null"]},"producible_item_count":{"description":"Quantity to produce.","type":["number","integer","string","null"]},"quickbook_disable_sync":{"description":"true when QuickBooks sync is off for this order.","type":"boolean"},"quickbook_disable_sync_at":{"description":"When the switch was last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_disable_sync_by":{"description":"The team member who last changed the switch, or null.","type":["string","null"]},"quickbook_disable_sync_reason":{"description":"The note given at the last change of the order's QuickBooks sync switch (off or back on), at most 500 characters, or null.","type":["string","null"]},"quickbook_last_error_sync":{"description":"When a QuickBooks sync of the order last failed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_last_success_sync":{"description":"When QuickBooks last accepted the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbooks_hold":{"description":"Set when YoPrint holds back a QuickBooks payment covering this order: `code` is `changed`, `deleted` or `rejected` (the payment was changed or deleted in QuickBooks, or QuickBooks refused a change), and `detail` is `already_deposited` (the payment is in a QuickBooks bank deposit) or null. Null when nothing is held.","properties":{"code":{"enum":["changed","deleted","rejected"],"type":"string"},"detail":{"type":["string","null"]}},"type":["object","null"]},"quote":{"description":"Older flag: true for a quote.","type":"boolean"},"scoped_id":{"description":"The order number people see, `SO` and at least four digits (quotes too). Not an id.","example":"SO1001","type":"string"},"ship_due_date":{"description":"Ship due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shipment_billable_fee_invoice_status":{"description":"Whether those shipping fees are on an invoice. Null when there is nothing to bill.","type":["string","null"]},"shipment_billable_fee_total":{"description":"The shipping fees you bill the customer on the order's shipments. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_cost_total":{"description":"Shipping cost incurred. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_lock_version":{"description":"Changes whenever the order's shipments change.","type":["integer","string","null"]},"shipping_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"shipping_address_id":{"type":["string","null"]},"shopify_last_error_sync":{"description":"When a Shopify sync of the order last failed. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_last_success_sync":{"description":"When Shopify last accepted the order. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_terminal_topic":{"description":"Shopify orders only: the Shopify event name behind the order's final state there. Null on YoPrint orders. The answer can also hold more `shopify_*` fields (`shopify_admin_url`, `shopify_compliance_deletion`, `shopify_finance_notices`, `shopify_has_fulfillment_conflict`, `shopify_last_fulfillment_conflict_at`): they are null or empty on YoPrint orders.","type":["string","null"]},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"The order's status (always included).","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_completion_date":{"description":"When the order's status last moved to an end status. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status_id":{"description":"The order's status (from the team's sales order or quote statuses).","example":"52CuV8sWcDZLPm","type":"string"},"status_last_change_date":{"description":"Last status change. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"tags":{"items":{"additionalProperties":true,"properties":{"color_hex":{"description":"Tag color, for example `#E53935`.","type":["string","null"]},"id":{"example":"7qYPMmbLZR9oFg","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"total_qty_need_ordering":{"description":"Quantity still to buy, as a decimal string with 8 decimal places (`\"24.00000000\"`).","example":"0.00000000","type":"string"},"trashed":{"description":"true when the order is deleted.","type":"boolean"},"type":{"description":"Older name for `object_type`.","enum":["order","quote"],"type":"string"},"unallocated_amount":{"description":"Payments not yet allocated to an invoice. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"unique_key":{"description":"The order's unique key (`ord_…`); accepted wherever `{order_unique_key}` is.","example":"ord_EXAMPLEuniqueKey","type":"string"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"version":{"description":"The order format version.","type":["integer","string","null"]},"wallet_currency_iso":{"description":"The order's currency code (`USD` and so on), or null on older orders without one.","example":"USD","type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"required":["id","unique_key","scoped_id","object_type","internal_status"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a sales order or quote","tags":["Sales orders"],"x-yoprint-docs":{"group":"Sales","notes":["To find an order by its number, use search; to list a customer's orders, use the sales order or quote filter with `customer_id`.","Line items here use the same shape as List the line items."],"permission":"Any member of the team.","related":["v2_public_sales_order_filter","v2_public_quote_filter","v2_public_order_item_index","v2_public_order_history"]}},"put":{"description":"Changes an order's header fields. Send only the fields you change.\n\nUse it for the name, number, customer PO number, notes, rush flag, status, Created By, addresses, brand profile and contact. Other changes have their own operation:\n\n- dates, payment term, pricing group, warehouse, customer, status with webhooks, conversion, cloning: Run an action (`v2.public.order.single_action`);\n- Client Note and production note alone: the note operations, which can also clear a note.\n\n`{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 is the updated order.","operationId":"v2_public_order_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"order_unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"customer_po_number":"PO-1190","is_rush":true,"name":"Spring team shirts"},"schema":{"properties":{"billing_address_id":{"description":"The billing address id, or null or an empty string to clear it. It must be a current address of the team.","type":["string","null"]},"client_note":{"description":"The Client Note (the customer sees it).","type":"string"},"created_by":{"description":"The team member shown as Created By. Must be a current member of the team.","type":"string"},"customer_contact_id":{"description":"The customer contact id, or empty to clear it.","type":["string","null"]},"customer_id":{"description":"Only the current customer is accepted here. Change a draft's customer with the `change_customer` action.","type":"string"},"customer_po_number":{"description":"The customer's purchase order number.","type":"string"},"customer_profile_id":{"description":"The customer brand profile id, or empty to clear it.","type":["string","null"]},"is_rush":{"description":"Marks the order as rush. Unlike the rush actions, this does not change the jobs or send a webhook.","type":"boolean"},"name":{"description":"The order's name.","type":"string"},"object_type":{"description":"Drafts only, and only the current value. Convert with the `convert_to_quote` or `convert_to_sales_order` action.","enum":["sales_order","quote"],"type":"string"},"prod_note":{"description":"The production note (internal).","type":"string"},"quote":{"description":"Drafts only, and only the current value.","type":"boolean"},"scoped_id":{"description":"The order number.","type":"string"},"shipping_address_id":{"description":"The shipping address id, or null or an empty string to clear it. It must be a current address of the team.","type":["string","null"]},"status_id":{"description":"A status id from the team's sales order (or quote) statuses. Prefer the `change_status` action, which also sends the status webhooks.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"calc_deposit_total":67500,"customer":{"id":"63KcENAAsKuipY","is_external":false,"name":"Northwind Apparel","tax_exempt":false},"customer_id":"63KcENAAsKuipY","customer_po_number":"PO-1190","deposit_amount_due":{"dp":4,"value":175000},"deposit_required":true,"deposit_total":50000,"due_date":"2026-11-14T00:00:00+00:00","id":"V4keXwwxMQyXw7","internal_status":"published","invoiced_discount_subtotal":{"dp":4,"value":0},"invoiced_order_item_subtotal":{"dp":4,"value":1250000},"invoiced_shipment_subtotal":{"dp":4,"value":0},"invoiced_tax_subtotal":{"dp":4,"value":100000},"invoiced_total":{"dp":4,"value":1350000},"is_rush":true,"issue_date":"2026-11-03T00:00:00+00:00","mode":"view","name":"Spring team shirts","object_type":"sales_order","order_balance_due":{"dp":4,"value":850000},"order_item_cart_total":{"dp":4,"value":1250000},"paid_amount":50000,"quote":false,"scoped_id":"SO1001","status":{"color":"#2196f3","customer_label":"In Progress","id":"52CuV8sWcDZLPm","label":"In production","position":2,"role":"order","trashed":false,"type":"in_progress"},"status_id":"52CuV8sWcDZLPm","total_qty_need_ordering":"0.00000000","trashed":false,"type":"order","unique_key":"ord_EXAMPLEuniqueKey"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A sales order or quote.","properties":{"approval_status":{"description":"`requested`, `sent-to-customer`, `viewed-by-customer`, `need-changes` or `approved`; null without approvals.","type":["string","null"]},"assigned_users":{"description":"The team members in the order's Assigned To list (always included).","items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"auto_invoice_managed":{"description":"true when YoPrint keeps one invoice in step with the order.","type":"boolean"},"auto_invoice_shipment_price_type":{"description":"`DONOTMANAGE`, `NONE`, `MARKUP` or `MARGIN`.","type":["string","null"]},"auto_invoice_shipment_rate":{"description":"The MARKUP or MARGIN percentage. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"auto_invoice_type":{"description":"How the automatic invoice is built. Always `single_invoice` today.","type":["string","null"]},"billing_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"billing_address_id":{"type":["string","null"]},"calc_deposit_total":{"description":"The deposit amount, rounded to 2 decimal places: the percentage of `order_item_cart_total`, or of the invoiced total once every line is invoiced (or the invoiced total reaches the order's); 0 unless `deposit_required`. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `invoiced_discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `invoiced_order_item_subtotal`, which already includes billed shipping. This older field adds `invoiced_shipment_subtotal` to it once more. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `invoiced_tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `invoiced_total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"client_note":{"description":"The Client Note.","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_by":{"description":"Created By (a team member id).","type":["string","null"]},"creator_name":{"type":["string","null"]},"cust_due_date":{"description":"Customer in-hands date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"Always present on order answers, lists included: the customer record, or null when the order has none. Get a sales order also nests the customer's contacts, addresses, brand profiles, tags, files and assigned users in it.","properties":{"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"id":{"example":"63KcENAAsKuipY","type":"string"},"is_external":{"description":"true for a customer synced from an integration.","type":"boolean"},"name":{"example":"Northwind Apparel","type":"string"},"tax_exempt":{"type":"boolean"}},"type":["object","null"]},"customer_billing_contact_id":{"description":"The id of the contact on the order (the same contact as `customer_contact_id`), or null.","type":["string","null"]},"customer_contact_id":{"type":["string","null"]},"customer_has_email":{"type":"boolean"},"customer_id":{"example":"63KcENAAsKuipY","type":["string","null"]},"customer_po_number":{"example":"PO-1188","type":["string","null"]},"customer_profile_id":{"description":"Brand profile.","type":["string","null"]},"deposit_amount_due":{"description":"Deposit still to pay (negative once overpaid). A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"deposit_due":{"description":"Deposit due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"deposit_required":{"type":"boolean"},"deposit_total":{"description":"The deposit as a **percentage** of the order. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","type":["integer","number","string","null"]},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"external_ids":{"description":"The order's links to records in other systems. An empty list when there are none.","items":{"additionalProperties":true,"description":"One link to a record in another system (Shopify, QuickBooks and so on): `id`, `external_integration_id`, `external_id`, `data`, `created_at`, `updated_at` and the nested `external_integration`.","type":"object"},"type":"array"},"external_type":{"description":"`shopify` for a Shopify order; null for YoPrint orders.","type":["string","null"]},"from_legacy":{"description":"true for an order that was moved over from the old format.","type":"boolean"},"full_amount_due":{"description":"Full payment due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"grouped_pdf":{"description":"PDF links, grouped: `Main` (only for roles with `view_order_finance`), `Job` (not on Shopify orders), `Shipment` and the team's templates.","items":{"additionalProperties":true,"properties":{"documents":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"label":{"example":"Main","type":"string"}},"type":"object"},"type":"array"},"has_external_integration_sync_error":{"description":"true when the last sync with an integration failed.","type":"boolean"},"has_invoice":{"description":"true when the order has at least one invoice, so a zero invoiced total can be told apart from no invoice.","type":"boolean"},"has_not_invoiced_items":{"description":"true when some line items are not on an invoice yet.","type":"boolean"},"has_over_invoiced_items":{"description":"true when some line items are invoiced for more than the order has.","type":"boolean"},"has_shipment_items_not_allocated":{"description":"true when some line items are not on a shipment yet.","type":"boolean"},"has_shipment_items_over_allocated":{"description":"true when some line items are on shipments for more than the order has.","type":"boolean"},"has_valid_invoice":{"description":"true when at least one of the order's invoices is in a valid state.","type":"boolean"},"has_valid_shipment":{"description":"true when at least one of the order's shipments is in a valid state.","type":"boolean"},"id":{"description":"The order's hash id: use it in every other call.","example":"V4keXwwxMQyXw7","type":"string"},"internal_status":{"description":"`draft` until published.","enum":["draft","published"],"type":"string"},"inventory_status":{"description":"Stock status of the order's lines: `not_committed`, `committed`, `partially_committed`, `not_applicable` or `pending`.","type":["string","null"]},"invoice_lock_version":{"description":"Changes whenever the order's invoices change.","type":["integer","string","null"]},"invoiced_discount_subtotal":{"description":"Discounts on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_order_item_subtotal":{"description":"The lines and shipping fees the order's invoices bill (the sum of their `cart_item_subtotal`); 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_shipment_subtotal":{"description":"The shipping fees in `invoiced_order_item_subtotal`; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_tax_subtotal":{"description":"Tax on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_total":{"description":"Total of the order's invoices. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"is_client_note_editable":{"description":"false for a Shopify order, whose client note comes from Shopify.","type":"boolean"},"is_external":{"description":"true for an order synced from an integration such as Shopify.","type":"boolean"},"is_legacy":{"description":"true for an order made in the old format.","type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"job_lock_version":{"description":"Changes whenever the order's jobs change.","type":["integer","string","null"]},"last_payment_request_date":{"description":"When a payment reminder was last emailed for the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"lock_version":{"description":"Changes on every save.","type":["integer","string","null"]},"mode":{"description":"Older flag: `create` for a draft, `view` once published.","enum":["create","view","edit"],"type":"string"},"name":{"example":"Spring team shirts","type":["string","null"]},"object_type":{"enum":["sales_order","quote"],"type":"string"},"order_balance_due":{"description":"Invoiced total minus paid. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_cart_total":{"description":"The value of the order's lines: the order's own total before invoicing. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_lock_version":{"description":"Changes whenever the order's line items change.","type":["integer","string","null"]},"order_margin_percentage":{"description":"Margin, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_markup_percentage":{"description":"Markup, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_profit":{"description":"Profit. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"paid_amount":{"description":"Paid so far. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"payment_lock_version":{"description":"Changes whenever the order's payments change.","type":["integer","string","null"]},"payment_term_id":{"type":["string","null"]},"pricing_group_id":{"type":["string","null"]},"pricing_strategy":{"description":"`job_separately`, `job_together` or `service_loc_together`.","type":["string","null"]},"prod_note":{"description":"The production note.","type":["string","null"]},"producible_item_count":{"description":"Quantity to produce.","type":["number","integer","string","null"]},"quickbook_disable_sync":{"description":"true when QuickBooks sync is off for this order.","type":"boolean"},"quickbook_disable_sync_at":{"description":"When the switch was last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_disable_sync_by":{"description":"The team member who last changed the switch, or null.","type":["string","null"]},"quickbook_disable_sync_reason":{"description":"The note given at the last change of the order's QuickBooks sync switch (off or back on), at most 500 characters, or null.","type":["string","null"]},"quickbook_last_error_sync":{"description":"When a QuickBooks sync of the order last failed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_last_success_sync":{"description":"When QuickBooks last accepted the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbooks_hold":{"description":"Set when YoPrint holds back a QuickBooks payment covering this order: `code` is `changed`, `deleted` or `rejected` (the payment was changed or deleted in QuickBooks, or QuickBooks refused a change), and `detail` is `already_deposited` (the payment is in a QuickBooks bank deposit) or null. Null when nothing is held.","properties":{"code":{"enum":["changed","deleted","rejected"],"type":"string"},"detail":{"type":["string","null"]}},"type":["object","null"]},"quote":{"description":"Older flag: true for a quote.","type":"boolean"},"scoped_id":{"description":"The order number people see, `SO` and at least four digits (quotes too). Not an id.","example":"SO1001","type":"string"},"ship_due_date":{"description":"Ship due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shipment_billable_fee_invoice_status":{"description":"Whether those shipping fees are on an invoice. Null when there is nothing to bill.","type":["string","null"]},"shipment_billable_fee_total":{"description":"The shipping fees you bill the customer on the order's shipments. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_cost_total":{"description":"Shipping cost incurred. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_lock_version":{"description":"Changes whenever the order's shipments change.","type":["integer","string","null"]},"shipping_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"shipping_address_id":{"type":["string","null"]},"shopify_last_error_sync":{"description":"When a Shopify sync of the order last failed. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_last_success_sync":{"description":"When Shopify last accepted the order. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_terminal_topic":{"description":"Shopify orders only: the Shopify event name behind the order's final state there. Null on YoPrint orders. The answer can also hold more `shopify_*` fields (`shopify_admin_url`, `shopify_compliance_deletion`, `shopify_finance_notices`, `shopify_has_fulfillment_conflict`, `shopify_last_fulfillment_conflict_at`): they are null or empty on YoPrint orders.","type":["string","null"]},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"The order's status (always included).","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_completion_date":{"description":"When the order's status last moved to an end status. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status_id":{"description":"The order's status (from the team's sales order or quote statuses).","example":"52CuV8sWcDZLPm","type":"string"},"status_last_change_date":{"description":"Last status change. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"tags":{"items":{"additionalProperties":true,"properties":{"color_hex":{"description":"Tag color, for example `#E53935`.","type":["string","null"]},"id":{"example":"7qYPMmbLZR9oFg","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"total_qty_need_ordering":{"description":"Quantity still to buy, as a decimal string with 8 decimal places (`\"24.00000000\"`).","example":"0.00000000","type":"string"},"trashed":{"description":"true when the order is deleted.","type":"boolean"},"type":{"description":"Older name for `object_type`.","enum":["order","quote"],"type":"string"},"unallocated_amount":{"description":"Payments not yet allocated to an invoice. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"unique_key":{"description":"The order's unique key (`ord_…`); accepted wherever `{order_unique_key}` is.","example":"ord_EXAMPLEuniqueKey","type":"string"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"version":{"description":"The order format version.","type":["integer","string","null"]},"wallet_currency_iso":{"description":"The order's currency code (`USD` and so on), or null on older orders without one.","example":"USD","type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"required":["id","unique_key","scoped_id","object_type","internal_status"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a sales order or quote","tags":["Sales orders"],"x-yoprint-docs":{"errors":[{"fix":"Use the matching action, or a value from the team's own lists.","status":422,"when":"A field breaks one of the rules above: `validation_error` with the message (`error.fields` names `status_id`, `created_by` or `customer_id` for those), or `validation_failed` for a value of the wrong type."},{"fix":"Ask the team owner for sales order edit permission.","status":403,"when":"The API key's role can't edit this order."},{"fix":"Check the id; restore a deleted order first.","status":404,"when":"No such order in this team, or it is deleted."}],"group":"Sales","permission":"Needs permission to edit this sales order or quote:\n\n- The team owner\n- A role with `update_all_order`\n- A role with `update_self_order`, when the order was created by or is assigned to the API key's user\n- The person who created a draft, with `create_order`\n\nQuotes use the same sales order permissions.","related":["v2_public_order_single_action","v2_public_order_customer_note_update","v2_public_order_production_note_update"],"rules":["A different `customer_id` is refused: \"Cannot change customer_id via update endpoint. Use change_customer single action.\"","On a draft, a different `object_type` or `quote` is refused: \"Cannot change order identity via update endpoint. Use conversion single action.\" On a published order both fields are ignored.","`status_id` must be one of the team's statuses for this kind of order: \"This status cannot be used for this sales order. Choose another status.\"","`created_by` must be a current team member; addresses must be current team addresses.","Shopify orders can't change `status_id` here (`shopify_order_status_update_boundary`): use the `change_status` action.","Shopify orders can't change their addresses or contact (`shopify_order_snapshot_update_boundary`) or their customer, and nothing changes once the order was deleted in Shopify (`shopify_order_deleted_externally`).","Deleted orders can't be updated: restore them first.","Fields not listed above are ignored."],"side_effects":["On a published order, a new `status_id` and changes to the number, customer PO number, notes and Created By are recorded in the order history.","Refreshes the order for people who have it open in the web app. On a published order, Customer Portal pages the order's customer has open refresh (a live update, not an email)."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}/action/{action_name}":{"put":{"description":"Runs one named action on an order. Put the action's name in the path (`{action_name}`) and its fields in the body.\n\nThe `send_order_detail`, `send_payment_reminder` and `send_approval_reminder` actions email the customer. Email limit: if your team makes more than 60 of these calls in a minute, or goes over the daily email limit for its plan, YoPrint blocks email sending for your whole team until YoPrint support lifts the block. Never call this in a loop.\n\n| `action_name` | Body | Draft | Published |\n| --- | --- | --- | --- |\n| `change_status` | `value`: status id | no | yes |\n| `change_customer` | `value`: customer id | yes | no |\n| `change_issue_date` | `value`: date; also moves the order's other dates, its jobs and invoices by the same amount | yes | yes |\n| `change_customer_due_date`, `change_ship_due_date` | `value`: date or null, not before the issue date | yes | yes |\n| `change_deposit_due`, `change_full_amount_due` | `value`: date or null; deposit due can't be after full payment due | yes | yes |\n| `change_start_end_date_date` | `start_date`, `due_date`: both dates or both null | yes | yes |\n| `change_payment_term` | `payment_term_id`, `deposit_due`, `full_amount_due`, optional `deposit_total` (a percentage) | yes | yes |\n| `change_pricing_group` | `pricing_group_id` | yes | yes |\n| `change_pricing_strategy` | `pricing_strategy` | yes | yes |\n| `change_warehouse` | `warehouse_id` | yes | yes |\n| `clone_order` | `is_time_shift`, `cloned_anchor_date`, `item_choices`, optional `pricing_group_id` | yes | yes |\n| `convert_to_quote`, `convert_to_sales_order` | optional `status_id` and `pricing_group_id` | yes | yes |\n| `bulk_change_invoice_address`, `bulk_change_shipment_address` | address flags and ids | yes | yes |\n| `configure_order_auto_invoice_managed` | the three auto-invoice fields | yes | yes |\n| `mark_order_as_rush`, `mark_order_as_not_rush`, `mark_all_job_as_rush`, `mark_all_job_as_not_rush` | `{}` | yes | yes |\n| `send_order_detail`, `send_payment_reminder`, `send_approval_reminder` | `{}` | no | yes |\n\nDates are ISO 8601, such as `2026-11-05`. An action that is not allowed for the order's state (draft or published) fails with `object_action_error` \"Action not found\".\n\nThe answer is the order after the action (for `clone_order` the new draft copy; for `convert_to_quote` and `convert_to_sales_order` the converted document, with the same `id`). `change_customer` adds `customer_profile` and `participants`; `change_pricing_group` and `change_pricing_strategy` add `items` and `participants`. Three actions answer differently: `bulk_change_invoice_address` returns the order's invoices with their lines (as List the invoices of a sales order), `bulk_change_shipment_address` returns the order's shipments with their lines, estimates and packages (as List the shipments of a sales order), and `configure_order_auto_invoice_managed` returns `data: null`.\n\n**These email the customer:** `send_order_detail` (the order or quote detail template; nothing is sent if the team has no such template), `send_payment_reminder` (only when the order is not fully paid; otherwise nothing is sent) and `send_approval_reminder` (needs an open approval and a recipient with an email address).\n\n`{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.","operationId":"v2_public_order_single_action","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"order_unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The action to run. See the table for each one's body and when it is allowed.","example":"change_status","in":"path","name":"action_name","required":true,"schema":{"enum":["change_status","change_customer","change_issue_date","change_customer_due_date","change_ship_due_date","change_deposit_due","change_full_amount_due","change_start_end_date_date","change_payment_term","change_pricing_group","change_pricing_strategy","change_warehouse","clone_order","convert_to_quote","convert_to_sales_order","bulk_change_invoice_address","bulk_change_shipment_address","configure_order_auto_invoice_managed","mark_order_as_rush","mark_order_as_not_rush","mark_all_job_as_rush","mark_all_job_as_not_rush","send_order_detail","send_payment_reminder","send_approval_reminder"],"example":"change_status","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"bulk_change_invoice_address":{"summary":"bulk_change_invoice_address","value":{"billing_address_id":"wvwxl8XfNRzRhC","update_billing_address":true,"update_shipping_address":false},"x-yoprint-path-parameters":{"action_name":"bulk_change_invoice_address"},"x-yoprint-variant":"bulk_change_invoice_address"},"bulk_change_shipment_address":{"summary":"bulk_change_shipment_address","value":{"shipping_address_id":"RNG2OuYC20YzXs","update_shipping_address":true},"x-yoprint-path-parameters":{"action_name":"bulk_change_shipment_address"},"x-yoprint-variant":"bulk_change_shipment_address"},"change_customer":{"summary":"change_customer","value":{"value":"GI8C9GWswRirDL"},"x-yoprint-path-parameters":{"action_name":"change_customer"},"x-yoprint-variant":"change_customer"},"change_customer_due_date":{"summary":"change_customer_due_date","value":{"value":"2026-11-20"},"x-yoprint-path-parameters":{"action_name":"change_customer_due_date"},"x-yoprint-variant":"change_customer_due_date"},"change_deposit_due":{"summary":"change_deposit_due","value":{"value":"2026-11-08"},"x-yoprint-path-parameters":{"action_name":"change_deposit_due"},"x-yoprint-variant":"change_deposit_due"},"change_full_amount_due":{"summary":"change_full_amount_due","value":{"value":"2026-11-30"},"x-yoprint-path-parameters":{"action_name":"change_full_amount_due"},"x-yoprint-variant":"change_full_amount_due"},"change_issue_date":{"summary":"change_issue_date","value":{"value":"2026-11-05"},"x-yoprint-path-parameters":{"action_name":"change_issue_date"},"x-yoprint-variant":"change_issue_date"},"change_payment_term":{"summary":"change_payment_term","value":{"deposit_due":"2026-11-08","deposit_total":{"dp":3,"value":50000},"full_amount_due":"2026-11-30","payment_term_id":"w57OrAv5fu6FoG"},"x-yoprint-path-parameters":{"action_name":"change_payment_term"},"x-yoprint-variant":"change_payment_term"},"change_pricing_group":{"summary":"change_pricing_group","value":{"pricing_group_id":"PvlX5QRtc6cV6V"},"x-yoprint-path-parameters":{"action_name":"change_pricing_group"},"x-yoprint-variant":"change_pricing_group"},"change_pricing_strategy":{"summary":"change_pricing_strategy","value":{"pricing_strategy":"job_together"},"x-yoprint-path-parameters":{"action_name":"change_pricing_strategy"},"x-yoprint-variant":"change_pricing_strategy"},"change_ship_due_date":{"summary":"change_ship_due_date","value":{"value":"2026-11-18"},"x-yoprint-path-parameters":{"action_name":"change_ship_due_date"},"x-yoprint-variant":"change_ship_due_date"},"change_start_end_date_date":{"summary":"change_start_end_date_date","value":{"due_date":"2026-11-14","start_date":"2026-11-10"},"x-yoprint-path-parameters":{"action_name":"change_start_end_date_date"},"x-yoprint-variant":"change_start_end_date_date"},"change_status":{"summary":"change_status","value":{"value":"52CuV8sWcDZLPm"},"x-yoprint-path-parameters":{"action_name":"change_status"},"x-yoprint-variant":"change_status"},"change_warehouse":{"summary":"change_warehouse","value":{"warehouse_id":"HjfVkHROYx8Xnu"},"x-yoprint-path-parameters":{"action_name":"change_warehouse"},"x-yoprint-variant":"change_warehouse"},"clone_order":{"summary":"clone_order","value":{"is_time_shift":false},"x-yoprint-path-parameters":{"action_name":"clone_order"},"x-yoprint-variant":"clone_order"},"configure_order_auto_invoice_managed":{"summary":"configure_order_auto_invoice_managed","value":{"auto_invoice_managed":true,"auto_invoice_shipment_price_type":"MARKUP","auto_invoice_shipment_rate":{"dp":0,"value":20}},"x-yoprint-path-parameters":{"action_name":"configure_order_auto_invoice_managed"},"x-yoprint-variant":"configure_order_auto_invoice_managed"},"convert_to_quote":{"summary":"convert_to_quote","value":{},"x-yoprint-path-parameters":{"action_name":"convert_to_quote"},"x-yoprint-variant":"convert_to_quote"},"convert_to_sales_order":{"summary":"convert_to_sales_order","value":{},"x-yoprint-path-parameters":{"action_name":"convert_to_sales_order"},"x-yoprint-variant":"convert_to_sales_order"},"mark_all_job_as_not_rush":{"summary":"mark_all_job_as_not_rush","value":{},"x-yoprint-path-parameters":{"action_name":"mark_all_job_as_not_rush"},"x-yoprint-variant":"mark_all_job_as_not_rush"},"mark_all_job_as_rush":{"summary":"mark_all_job_as_rush","value":{},"x-yoprint-path-parameters":{"action_name":"mark_all_job_as_rush"},"x-yoprint-variant":"mark_all_job_as_rush"},"mark_order_as_not_rush":{"summary":"mark_order_as_not_rush","value":{},"x-yoprint-path-parameters":{"action_name":"mark_order_as_not_rush"},"x-yoprint-variant":"mark_order_as_not_rush"},"mark_order_as_rush":{"summary":"mark_order_as_rush","value":{},"x-yoprint-path-parameters":{"action_name":"mark_order_as_rush"},"x-yoprint-variant":"mark_order_as_rush"},"send_approval_reminder":{"summary":"send_approval_reminder","value":{},"x-yoprint-path-parameters":{"action_name":"send_approval_reminder"},"x-yoprint-variant":"send_approval_reminder"},"send_order_detail":{"summary":"send_order_detail","value":{},"x-yoprint-path-parameters":{"action_name":"send_order_detail"},"x-yoprint-variant":"send_order_detail"},"send_payment_reminder":{"summary":"send_payment_reminder","value":{},"x-yoprint-path-parameters":{"action_name":"send_payment_reminder"},"x-yoprint-variant":"send_payment_reminder"}},"schema":{"anyOf":[{"description":"Published orders only. Moves the order to another status.","properties":{"value":{"description":"A status id from the team's sales order statuses (or quote statuses for a quote).","type":"string"}},"required":["value"],"title":"change_status","type":"object"},{"description":"Drafts only. Sets another customer and resets order defaults (brand profile, addresses, contact, payment term, warehouse, pricing group, and invoices).","properties":{"value":{"description":"The new customer's `id`.","type":"string"}},"required":["value"],"title":"change_customer","type":"object"},{"description":"Sets the issue date and moves the other dates by the same number of days (including its jobs and invoices).","properties":{"shift_other_date":{"description":"Accepted and ignored: the other dates, jobs, and invoices always move by the same number of days with the issue date.","type":"boolean"},"value":{"description":"The new issue date (ISO 8601).","format":"date","type":"string"}},"required":["value"],"title":"change_issue_date","type":"object"},{"description":"Sets the in-hands date; not before the issue date.","properties":{"value":{"description":"The new date (ISO 8601), or `null` (or an empty string) to clear it. Leaving `value` out also clears it.","format":"date","type":["string","null"]}},"title":"change_customer_due_date","type":"object"},{"description":"Sets the ship due date; not before the issue date.","properties":{"value":{"description":"The new date (ISO 8601), or `null` (or an empty string) to clear it. Leaving `value` out also clears it.","format":"date","type":["string","null"]}},"title":"change_ship_due_date","type":"object"},{"description":"Sets the deposit due date; not after the full payment due date.","properties":{"value":{"description":"The new date (ISO 8601), or `null` (or an empty string) to clear it. Leaving `value` out also clears it.","format":"date","type":["string","null"]}},"title":"change_deposit_due","type":"object"},{"description":"Sets the full payment due date; not before the deposit due date.","properties":{"value":{"description":"The new date (ISO 8601), or `null` (or an empty string) to clear it. Leaving `value` out also clears it.","format":"date","type":["string","null"]}},"title":"change_full_amount_due","type":"object"},{"description":"Sets both production dates, or clears both with null.","properties":{"due_date":{"description":"Production due date, or null.","format":"date","type":["string","null"]},"start_date":{"description":"Production start date, or null.","format":"date","type":["string","null"]}},"required":["start_date","due_date"],"title":"change_start_end_date_date","type":"object"},{"description":"Sets the payment term, the deposit percentage and the due dates.","properties":{"deposit_due":{"description":"Deposit due date, or null for no deposit. Required (may be null).","format":"date","type":["string","null"]},"deposit_required":{"description":"Ignored: a deposit is required exactly when `deposit_due` is set.","type":"boolean"},"deposit_total":{"description":"Optional deposit percentage. Sent as a percentage ×1000 inside a decimal pair with `dp` exactly 3: `50000` with `dp` 3 is 50% (`{ \"value\": 50000, \"dp\": 3 }`). YoPrint works out the deposit amount (`calc_deposit_total`) from it. Leave it out to keep the current percentage.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"full_amount_due":{"description":"Full payment due date, or null. Required (may be null).","format":"date","type":["string","null"]},"payment_term_id":{"description":"A payment term id from the team's payment terms.","type":"string"}},"required":["payment_term_id","deposit_due","full_amount_due"],"title":"change_payment_term","type":"object"},{"description":"Changes the pricing group and reprices every line. A removed group is refused, and so is a turned-off group unless the order is already on it.","properties":{"pricing_group_id":{"description":"A pricing group id. Pricing groups are not listed on the public API: copy `pricing_group_id` from a sales order or quote that uses the group (Get a sales order or quote), or `default_pricing_group_id` from a customer that has it (Get a customer).","type":"string"}},"required":["pricing_group_id"],"title":"change_pricing_group","type":"object"},{"description":"Changes how decoration is priced and reprices the order.","properties":{"pricing_strategy":{"description":"How decoration quantity breaks are counted: per job, across jobs, or across jobs per print location.","enum":["job_separately","job_together","service_loc_together"],"type":"string"}},"required":["pricing_strategy"],"title":"change_pricing_strategy","type":"object"},{"description":"Changes the warehouse the order ships and takes stock from. On a published order that already has stock allocated, or a pending or in-progress stock flow, nothing changes (the answer still shows the old warehouse).","properties":{"warehouse_id":{"description":"A current store location of the team.","type":"string"}},"required":["warehouse_id"],"title":"change_warehouse","type":"object"},{"description":"Copies the order into a new draft with a new number and the starting status. Answers with the new draft.","properties":{"cloned_anchor_date":{"description":"The copy's issue date. Required when `is_time_shift` is true. A date-time with an offset is taken as that moment (stored in UTC).","format":"date","type":"string"},"is_time_shift":{"description":"true to move all dates so the copy's issue date is `cloned_anchor_date`; false to keep the original dates.","type":"boolean"},"item_choices":{"description":"Required for each line on a phased-out or deleted product, size or color, and only for those: leave it out, or replace it with another size or color of the same product.","items":{"properties":{"action":{"enum":["leave_out","replace"],"type":"string"},"id":{"description":"The source line's id.","type":"string"},"replacement_id":{"description":"With `replace`: the size or color (variant) to use instead. Simple products can only be left out.","type":"string"}},"required":["id","action"],"type":"object"},"type":"array"},"pricing_group_id":{"description":"Optional: the pricing group for the copy, which is repriced with it. Required when the order's own group was removed (`clone_needs_pricing_group`).","type":"string"}},"required":["is_time_shift"],"title":"clone_order","type":"object"},{"description":"Turns a sales order into a quote.","properties":{"pricing_group_id":{"description":"Optional: another pricing group for the converted document, which is repriced with it. Required when the document's own group was removed (`clone_needs_pricing_group`).","type":"string"},"status_id":{"description":"Optional: the status to give the converted document. Default: the team's starting status.","type":"string"}},"title":"convert_to_quote","type":"object"},{"description":"Turns a quote into a sales order.","properties":{"pricing_group_id":{"description":"Optional: another pricing group for the converted document, which is repriced with it. Required when the document's own group was removed (`clone_needs_pricing_group`).","type":"string"},"status_id":{"description":"Optional: the status to give the converted document. Default: the team's starting status.","type":"string"}},"title":"convert_to_sales_order","type":"object"},{"description":"Sets the billing and/or shipping address on every invoice of the order and redoes Auto Tax for the new addresses. Answers with the order's invoices, not the order.","properties":{"billing_address_id":{"description":"Required (may be null) when `update_billing_address` is true.","type":["string","null"]},"shipping_address_id":{"description":"Required (may be null) when `update_shipping_address` is true.","type":["string","null"]},"update_billing_address":{"type":"boolean"},"update_shipping_address":{"type":"boolean"}},"required":["update_billing_address","update_shipping_address"],"title":"bulk_change_invoice_address","type":"object"},{"description":"Sets the shipping address on every shipment of the order except pick-up shipments. Answers with the order's shipments, not the order.","properties":{"shipping_address_id":{"description":"Required (may be null) when `update_shipping_address` is true.","type":["string","null"]},"update_shipping_address":{"type":"boolean"}},"required":["update_shipping_address"],"title":"bulk_change_shipment_address","type":"object"},{"description":"Turns the automatic invoice on or off; here, shipping at a 20% markup. Answers with `data: null`.","properties":{"auto_invoice_managed":{"description":"true to keep one invoice in step with the order automatically.","type":"boolean"},"auto_invoice_shipment_price_type":{"description":"Shipping on that invoice: `DONOTMANAGE` adds none, `NONE` charges the shipping cost, `MARKUP` adds `rate` percent to it (at least -100), `MARGIN` prices it for a `rate` percent margin (0 to under 100).","enum":["DONOTMANAGE","NONE","MARKUP","MARGIN"],"type":"string"},"auto_invoice_shipment_rate":{"description":"The percentage for MARKUP or MARGIN, as a `{ value, dp }` pair; `dp` 0 to 16. Send 0 for the other types.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["auto_invoice_managed","auto_invoice_shipment_price_type","auto_invoice_shipment_rate"],"title":"configure_order_auto_invoice_managed","type":"object"},{"description":"No fields: send `{}`.","title":"mark_order_as_rush","type":"object"},{"description":"No fields: send `{}`.","title":"mark_order_as_not_rush","type":"object"},{"description":"No fields: send `{}`.","title":"mark_all_job_as_rush","type":"object"},{"description":"No fields: send `{}`.","title":"mark_all_job_as_not_rush","type":"object"},{"description":"No fields: send `{}`.","title":"send_order_detail","type":"object"},{"description":"No fields: send `{}`.","title":"send_payment_reminder","type":"object"},{"description":"No fields: send `{}`.","title":"send_approval_reminder","type":"object"}],"title":"Which action?","x-yoprint-discriminator":{"mapping":{"bulk_change_invoice_address":"bulk_change_invoice_address","bulk_change_shipment_address":"bulk_change_shipment_address","change_customer":"change_customer","change_customer_due_date":"change_customer_due_date","change_deposit_due":"change_deposit_due","change_full_amount_due":"change_full_amount_due","change_issue_date":"change_issue_date","change_payment_term":"change_payment_term","change_pricing_group":"change_pricing_group","change_pricing_strategy":"change_pricing_strategy","change_ship_due_date":"change_ship_due_date","change_start_end_date_date":"change_start_end_date_date","change_status":"change_status","change_warehouse":"change_warehouse","clone_order":"clone_order","configure_order_auto_invoice_managed":"configure_order_auto_invoice_managed","convert_to_quote":"convert_to_quote","convert_to_sales_order":"convert_to_sales_order","mark_all_job_as_not_rush":"mark_all_job_as_not_rush","mark_all_job_as_rush":"mark_all_job_as_rush","mark_order_as_not_rush":"mark_order_as_not_rush","mark_order_as_rush":"mark_order_as_rush","send_approval_reminder":"send_approval_reminder","send_order_detail":"send_order_detail","send_payment_reminder":"send_payment_reminder"},"pathParameter":"action_name"}}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"calc_deposit_total":67500,"customer":{"id":"63KcENAAsKuipY","is_external":false,"name":"Northwind Apparel","tax_exempt":false},"customer_id":"63KcENAAsKuipY","customer_po_number":"PO-1188","deposit_amount_due":{"dp":4,"value":175000},"deposit_required":true,"deposit_total":50000,"due_date":"2026-11-14T00:00:00+00:00","id":"V4keXwwxMQyXw7","internal_status":"published","invoiced_discount_subtotal":{"dp":4,"value":0},"invoiced_order_item_subtotal":{"dp":4,"value":1250000},"invoiced_shipment_subtotal":{"dp":4,"value":0},"invoiced_tax_subtotal":{"dp":4,"value":100000},"invoiced_total":{"dp":4,"value":1350000},"is_rush":false,"issue_date":"2026-11-03T00:00:00+00:00","mode":"view","name":"Spring team shirts","object_type":"sales_order","order_balance_due":{"dp":4,"value":850000},"order_item_cart_total":{"dp":4,"value":1250000},"paid_amount":50000,"quote":false,"scoped_id":"SO1001","status":{"color":"#2196f3","customer_label":"In Progress","id":"52CuV8sWcDZLPm","label":"In production","position":2,"role":"order","trashed":false,"type":"in_progress"},"status_id":"52CuV8sWcDZLPm","total_qty_need_ordering":"0.00000000","trashed":false,"type":"order","unique_key":"ord_EXAMPLEuniqueKey"},"status":200,"success":true},"schema":{"properties":{"data":{"anyOf":[{"additionalProperties":true,"description":"Every action except the three below: the sales order or quote after the action. `clone_order`: the new draft copy. `convert_to_quote` and `convert_to_sales_order`: the converted document (same `id`).","properties":{"approval_status":{"description":"`requested`, `sent-to-customer`, `viewed-by-customer`, `need-changes` or `approved`; null without approvals.","type":["string","null"]},"assigned_users":{"description":"The team members in the order's Assigned To list (always included).","items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"auto_invoice_managed":{"description":"true when YoPrint keeps one invoice in step with the order.","type":"boolean"},"auto_invoice_shipment_price_type":{"description":"`DONOTMANAGE`, `NONE`, `MARKUP` or `MARGIN`.","type":["string","null"]},"auto_invoice_shipment_rate":{"description":"The MARKUP or MARGIN percentage. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"auto_invoice_type":{"description":"How the automatic invoice is built. Always `single_invoice` today.","type":["string","null"]},"billing_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"billing_address_id":{"type":["string","null"]},"calc_deposit_total":{"description":"The deposit amount, rounded to 2 decimal places: the percentage of `order_item_cart_total`, or of the invoiced total once every line is invoiced (or the invoiced total reaches the order's); 0 unless `deposit_required`. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `invoiced_discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `invoiced_order_item_subtotal`, which already includes billed shipping. This older field adds `invoiced_shipment_subtotal` to it once more. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `invoiced_tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `invoiced_total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"client_note":{"description":"The Client Note.","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_by":{"description":"Created By (a team member id).","type":["string","null"]},"creator_name":{"type":["string","null"]},"cust_due_date":{"description":"Customer in-hands date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"Always present on order answers, lists included: the customer record, or null when the order has none. Get a sales order also nests the customer's contacts, addresses, brand profiles, tags, files and assigned users in it.","properties":{"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"id":{"example":"63KcENAAsKuipY","type":"string"},"is_external":{"description":"true for a customer synced from an integration.","type":"boolean"},"name":{"example":"Northwind Apparel","type":"string"},"tax_exempt":{"type":"boolean"}},"type":["object","null"]},"customer_billing_contact_id":{"description":"The id of the contact on the order (the same contact as `customer_contact_id`), or null.","type":["string","null"]},"customer_contact_id":{"type":["string","null"]},"customer_has_email":{"type":"boolean"},"customer_id":{"example":"63KcENAAsKuipY","type":["string","null"]},"customer_po_number":{"example":"PO-1188","type":["string","null"]},"customer_profile":{"additionalProperties":true,"description":"`change_customer` only: the brand profile after the change, or null.","type":["object","null"]},"customer_profile_id":{"description":"Brand profile.","type":["string","null"]},"deposit_amount_due":{"description":"Deposit still to pay (negative once overpaid). A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"deposit_due":{"description":"Deposit due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"deposit_required":{"type":"boolean"},"deposit_total":{"description":"The deposit as a **percentage** of the order. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","type":["integer","number","string","null"]},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"external_ids":{"description":"The order's links to records in other systems. An empty list when there are none.","items":{"additionalProperties":true,"description":"One link to a record in another system (Shopify, QuickBooks and so on): `id`, `external_integration_id`, `external_id`, `data`, `created_at`, `updated_at` and the nested `external_integration`.","type":"object"},"type":"array"},"external_type":{"description":"`shopify` for a Shopify order; null for YoPrint orders.","type":["string","null"]},"from_legacy":{"description":"true for an order that was moved over from the old format.","type":"boolean"},"full_amount_due":{"description":"Full payment due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"grouped_pdf":{"description":"PDF links, grouped: `Main` (only for roles with `view_order_finance`), `Job` (not on Shopify orders), `Shipment` and the team's templates.","items":{"additionalProperties":true,"properties":{"documents":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"label":{"example":"Main","type":"string"}},"type":"object"},"type":"array"},"has_external_integration_sync_error":{"description":"true when the last sync with an integration failed.","type":"boolean"},"has_invoice":{"description":"true when the order has at least one invoice, so a zero invoiced total can be told apart from no invoice.","type":"boolean"},"has_not_invoiced_items":{"description":"true when some line items are not on an invoice yet.","type":"boolean"},"has_over_invoiced_items":{"description":"true when some line items are invoiced for more than the order has.","type":"boolean"},"has_shipment_items_not_allocated":{"description":"true when some line items are not on a shipment yet.","type":"boolean"},"has_shipment_items_over_allocated":{"description":"true when some line items are on shipments for more than the order has.","type":"boolean"},"has_valid_invoice":{"description":"true when at least one of the order's invoices is in a valid state.","type":"boolean"},"has_valid_shipment":{"description":"true when at least one of the order's shipments is in a valid state.","type":"boolean"},"id":{"description":"The order's hash id: use it in every other call.","example":"V4keXwwxMQyXw7","type":"string"},"internal_status":{"description":"`draft` until published.","enum":["draft","published"],"type":"string"},"inventory_status":{"description":"Stock status of the order's lines: `not_committed`, `committed`, `partially_committed`, `not_applicable` or `pending`.","type":["string","null"]},"invoice_lock_version":{"description":"Changes whenever the order's invoices change.","type":["integer","string","null"]},"invoiced_discount_subtotal":{"description":"Discounts on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_order_item_subtotal":{"description":"The lines and shipping fees the order's invoices bill (the sum of their `cart_item_subtotal`); 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_shipment_subtotal":{"description":"The shipping fees in `invoiced_order_item_subtotal`; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_tax_subtotal":{"description":"Tax on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_total":{"description":"Total of the order's invoices. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"is_client_note_editable":{"description":"false for a Shopify order, whose client note comes from Shopify.","type":"boolean"},"is_external":{"description":"true for an order synced from an integration such as Shopify.","type":"boolean"},"is_legacy":{"description":"true for an order made in the old format.","type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"items":{"description":"`change_pricing_group` and `change_pricing_strategy` only: the repriced lines.","items":{"additionalProperties":true,"description":"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).","properties":{"_meta":{"additionalProperties":true,"description":"The line's own values again (`id`, `type`, `order_id`, `unit_price`, `subtotal` and so on). Always an object.","type":"object"},"id":{"example":"Owr88lhAk28aqL","type":"string"},"inventory_status":{"description":"Stock status of the line.","type":["string","null"]},"job":{"additionalProperties":true,"type":"object"},"lock_version":{"description":"The line's own lock version (a microsecond timestamp).","type":["integer","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_unique_key":{"description":"The order's `unique_key`. The line's own `unique_key` is not in the answer: use `id`.","example":"ord_EXAMPLEuniqueKey","type":"string"},"position":{"example":200000,"type":"integer"},"pricing":{"additionalProperties":true,"type":"object"},"pricing_rule_applied":{"description":"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.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"11.05","type":"string"},"after_total":{"description":"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.","example":{"dp":6,"value":11050000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: that starting price, as a decimal string with at least 2 decimal places.","example":"8.50","type":"string"},"base_type":{"description":"Full summary only: what the rule started from: the supplier price for catalog lines, the product's own price for other lines.","enum":["supplier_price","base_price"],"type":"string"},"normal_price":{"description":"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`.","example":"11.05","type":["string","null"]},"original_total":{"description":"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.","example":{"dp":6,"value":8500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The line keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`product` on a line.","example":"product","type":"string"}},"type":["object","null"]},"product":{"additionalProperties":true,"type":"object"},"quantity":{"additionalProperties":true,"description":"The quantity, trailing zeros dropped: 10 is `{ \"value\": 10, \"dp\": 0 }`.","type":"object"},"subtotal":{"description":"`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.","example":{"dp":4,"value":1250000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"trashed":{"description":"true when the line was deleted.","example":false,"type":"boolean"},"type":{"description":"The kind of line: db_catalog, user_simple, db_variant, custom or fee.","example":"user_simple","type":"string"},"unit_price":{"description":"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.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"}},"type":"object"},"type":"array"},"job_lock_version":{"description":"Changes whenever the order's jobs change.","type":["integer","string","null"]},"last_payment_request_date":{"description":"When a payment reminder was last emailed for the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"lock_version":{"description":"Changes on every save.","type":["integer","string","null"]},"mode":{"description":"Older flag: `create` for a draft, `view` once published.","enum":["create","view","edit"],"type":"string"},"name":{"example":"Spring team shirts","type":["string","null"]},"object_type":{"enum":["sales_order","quote"],"type":"string"},"order_balance_due":{"description":"Invoiced total minus paid. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_cart_total":{"description":"The value of the order's lines: the order's own total before invoicing. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_lock_version":{"description":"Changes whenever the order's line items change.","type":["integer","string","null"]},"order_margin_percentage":{"description":"Margin, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_markup_percentage":{"description":"Markup, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_profit":{"description":"Profit. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"paid_amount":{"description":"Paid so far. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"participants":{"description":"`change_customer`, `change_pricing_group` and `change_pricing_strategy` only: who receives the order's messages.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"payment_lock_version":{"description":"Changes whenever the order's payments change.","type":["integer","string","null"]},"payment_term_id":{"type":["string","null"]},"pricing_group_id":{"type":["string","null"]},"pricing_strategy":{"description":"`job_separately`, `job_together` or `service_loc_together`.","type":["string","null"]},"prod_note":{"description":"The production note.","type":["string","null"]},"producible_item_count":{"description":"Quantity to produce.","type":["number","integer","string","null"]},"quickbook_disable_sync":{"description":"true when QuickBooks sync is off for this order.","type":"boolean"},"quickbook_disable_sync_at":{"description":"When the switch was last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_disable_sync_by":{"description":"The team member who last changed the switch, or null.","type":["string","null"]},"quickbook_disable_sync_reason":{"description":"The note given at the last change of the order's QuickBooks sync switch (off or back on), at most 500 characters, or null.","type":["string","null"]},"quickbook_last_error_sync":{"description":"When a QuickBooks sync of the order last failed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_last_success_sync":{"description":"When QuickBooks last accepted the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbooks_hold":{"description":"Set when YoPrint holds back a QuickBooks payment covering this order: `code` is `changed`, `deleted` or `rejected` (the payment was changed or deleted in QuickBooks, or QuickBooks refused a change), and `detail` is `already_deposited` (the payment is in a QuickBooks bank deposit) or null. Null when nothing is held.","properties":{"code":{"enum":["changed","deleted","rejected"],"type":"string"},"detail":{"type":["string","null"]}},"type":["object","null"]},"quote":{"description":"Older flag: true for a quote.","type":"boolean"},"scoped_id":{"description":"The order number people see, `SO` and at least four digits (quotes too). Not an id.","example":"SO1001","type":"string"},"ship_due_date":{"description":"Ship due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shipment_billable_fee_invoice_status":{"description":"Whether those shipping fees are on an invoice. Null when there is nothing to bill.","type":["string","null"]},"shipment_billable_fee_total":{"description":"The shipping fees you bill the customer on the order's shipments. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_cost_total":{"description":"Shipping cost incurred. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_lock_version":{"description":"Changes whenever the order's shipments change.","type":["integer","string","null"]},"shipping_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"shipping_address_id":{"type":["string","null"]},"shopify_last_error_sync":{"description":"When a Shopify sync of the order last failed. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_last_success_sync":{"description":"When Shopify last accepted the order. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_terminal_topic":{"description":"Shopify orders only: the Shopify event name behind the order's final state there. Null on YoPrint orders. The answer can also hold more `shopify_*` fields (`shopify_admin_url`, `shopify_compliance_deletion`, `shopify_finance_notices`, `shopify_has_fulfillment_conflict`, `shopify_last_fulfillment_conflict_at`): they are null or empty on YoPrint orders.","type":["string","null"]},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"The order's status (always included).","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_completion_date":{"description":"When the order's status last moved to an end status. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status_id":{"description":"The order's status (from the team's sales order or quote statuses).","example":"52CuV8sWcDZLPm","type":"string"},"status_last_change_date":{"description":"Last status change. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"tags":{"items":{"additionalProperties":true,"properties":{"color_hex":{"description":"Tag color, for example `#E53935`.","type":["string","null"]},"id":{"example":"7qYPMmbLZR9oFg","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"total_qty_need_ordering":{"description":"Quantity still to buy, as a decimal string with 8 decimal places (`\"24.00000000\"`).","example":"0.00000000","type":"string"},"trashed":{"description":"true when the order is deleted.","type":"boolean"},"type":{"description":"Older name for `object_type`.","enum":["order","quote"],"type":"string"},"unallocated_amount":{"description":"Payments not yet allocated to an invoice. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"unique_key":{"description":"The order's unique key (`ord_…`); accepted wherever `{order_unique_key}` is.","example":"ord_EXAMPLEuniqueKey","type":"string"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"version":{"description":"The order format version.","type":["integer","string","null"]},"wallet_currency_iso":{"description":"The order's currency code (`USD` and so on), or null on older orders without one.","example":"USD","type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"required":["id","unique_key","scoped_id","object_type","internal_status"],"title":"The order","type":"object"},{"description":"`bulk_change_invoice_address` only: every invoice of the order that is not deleted, with its lines, as List the invoices of a sales order returns them; `[]` when there are none.","items":{"additionalProperties":true,"description":"An invoice.","properties":{"auto_invoice_managed":{"type":"boolean"},"billing_address_id":{"type":["string","null"]},"calc_deposit_total":{"description":"The order's deposit amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"cart_item_subtotal":{"description":"Lines subtotal. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"The customer record, with the same fields as Get a customer (`GET /v1/api/store/{team_slug}/customer/{hash_id}`); the main ones are listed here.","properties":{"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"id":{"example":"63KcENAAsKuipY","type":"string"},"is_external":{"description":"true for a customer synced from an integration.","type":"boolean"},"name":{"example":"Northwind Apparel","type":"string"},"tax_exempt":{"type":"boolean"}},"type":["object","null"]},"discount_subtotal":{"description":"Discount. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"id":{"example":"QRbvVd2ZKcvSTB","type":"string"},"is_paid":{"type":"boolean"},"is_valid":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"items":{"description":"The invoice lines.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"paid_amount":{"description":"Paid on this invoice. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"pdf_url":{"description":"The invoice PDF links, despite the name: a list, first the standard invoice, then one per invoice PDF template the team has turned on.","items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"label":{"example":"Invoice","type":"string"},"object_type":{"example":"invoice","type":"string"},"url":{"description":"Link to the PDF.","type":"string"}},"type":"object"},"type":"array"},"scoped_id":{"description":"The invoice number, from the team's invoice counter.","example":"1001","type":"string"},"shipment_subtotal":{"description":"Shipping. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_tax_subtotal":{"description":"Tax on shipping. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipping_address_id":{"type":["string","null"]},"tax_subtotal":{"description":"Tax. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"total":{"description":"Invoice total. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"}},"required":["id","order_id","total"],"type":"object"},"title":"The order's invoices","type":"array"},{"description":"`bulk_change_shipment_address` only: every shipment of the order that is not deleted (pick-up shipments included, unchanged) with its lines, estimates and packages, as List the shipments of a sales order returns them; `[]` when there are none.","items":{"additionalProperties":true,"description":"A shipment.","properties":{"billable_fee_total":{"description":"Shipping charged to the customer. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"cost_total":{"description":"Shipping cost. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"customer_due_date":{"description":"The order's in-hands date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_id":{"type":["string","null"]},"delivery_notes":{"type":["string","null"]},"id":{"example":"qAKg4jO63uFqjs","type":"string"},"internal_notes":{"type":["string","null"]},"is_external":{"type":"boolean"},"is_valid":{"type":"boolean"},"items":{"description":"Shipment lines (list only).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"ready_to_ship":{"type":"boolean"},"receiver_contact_id":{"type":["string","null"]},"scoped_id":{"description":"The shipment number.","example":"SHIP-1001","type":"string"},"shipment_estimates":{"description":"Shipping estimates (list only).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"shipment_packages":{"description":"Packages (list only).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"shipping_address_id":{"type":["string","null"]},"shipping_type_id":{"type":["string","null"]},"status":{"additionalProperties":true,"description":"A status, as the status operations return it.","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_id":{"example":"lziIhzgc0acXFc","type":"string"}},"required":["id","order_id","status_id"],"type":"object"},"title":"The order's shipments","type":"array"},{"description":"`configure_order_auto_invoice_managed` only: `data` is null.","title":"No data","type":"null"}],"description":"Depends on the action: see the description.","title":"What came back?"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Run an action on a sales order or quote","tags":["Sales orders"],"x-yoprint-docs":{"errors":[{"fix":"Check the table: some actions are drafts-only or published-only.","status":422,"when":"The action name is unknown, or not allowed for a draft or published order: \"Action not found\" (`object_action_error`)."},{"fix":"Read `error.code`, `error.message` and `error.fields`.","status":422,"when":"The body breaks a rule above: field rules and MARKUP/MARGIN limits (`validation_failed`, with `error.fields`); dates out of order, a customer that can't change, an address or warehouse that can't be used, or an action an integration-synced order doesn't allow (`validation_error`); production dates not both set, or due before start (`job_validation_error`); clone choices (`clone_needs_choices`, `clone_choice_not_needed`, `clone_choice_unknown_line`, `clone_replacement_invalid`); a conversion that isn't possible (`object_action_error`)."},{"fix":"Send another `pricing_group_id`.","status":422,"when":"A pricing group that can't be used: removed (`pricing_group_removed`), turned off (`pricing_group_disabled`), or the order's own group was removed and a copy or conversion needs another (`clone_needs_pricing_group`, with `error.suggested_pricing_group`)."},{"fix":"Create an approval first, or add a contact with an email address.","status":422,"when":"`send_approval_reminder` with no open approval (`approval_reminder_no_open_approval`) or nobody who can receive email (`approval_email_no_recipient`)."},{"fix":"Ask YoPrint support to turn email on, or lift the block.","status":422,"when":"The team can't send email: a trial without email turned on (`email_feature_not_enabled_in_trial`), or over the daily limit (\"You are sending too many emails ...\", `validation_error`)."},{"fix":"Ask the team owner for the permission.","status":403,"when":"The API key's role lacks the permission the action needs (`user_is_not_authorized`)."},{"fix":"Use ids from the team's own lists.","status":404,"when":"No such order, status (for `change_status` or a conversion's `status_id`), customer, payment term, warehouse or address in this team (`error.code` null, \"No query results for …\")."},{"fix":"Copy `pricing_group_id` from an order or customer that uses the group.","status":404,"when":"The `pricing_group_id` is not one of the team's published groups (`pricing_group_not_found`, \"This pricing group doesn't exist or was removed.\")."}],"group":"Sales","notes":["The path parameter `{action_name}` is the action's name, not an id.","Get status ids from the team's sales order and quote status lists.","Ask before calling the `send_*` actions on someone's behalf: they email the customer."],"permission":"Most actions need permission to edit this order (`update_all_order`, or `update_self_order` for orders the user created or is assigned to; the creator of a draft with `create_order`). `clone_order` needs `create_order` and permission to view the order. The `send_*` actions need permission to message the order's customer (`message_all_order`, or `message_self_order` for own and assigned orders). The team owner can do all of them.","related":["v2_public_order_update","v1_public_status_list_sales_order","v1_public_status_list_quote","v1_public_payment_term_index"],"rules":["On an order synced from an integration (Shopify), only `change_status`, `change_customer_due_date`, `change_ship_due_date`, `change_start_end_date_date` and `send_order_detail` work; every other action fails with 422 `validation_error` \"Cannot update external object from API.\" A Shopify order deleted in Shopify fails every action with 422 `shopify_order_deleted_externally`.","`change_customer` works on drafts only. It is refused if the draft has any of the following: a payment, a payment link, a sent message, or linked stock. Shopify orders and Shopify customers are also refused. Sending the current customer changes nothing.","`change_customer` resets the order using the new customer's settings:\n\n- **Brand profile, addresses, contact**: the customer's primary brand profile, primary billing and shipping addresses, and primary (or first) contact replace the order's (or are cleared if none exist). Message participants are replaced by that contact.\n- **Payment term**: uses the customer's default payment term (or the team's default). The deposit percentage, deposit requirement, and due dates (counted from today) update from it. If there is no default term, only the term is cleared.\n- **Warehouse**: sets the customer's default warehouse, if configured.\n- **Pricing group**: sets the customer's default pricing group (or the team's default if none exists or theirs was removed). The order is repriced if the pricing group changes.\n- **Invoices and shipments**: every invoice receives the new customer and new addresses, and its tax is recalculated (manually entered tax is kept). Shipments receive the new customer but keep their existing addresses.","`change_status` works on published orders only; the status must belong to the team and to this kind of order.","`change_customer_due_date` and `change_ship_due_date` can't be before the issue date: \"Input date should be after order issue date.\"","`change_deposit_due` can't be after the full payment due date, and `change_full_amount_due` can't be before the deposit due date.","`change_start_end_date_date` needs both dates or neither, and the due date not before the start date.","`change_payment_term`: `deposit_due` and `full_amount_due` must be present (null allowed); a deposit is required when `deposit_due` is set; `deposit_total.dp` must be 3.","`clone_order` needs a choice in `item_choices` for every line on a phased-out or deleted product, size or color (`clone_needs_choices`), and refuses choices that are not needed (`clone_choice_not_needed`), unknown lines (`clone_choice_unknown_line`) and bad replacements (`clone_replacement_invalid`). Shopify orders can't be cloned.","`clone_order`, `convert_to_quote` and `convert_to_sales_order` keep the order's pricing group unless you send `pricing_group_id`. When that group was removed they are refused with 422 `clone_needs_pricing_group` (\"<name> was removed. Choose a pricing group.\"): `error.pricing_group` names the removed group and `error.suggested_pricing_group` the customer's default or else the team's (`{ id, name, removed, disabled }`, or null). Send `pricing_group_id`, for example the suggested one, and try again. When a `clone_order` also has lines that need `item_choices`, the refusal is `clone_needs_choices` instead: it lists those lines and carries `pricing_group_needed: true` with the same two groups.","A `pricing_group_id` you send (in `change_pricing_group`, `clone_order` or a conversion) must be one of the team's published groups: a removed group is refused with 422 `pricing_group_removed` (\"<name> was removed. Choose another pricing group.\", `error.pricing_group` names it); a group that is turned off with 422 `pricing_group_disabled` unless it is already the order's (or, for a copy or conversion, the customer's default); a draft or another team's group with 404 `pricing_group_not_found`.","Conversions refuse deleted orders (\"A deleted order cannot be converted. Restore it first.\"), Shopify orders and orders whose customer is a Shopify customer, converting to the same kind, an order whose current status is not one of its kind's statuses, and teams without a starting status for the target kind; each is 422 `object_action_error`. A `status_id` must be a status of the target kind (else 404).","MARKUP rates can't be below -100; MARGIN rates must be 0 or more and below 100.","The `send_*` actions count toward the team's daily email limit (60 a day on the free plan, and on a trial only once YoPrint support has turned email on for it; on paid plans 280 in the first 6 days of the subscription or the team, 800 once the subscription is over 3 months old, 380 otherwise). Every call counts, even one that ends up sending nothing. Going over it blocks the team's email until YoPrint support lifts the block. A trial without email turned on, or a team without an active plan, gets 422 `email_feature_not_enabled_in_trial`."],"side_effects":["`change_status` sends `sales_order.status_changed` (or `quote.status_changed`) and `order.status_changed` webhooks and records the change in the history, only when the status really changes.","`convert_to_sales_order` sends `quote.converted_to_sales_order`; `convert_to_quote` sends `order.converted_to_quote` and releases the order's stock reservations.","`mark_order_as_rush` and `mark_order_as_not_rush` change the order and all its jobs and send `order.marked_as_rush` or `order.marked_as_not_rush` when the order's flag changes; the `mark_all_job_*` actions change only the jobs. No job rush webhooks are sent.","`configure_order_auto_invoice_managed` turned on creates or updates the order's one managed invoice (`DONOTMANAGE` removes its managed shipping lines); turned off, the invoices and their lines stay but are no longer managed.","`bulk_change_invoice_address` redoes Auto Tax for the new addresses.","`change_deposit_due` changes only the date: whether a deposit is required and its amount stay as they are (use `change_payment_term` for those).","`change_pricing_group` and `change_pricing_strategy` recalculate prices, totals and auto-managed invoices. `change_payment_term` recalculates only the deposit (and the customer's totals on a published sales order).","`change_issue_date` moves the other dates of the order, its jobs, and its invoices by the same number of days.","The `send_*` actions email the customer; `clone_order` creates a new draft. On a copy whose invoices are recalculated (for example when a line is left out), the deposit amount is recalculated too.","On a published order, Customer Portal pages the order's customer has open refresh (a live update, not an email)."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}/customer_note":{"put":{"description":"Sets the order's Client Note. It is printed on the order's documents, which the customer receives: for notes the customer must not see, use the production note or a comment.\n\nWorks on drafts, published and deleted orders. The answer is the order. `{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.","operationId":"v2_public_order_customer_note_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"order_unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"customer_note":"Ship in two boxes."},"schema":{"properties":{"customer_note":{"description":"The Client Note. Send `null` to clear it. Leave the field out to change nothing.","type":["string","null"]}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"calc_deposit_total":67500,"client_note":"Ship in two boxes.","customer":{"id":"63KcENAAsKuipY","is_external":false,"name":"Northwind Apparel","tax_exempt":false},"customer_id":"63KcENAAsKuipY","customer_po_number":"PO-1188","deposit_amount_due":{"dp":4,"value":175000},"deposit_required":true,"deposit_total":50000,"due_date":"2026-11-14T00:00:00+00:00","id":"V4keXwwxMQyXw7","internal_status":"published","invoiced_discount_subtotal":{"dp":4,"value":0},"invoiced_order_item_subtotal":{"dp":4,"value":1250000},"invoiced_shipment_subtotal":{"dp":4,"value":0},"invoiced_tax_subtotal":{"dp":4,"value":100000},"invoiced_total":{"dp":4,"value":1350000},"is_rush":false,"issue_date":"2026-11-03T00:00:00+00:00","mode":"view","name":"Spring team shirts","object_type":"sales_order","order_balance_due":{"dp":4,"value":850000},"order_item_cart_total":{"dp":4,"value":1250000},"paid_amount":50000,"quote":false,"scoped_id":"SO1001","status":{"color":"#2196f3","customer_label":"In Progress","id":"52CuV8sWcDZLPm","label":"In production","position":2,"role":"order","trashed":false,"type":"in_progress"},"status_id":"52CuV8sWcDZLPm","total_qty_need_ordering":"0.00000000","trashed":false,"type":"order","unique_key":"ord_EXAMPLEuniqueKey"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A sales order or quote.","properties":{"approval_status":{"description":"`requested`, `sent-to-customer`, `viewed-by-customer`, `need-changes` or `approved`; null without approvals.","type":["string","null"]},"assigned_users":{"description":"The team members in the order's Assigned To list (always included).","items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"auto_invoice_managed":{"description":"true when YoPrint keeps one invoice in step with the order.","type":"boolean"},"auto_invoice_shipment_price_type":{"description":"`DONOTMANAGE`, `NONE`, `MARKUP` or `MARGIN`.","type":["string","null"]},"auto_invoice_shipment_rate":{"description":"The MARKUP or MARGIN percentage. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"auto_invoice_type":{"description":"How the automatic invoice is built. Always `single_invoice` today.","type":["string","null"]},"billing_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"billing_address_id":{"type":["string","null"]},"calc_deposit_total":{"description":"The deposit amount, rounded to 2 decimal places: the percentage of `order_item_cart_total`, or of the invoiced total once every line is invoiced (or the invoiced total reaches the order's); 0 unless `deposit_required`. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `invoiced_discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `invoiced_order_item_subtotal`, which already includes billed shipping. This older field adds `invoiced_shipment_subtotal` to it once more. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `invoiced_tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `invoiced_total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"client_note":{"description":"The Client Note.","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_by":{"description":"Created By (a team member id).","type":["string","null"]},"creator_name":{"type":["string","null"]},"cust_due_date":{"description":"Customer in-hands date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"Always present on order answers, lists included: the customer record, or null when the order has none. Get a sales order also nests the customer's contacts, addresses, brand profiles, tags, files and assigned users in it.","properties":{"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"id":{"example":"63KcENAAsKuipY","type":"string"},"is_external":{"description":"true for a customer synced from an integration.","type":"boolean"},"name":{"example":"Northwind Apparel","type":"string"},"tax_exempt":{"type":"boolean"}},"type":["object","null"]},"customer_billing_contact_id":{"description":"The id of the contact on the order (the same contact as `customer_contact_id`), or null.","type":["string","null"]},"customer_contact_id":{"type":["string","null"]},"customer_has_email":{"type":"boolean"},"customer_id":{"example":"63KcENAAsKuipY","type":["string","null"]},"customer_po_number":{"example":"PO-1188","type":["string","null"]},"customer_profile_id":{"description":"Brand profile.","type":["string","null"]},"deposit_amount_due":{"description":"Deposit still to pay (negative once overpaid). A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"deposit_due":{"description":"Deposit due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"deposit_required":{"type":"boolean"},"deposit_total":{"description":"The deposit as a **percentage** of the order. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","type":["integer","number","string","null"]},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"external_ids":{"description":"The order's links to records in other systems. An empty list when there are none.","items":{"additionalProperties":true,"description":"One link to a record in another system (Shopify, QuickBooks and so on): `id`, `external_integration_id`, `external_id`, `data`, `created_at`, `updated_at` and the nested `external_integration`.","type":"object"},"type":"array"},"external_type":{"description":"`shopify` for a Shopify order; null for YoPrint orders.","type":["string","null"]},"from_legacy":{"description":"true for an order that was moved over from the old format.","type":"boolean"},"full_amount_due":{"description":"Full payment due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"grouped_pdf":{"description":"PDF links, grouped: `Main` (only for roles with `view_order_finance`), `Job` (not on Shopify orders), `Shipment` and the team's templates.","items":{"additionalProperties":true,"properties":{"documents":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"label":{"example":"Main","type":"string"}},"type":"object"},"type":"array"},"has_external_integration_sync_error":{"description":"true when the last sync with an integration failed.","type":"boolean"},"has_invoice":{"description":"true when the order has at least one invoice, so a zero invoiced total can be told apart from no invoice.","type":"boolean"},"has_not_invoiced_items":{"description":"true when some line items are not on an invoice yet.","type":"boolean"},"has_over_invoiced_items":{"description":"true when some line items are invoiced for more than the order has.","type":"boolean"},"has_shipment_items_not_allocated":{"description":"true when some line items are not on a shipment yet.","type":"boolean"},"has_shipment_items_over_allocated":{"description":"true when some line items are on shipments for more than the order has.","type":"boolean"},"has_valid_invoice":{"description":"true when at least one of the order's invoices is in a valid state.","type":"boolean"},"has_valid_shipment":{"description":"true when at least one of the order's shipments is in a valid state.","type":"boolean"},"id":{"description":"The order's hash id: use it in every other call.","example":"V4keXwwxMQyXw7","type":"string"},"internal_status":{"description":"`draft` until published.","enum":["draft","published"],"type":"string"},"inventory_status":{"description":"Stock status of the order's lines: `not_committed`, `committed`, `partially_committed`, `not_applicable` or `pending`.","type":["string","null"]},"invoice_lock_version":{"description":"Changes whenever the order's invoices change.","type":["integer","string","null"]},"invoiced_discount_subtotal":{"description":"Discounts on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_order_item_subtotal":{"description":"The lines and shipping fees the order's invoices bill (the sum of their `cart_item_subtotal`); 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_shipment_subtotal":{"description":"The shipping fees in `invoiced_order_item_subtotal`; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_tax_subtotal":{"description":"Tax on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_total":{"description":"Total of the order's invoices. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"is_client_note_editable":{"description":"false for a Shopify order, whose client note comes from Shopify.","type":"boolean"},"is_external":{"description":"true for an order synced from an integration such as Shopify.","type":"boolean"},"is_legacy":{"description":"true for an order made in the old format.","type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"job_lock_version":{"description":"Changes whenever the order's jobs change.","type":["integer","string","null"]},"last_payment_request_date":{"description":"When a payment reminder was last emailed for the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"lock_version":{"description":"Changes on every save.","type":["integer","string","null"]},"mode":{"description":"Older flag: `create` for a draft, `view` once published.","enum":["create","view","edit"],"type":"string"},"name":{"example":"Spring team shirts","type":["string","null"]},"object_type":{"enum":["sales_order","quote"],"type":"string"},"order_balance_due":{"description":"Invoiced total minus paid. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_cart_total":{"description":"The value of the order's lines: the order's own total before invoicing. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_lock_version":{"description":"Changes whenever the order's line items change.","type":["integer","string","null"]},"order_margin_percentage":{"description":"Margin, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_markup_percentage":{"description":"Markup, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_profit":{"description":"Profit. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"paid_amount":{"description":"Paid so far. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"payment_lock_version":{"description":"Changes whenever the order's payments change.","type":["integer","string","null"]},"payment_term_id":{"type":["string","null"]},"pricing_group_id":{"type":["string","null"]},"pricing_strategy":{"description":"`job_separately`, `job_together` or `service_loc_together`.","type":["string","null"]},"prod_note":{"description":"The production note.","type":["string","null"]},"producible_item_count":{"description":"Quantity to produce.","type":["number","integer","string","null"]},"quickbook_disable_sync":{"description":"true when QuickBooks sync is off for this order.","type":"boolean"},"quickbook_disable_sync_at":{"description":"When the switch was last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_disable_sync_by":{"description":"The team member who last changed the switch, or null.","type":["string","null"]},"quickbook_disable_sync_reason":{"description":"The note given at the last change of the order's QuickBooks sync switch (off or back on), at most 500 characters, or null.","type":["string","null"]},"quickbook_last_error_sync":{"description":"When a QuickBooks sync of the order last failed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_last_success_sync":{"description":"When QuickBooks last accepted the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbooks_hold":{"description":"Set when YoPrint holds back a QuickBooks payment covering this order: `code` is `changed`, `deleted` or `rejected` (the payment was changed or deleted in QuickBooks, or QuickBooks refused a change), and `detail` is `already_deposited` (the payment is in a QuickBooks bank deposit) or null. Null when nothing is held.","properties":{"code":{"enum":["changed","deleted","rejected"],"type":"string"},"detail":{"type":["string","null"]}},"type":["object","null"]},"quote":{"description":"Older flag: true for a quote.","type":"boolean"},"scoped_id":{"description":"The order number people see, `SO` and at least four digits (quotes too). Not an id.","example":"SO1001","type":"string"},"ship_due_date":{"description":"Ship due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shipment_billable_fee_invoice_status":{"description":"Whether those shipping fees are on an invoice. Null when there is nothing to bill.","type":["string","null"]},"shipment_billable_fee_total":{"description":"The shipping fees you bill the customer on the order's shipments. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_cost_total":{"description":"Shipping cost incurred. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_lock_version":{"description":"Changes whenever the order's shipments change.","type":["integer","string","null"]},"shipping_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"shipping_address_id":{"type":["string","null"]},"shopify_last_error_sync":{"description":"When a Shopify sync of the order last failed. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_last_success_sync":{"description":"When Shopify last accepted the order. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_terminal_topic":{"description":"Shopify orders only: the Shopify event name behind the order's final state there. Null on YoPrint orders. The answer can also hold more `shopify_*` fields (`shopify_admin_url`, `shopify_compliance_deletion`, `shopify_finance_notices`, `shopify_has_fulfillment_conflict`, `shopify_last_fulfillment_conflict_at`): they are null or empty on YoPrint orders.","type":["string","null"]},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"The order's status (always included).","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_completion_date":{"description":"When the order's status last moved to an end status. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status_id":{"description":"The order's status (from the team's sales order or quote statuses).","example":"52CuV8sWcDZLPm","type":"string"},"status_last_change_date":{"description":"Last status change. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"tags":{"items":{"additionalProperties":true,"properties":{"color_hex":{"description":"Tag color, for example `#E53935`.","type":["string","null"]},"id":{"example":"7qYPMmbLZR9oFg","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"total_qty_need_ordering":{"description":"Quantity still to buy, as a decimal string with 8 decimal places (`\"24.00000000\"`).","example":"0.00000000","type":"string"},"trashed":{"description":"true when the order is deleted.","type":"boolean"},"type":{"description":"Older name for `object_type`.","enum":["order","quote"],"type":"string"},"unallocated_amount":{"description":"Payments not yet allocated to an invoice. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"unique_key":{"description":"The order's unique key (`ord_…`); accepted wherever `{order_unique_key}` is.","example":"ord_EXAMPLEuniqueKey","type":"string"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"version":{"description":"The order format version.","type":["integer","string","null"]},"wallet_currency_iso":{"description":"The order's currency code (`USD` and so on), or null on older orders without one.","example":"USD","type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"required":["id","unique_key","scoped_id","object_type","internal_status"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set the Client Note of a sales order or quote","tags":["Sales orders"],"x-yoprint-docs":{"errors":[{"fix":"Change the note in Shopify, or send a string.","status":422,"when":"A Shopify order, or the note is not a string."},{"fix":"Ask the team owner for sales order edit permission.","status":403,"when":"The API key's role can't edit this order."}],"group":"Sales","permission":"Needs permission to edit this sales order or quote:\n\n- The team owner\n- A role with `update_all_order`\n- A role with `update_self_order`, when the order was created by or is assigned to the API key's user\n- The person who created a draft, with `create_order`\n\nQuotes use the same sales order permissions.","related":["v2_public_order_production_note_update","v2_public_order_comment_store"],"rules":["Shopify manages the note of a Shopify order: refused with `shopify_customer_note_read_only`.","Refused when the Shopify order was deleted in Shopify (`shopify_order_deleted_externally`)."],"side_effects":["On a published order, records the change in the order history.","Refreshes the order for people who have it open in the web app."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}/history":{"get":{"description":"Returns the order's activity history: who changed what and when.\n\nThe answer is paginated, newest first: rows are in `data`, and pagination metadata is in `pagination` (`total`, `count`, `perPage`, `currentPage`, and `totalPages`). A page holds the team's page size (50 unless the team changed it); request the next page with `?page=2`.\n\n`{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. Works on deleted orders too. Use this, not the retired v1 history.","operationId":"v2_public_order_history","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"order_unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"The page to return, from 1.","in":"query","name":"page","required":false,"schema":{"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"action":"status_change","created_at":"2026-11-03T09:00:00+00:00","id":"K1J40XmWy4eDJQ","message_key":"order.status_change","object":{"from_status":{"id":"HqXxdtvY4icbzQ","label":"New","type":"start"},"order":{"id":"V4keXwwxMQyXw7","object_type":"sales_order","quote":false,"scoped_id":"SO1001"},"to_status":{"id":"52CuV8sWcDZLPm","label":"In production","type":"in_progress"},"user":{"avatar_url":null,"id":"PydH0WtBhSeiNU","name":"Alex Rivera"}},"team":{"id":"MwFS4szpsdJJDt","name":"Your Team","slug":"your-team"},"type":"order"}],"pagination":{"count":1,"currentPage":1,"links":[],"perPage":50,"total":1,"totalPages":1},"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"One history entry, newest first.","properties":{"action":{"description":"What happened, for example `status_change`, `order_changes_in_view_mode`, `order_deleted`, `order_restored`, `new_comment` or `received_user_payment`.","type":"string"},"created_at":{"description":"When. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"id":{"example":"K1J40XmWy4eDJQ","type":"string"},"message_key":{"description":"`type.action`, for example `order.status_change`: the key of the sentence the web app shows.","type":["string","null"]},"object":{"additionalProperties":true,"description":"The details: usually `team`, `order` (`id`, `scoped_id`, `object_type`, `quote`), the changed values (a status change has `from_status` and `to_status`) and `user` (`id`, `name`, `avatar_url`). `[]` (an empty array) when an entry has no details.","type":["object","array"]},"team":{"additionalProperties":true,"description":"Your team.","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"}},"type":"object"},"type":{"description":"What kind of record changed: `order`, `job`, `shipment` and so on.","type":"string"}},"required":["id","type","action"],"type":"object"},"type":"array"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the history of a sales order or quote","tags":["Sales orders"],"x-yoprint-docs":{"group":"Sales","permission":"Any member of the team.","related":["v2_public_order_show"]}}},"/v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}/order_item":{"get":{"description":"Returns every line of a sales order or quote: products, custom lines and fees, with their quantities and prices.\n\n`{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.\n\nThe answer is the full list in `data`, not paginated, sorted by `position` ascending as the web app shows them. Each line has the same groups you send when adding one (`product`, `pricing`, `quantity`, `job`, `weight`, `position`), plus `unit_price`, `subtotal`, stock details and `_meta`. Prices and quantities are `{ value, dp }` pairs (the amount is `value` ÷ 10^`dp`), and answers keep the stored scale: prices have 6 decimal places (12.50 is `{ \"value\": 12500000, \"dp\": 6 }`), subtotals 4, weights 8; quantities drop trailing zeros (24 is `{ \"value\": 24, \"dp\": 0 }`).","operationId":"v2_public_order_item_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"order_unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"id":"Owr88lhAk28aqL","job":{"id":"K6iF8n29iwOZnj","scoped_id":"JOB-1001","type":"linked","unique_key":"job_EXAMPLEuniqueKey"},"lock_version":1793696400234567,"order_id":"V4keXwwxMQyXw7","order_unique_key":"ord_EXAMPLEuniqueKey","position":200000,"pricing":{"product":{"override":true,"total":{"dp":6,"value":12500000}},"type":"product_cost_service"},"product":{"properties":{"customer_supplied":false,"id":"nqSB3HG1O2u5Jg"},"type":"user_simple"},"quantity":{"total":{"dp":0,"value":10},"type":"unit"},"subtotal":{"dp":4,"value":1250000},"trashed":false,"type":"user_simple","unit_price":{"dp":6,"value":12500000}}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"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).","properties":{"_meta":{"additionalProperties":true,"description":"The line's own values again (`id`, `type`, `order_id`, `unit_price`, `subtotal` and so on). Always an object.","type":"object"},"id":{"example":"Owr88lhAk28aqL","type":"string"},"inventory_status":{"description":"Stock status of the line.","type":["string","null"]},"job":{"additionalProperties":true,"type":"object"},"lock_version":{"description":"The line's own lock version (a microsecond timestamp).","type":["integer","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_unique_key":{"description":"The order's `unique_key`. The line's own `unique_key` is not in the answer: use `id`.","example":"ord_EXAMPLEuniqueKey","type":"string"},"position":{"example":200000,"type":"integer"},"pricing":{"additionalProperties":true,"type":"object"},"pricing_rule_applied":{"description":"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.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"11.05","type":"string"},"after_total":{"description":"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.","example":{"dp":6,"value":11050000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: that starting price, as a decimal string with at least 2 decimal places.","example":"8.50","type":"string"},"base_type":{"description":"Full summary only: what the rule started from: the supplier price for catalog lines, the product's own price for other lines.","enum":["supplier_price","base_price"],"type":"string"},"normal_price":{"description":"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`.","example":"11.05","type":["string","null"]},"original_total":{"description":"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.","example":{"dp":6,"value":8500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The line keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`product` on a line.","example":"product","type":"string"}},"type":["object","null"]},"product":{"additionalProperties":true,"type":"object"},"quantity":{"additionalProperties":true,"description":"The quantity, trailing zeros dropped: 10 is `{ \"value\": 10, \"dp\": 0 }`.","type":"object"},"subtotal":{"description":"`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.","example":{"dp":4,"value":1250000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"trashed":{"description":"true when the line was deleted.","example":false,"type":"boolean"},"type":{"description":"The kind of line: db_catalog, user_simple, db_variant, custom or fee.","example":"user_simple","type":"string"},"unit_price":{"description":"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.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the line items of a sales order or quote","tags":["Sales order line items"],"x-yoprint-docs":{"group":"Sales","notes":["Deleted lines are not listed.","A simple-product line from the older editor reads `db_simple` in `product.type`; new lines read `user_simple`. Treat both as Custom simple product.","A line's `pricing._meta.editable_fields_on_update` and `product._meta.editable_fields_on_update` list the request paths an update accepts for that group. `pricing.type` is listed, but it must stay the line's own."],"permission":"Any member of the team.","related":["v2_public_order_item_show","v2_public_order_item_store","v2_public_order_item_bulk","v2_public_order_show"]}},"post":{"description":"Adds one line to a sales order or quote and recalculates the order's totals. It works on drafts and on published orders (Live Edit). Sending the same request again adds the line again, so read the order back before you retry after a timeout.\n\nWhat you send depends on what you add, chosen by `product.type`, which also fixes `pricing.type`:\n\n| You add | `product.type` | `pricing.type` | You send |\n| --- | --- | --- | --- |\n| Catalog product | `db_catalog` | `catalog_product_pricing` | the catalog item id and its supplier cost |\n| Custom simple product | `user_simple` | `product_cost_service` | your product's id |\n| Custom variant product | `db_variant` | `product_cost_service` | the id of one size and color |\n| Custom line item | `custom` | `custom_product` | a name and a price |\n| Fee line item | `fee` | `fee` | a name and an amount |\n\nEvery line also needs `quantity` (`type: \"unit\"`), `job` (`linked` with a job id of this order, or `standalone`) and `position`. `weight` is optional.\n\nAmounts 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.\n\n**How the price is worked out.** YoPrint determines the product price in this order:\n\n1. Price override: if `pricing.product.override` is true, it uses `pricing.product.total`.\n2. Customer-supplied: if the item is customer-supplied, the product price is 0.\n3. Cost and markup: otherwise, YoPrint starts from the cost (the catalog cost, your `product_cost`, or the product's price in Products) and applies the order's pricing group markup or a matching pricing rule.\n\nThe unit price adds the job's decoration price per unit (or `pricing.service.total` when `service.override` is true). The subtotal is the unit price multiplied by the quantity.\n\nTo add several lines at once, or a whole size run, use the bulk operation: it saves them together or not at all.\n\n`{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.\n\nThe answer is `data.item`, the saved line with its computed `unit_price` and `subtotal`, plus `action_performed: \"CREATED\"`. Read the order to get its new totals.\n\nA new line is refused with HTTP 422 if the product or variant cannot be sold:\n\n- Simple product phased out: 422 `product_phased_out` (`error.product_id` names it)\n- Simple product deleted: 422 `product_deleted` (`error.product_id` names it)\n- Size or color phased out: 422 `variant_phased_out` (`error.variant_id` names it)\n- Size or color deleted: 422 `variant_deleted` (`error.variant_id` names it)\n\nThis 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.","operationId":"v2_public_order_item_store","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"order_unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"catalog":{"summary":"A catalog product: 24 units, priced from the supplier cost","value":{"job":{"id":"K6iF8n29iwOZnj","type":"linked"},"position":100000,"pricing":{"catalog":{"date":"2026-11-03","provider":"smr","selected":"piece","total":{"dp":2,"value":450}},"product":{"override":false},"service":{"override":false},"type":"catalog_product_pricing"},"product":{"properties":{"customer_supplied":false,"id":"smr-10001"},"type":"db_catalog"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"}},"x-yoprint-variant":"Catalog product"},"custom":{"summary":"A one-off line with a name and a price","value":{"job":{"id":"K6iF8n29iwOZnj","type":"linked"},"position":400000,"pricing":{"product":{"override":true,"total":{"dp":2,"value":300}},"product_cost":{"total":{"dp":2,"value":120}},"service":{"override":false},"type":"custom_product"},"product":{"properties":{"customer_supplied":false,"description":"Navy border","name":"Embroidered patch"},"type":"custom"},"quantity":{"total":{"dp":0,"value":50},"type":"unit"}},"x-yoprint-variant":"Custom line item"},"fee":{"summary":"A fee","value":{"job":{"type":"standalone"},"position":500000,"pricing":{"product":{"total":{"dp":2,"value":2500}},"type":"fee"},"product":{"properties":{"name":"Rush fee"},"type":"fee"},"quantity":{"total":{"dp":0,"value":1},"type":"unit"}},"x-yoprint-variant":"Fee line item"},"simple":{"summary":"Your simple product, at a price you set","value":{"job":{"id":"K6iF8n29iwOZnj","type":"linked"},"position":200000,"pricing":{"product":{"override":true,"total":{"dp":2,"value":1250}},"service":{"override":false},"type":"product_cost_service"},"product":{"properties":{"customer_supplied":false,"id":"nqSB3HG1O2u5Jg"},"type":"user_simple"},"quantity":{"total":{"dp":0,"value":10},"type":"unit"}},"x-yoprint-variant":"Custom simple product"},"variant":{"summary":"One size and color of your product, priced by YoPrint","value":{"job":{"id":"K6iF8n29iwOZnj","type":"linked"},"position":300000,"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"}},"x-yoprint-variant":"Custom variant product"}},"schema":{"description":"Pick the branch by `product.type`.","oneOf":[{"description":"Add a product from a supplier catalog (one size and color).","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. YoPrint determines the product price in this order:\n\n1. Price override: if `product.override` is true, YoPrint uses `product.total`.\n2. Customer-supplied: if `customer_supplied` is true (`product.properties.customer_supplied`), the product price is 0.\n3. Marked-up cost: otherwise, YoPrint takes the supplier cost in `catalog` and applies the order's pricing group markup or a matching pricing rule.\n\nA 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.\").","properties":{"catalog":{"description":"The supplier price the line starts from. When you send `catalog`, all four fields are required.","properties":{"date":{"description":"When the price was looked up, an ISO 8601 date such as 2026-11-03 (a date-time is accepted too).","format":"date","type":"string"},"provider":{"description":"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.","type":"string"},"selected":{"description":"Which supplier price `total` represents:\n\n- `piece`: standard piece price\n- `dozen`: dozen price tier\n- `case`: case price tier\n- `account`: your account's negotiated price (`your_price` in catalog lookups)\n- `sales`: the supplier's sale price (`sales_price` in catalog lookups)\n- `custom`: a custom cost you entered manually\n- `legacy`: lines migrated from the old editor","enum":["piece","dozen","case","account","sales","custom","legacy"],"type":"string"},"total":{"description":"The supplier's cost for one unit.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["provider","selected","date","total"],"type":"object"},"product":{"description":"Set your own product price for one unit with `override: true` and `total`. It replaces the marked-up catalog cost.","properties":{"override":{"description":"true to use `total` as given; false to let YoPrint work it out.","type":"boolean"},"total":{"description":"The amount for one unit, as a `{ value, dp }` pair. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"catalog_product_pricing","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"customer_supplied":{"description":"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.","type":"boolean"},"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"},"id":{"description":"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`.","type":"string"}},"required":["id","customer_supplied"],"type":"object"},"type":{"const":"db_catalog","type":"string"}},"required":["type","properties"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type","total"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out to use the product's weight.","discriminator":{"mapping":{"mass":"#/components/schemas/WeightMassCreate","use_system":"#/components/schemas/WeightUseSystem"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/WeightUseSystem"},{"$ref":"#/components/schemas/WeightMassCreate"}],"title":"Weight"}},"required":["product","pricing","quantity","job","position"],"title":"Catalog product","type":"object"},{"description":"Add one of your own products that has no sizes or colors.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. YoPrint determines the product price in this order:\n\n1. Price override: if `product.override` is true, YoPrint uses `product.total`.\n2. Customer-supplied: if `customer_supplied` is true (`product.properties.customer_supplied`), the product price is 0.\n3. Product pricing: otherwise, YoPrint starts from `product_cost.total` (or the price from Products when omitted or 0) and applies any matching pricing rule.","properties":{"product":{"description":"Set your own product price for one unit with `override: true` and `total`.","properties":{"override":{"description":"true to use `total` as given; false to let YoPrint work it out.","type":"boolean"},"total":{"description":"The amount for one unit, as a `{ value, dp }` pair. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"product_cost":{"description":"Your cost for one unit. Optional: leave it out, or send a total of 0, to use the product's price from Products.","properties":{"override":{"description":"true when you set the cost yourself.","type":"boolean"},"total":{"description":"The cost for one unit. 0 means \"use the product's price\".","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override","total"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"product_cost_service","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"customer_supplied":{"description":"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.","type":"boolean"},"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"},"id":{"description":"The product's `id` from Products.","type":"string"}},"required":["id","customer_supplied"],"type":"object"},"type":{"const":"user_simple","type":"string"}},"required":["type","properties"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type","total"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out to use the product's weight.","discriminator":{"mapping":{"mass":"#/components/schemas/WeightMassCreate","use_system":"#/components/schemas/WeightUseSystem"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/WeightUseSystem"},{"$ref":"#/components/schemas/WeightMassCreate"}],"title":"Weight"}},"required":["product","pricing","quantity","job","position"],"title":"Custom simple product","type":"object"},{"description":"Add one size and color of your own product.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. YoPrint determines the product price in this order:\n\n1. Price override: if `product.override` is true, YoPrint uses `product.total`.\n2. Customer-supplied: if `customer_supplied` is true (`product.properties.customer_supplied`), the product price is 0.\n3. Product pricing: otherwise, YoPrint starts from `product_cost.total` (or the price from Products when omitted or 0) and applies any matching pricing rule.","properties":{"product":{"description":"Set your own product price for one unit with `override: true` and `total`.","properties":{"override":{"description":"true to use `total` as given; false to let YoPrint work it out.","type":"boolean"},"total":{"description":"The amount for one unit, as a `{ value, dp }` pair. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"product_cost":{"description":"Your cost for one unit. Optional: leave it out, or send a total of 0, to use the product's price from Products.","properties":{"override":{"description":"true when you set the cost yourself.","type":"boolean"},"total":{"description":"The cost for one unit. 0 means \"use the product's price\".","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override","total"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"product_cost_service","type":"string"}},"required":["type"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"customer_supplied":{"description":"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.","type":"boolean"},"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"},"id":{"description":"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.","type":"string"}},"required":["id","customer_supplied"],"type":"object"},"type":{"const":"db_variant","type":"string"}},"required":["type","properties"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type","total"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out to use the product's weight.","discriminator":{"mapping":{"mass":"#/components/schemas/WeightMassCreate","use_system":"#/components/schemas/WeightUseSystem"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/WeightUseSystem"},{"$ref":"#/components/schemas/WeightMassCreate"}],"title":"Weight"}},"required":["product","pricing","quantity","job","position"],"title":"Custom variant product","type":"object"},{"description":"Add a one-off line with a name and a price, not linked to a product.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"How the line is priced. Send the unit price in `product.total` with `override: true`.","properties":{"product":{"description":"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.","properties":{"override":{"description":"true to use `total` as the price.","type":"boolean"},"total":{"description":"The price for one unit. Up to 6 decimal places are kept.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"product_cost":{"description":"Optional: your cost for one unit, used for profit and margin.","properties":{"total":{"description":"Your cost for one unit.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"service":{"description":"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).","properties":{"override":{"description":"true to use `total` instead of the job's decoration price.","type":"boolean"},"total":{"description":"The decoration price for one unit. Required when `override` is true. Up to 6 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["override"],"type":"object"},"type":{"const":"custom_product","type":"string"}},"required":["type","product"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"customer_supplied":{"description":"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.","type":"boolean"},"description":{"description":"Extra text shown under the line, for example a note about the color.","type":"string"},"name":{"description":"The line's name, as the customer sees it.","type":"string"}},"required":["name","customer_supplied"],"type":"object"},"type":{"const":"custom","type":"string"}},"required":["type","properties"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type","total"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out for 0 lb.","oneOf":[{"description":"Your own weight for one unit.","properties":{"total":{"description":"The weight as a `{ value, dp }` pair whose two parts are strings: 1.5 is `{ \"value\": \"15\", \"dp\": \"1\" }`.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, as a string.","type":"string"},"value":{"description":"The weight without its decimal point, as a string of digits.","type":"string"}},"required":["value","dp"],"type":"object"},"type":{"const":"mass","type":"string"},"unit":{"enum":["lb","kg"],"type":"string"}},"required":["type","unit","total"],"title":"Set the weight","type":"object"}],"title":"Weight"}},"required":["product","pricing","quantity","job","position"],"title":"Custom line item","type":"object"},{"description":"Add a fee, such as a rush or setup fee.","properties":{"job":{"description":"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.","discriminator":{"mapping":{"linked":"#/components/schemas/JobLinked","standalone":"#/components/schemas/JobStandalone"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/JobLinked"},{"$ref":"#/components/schemas/JobStandalone"}],"title":"Job"},"position":{"description":"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.","type":"integer"},"pricing":{"description":"The fee amount for one unit. Fees never take a decoration price.","properties":{"product":{"properties":{"total":{"description":"The fee for one unit, 0 or more.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["total"],"type":"object"},"type":{"const":"fee","type":"string"}},"required":["type","product"],"type":"object"},"product":{"description":"What the line is. `type` picks the kind of line and can't change later.","properties":{"properties":{"properties":{"description":{"description":"Extra text shown under the fee, for example what it covers.","type":"string"},"name":{"description":"The fee's name, for example \"Rush fee\".","type":"string"}},"required":["name"],"type":"object"},"type":{"const":"fee","type":"string"}},"required":["type","properties"],"type":"object"},"quantity":{"description":"How many units. `type` is always `unit`.","properties":{"total":{"description":"The quantity as a `{ value, dp }` pair: 24 is `{ \"value\": 24, \"dp\": 0 }`. Up to 8 decimal places.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, 0 to 30. 12.50 is 2.","type":["integer","string"]},"value":{"description":"The number without its decimal point, as a whole number or a string of digits. 12.50 is 1250.","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type","total"],"type":"object"},"weight":{"description":"Optional, used for shipping. Leave it out for no weight.","oneOf":[{"description":"Your own weight for one unit.","properties":{"total":{"description":"The weight as a `{ value, dp }` pair whose two parts are strings: 1.5 is `{ \"value\": \"15\", \"dp\": \"1\" }`.","properties":{"dp":{"description":"How many digits of `value` are after the decimal point, as a string.","type":"string"},"value":{"description":"The weight without its decimal point, as a string of digits.","type":"string"}},"required":["value","dp"],"type":"object"},"type":{"const":"mass","type":"string"},"unit":{"enum":["lb","kg"],"type":"string"}},"required":["type","unit","total"],"title":"Set the weight","type":"object"}],"title":"Weight"}},"required":["product","pricing","quantity","job","position"],"title":"Fee line item","type":"object"}],"title":"What are you adding?","x-yoprint-discriminator":{"mapping":{"custom":"Custom line item","db_catalog":"Catalog product","db_variant":"Custom variant product","fee":"Fee line item","user_simple":"Custom simple product"},"propertyPath":"product.type"}}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"action_performed":"CREATED","has_changes":true,"item":{"id":"Owr88lhAk28aqL","job":{"id":"K6iF8n29iwOZnj","scoped_id":"JOB-1001","type":"linked","unique_key":"job_EXAMPLEuniqueKey"},"lock_version":1793696400234567,"order_id":"V4keXwwxMQyXw7","order_unique_key":"ord_EXAMPLEuniqueKey","position":200000,"pricing":{"product":{"override":true,"total":{"dp":6,"value":12500000}},"type":"product_cost_service"},"product":{"properties":{"customer_supplied":false,"id":"nqSB3HG1O2u5Jg"},"type":"user_simple"},"quantity":{"total":{"dp":0,"value":10},"type":"unit"},"subtotal":{"dp":4,"value":1250000},"trashed":false,"type":"user_simple","unit_price":{"dp":6,"value":12500000}},"lock_version":{"order":{"invoice_lock_version":1793696400123456,"job_lock_version":1793696400123456,"order_item_lock_version":1793696400234567,"order_lock_version":1793696400234567,"payment_lock_version":1793696400123456,"shipment_lock_version":null}},"object_type":"order_item"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"action_performed":{"description":"`NONE` when nothing changed.","enum":["CREATED","UPDATED","DELETED","NONE"],"type":"string"},"has_changes":{"type":"boolean"},"item":{"additionalProperties":true,"description":"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).","properties":{"_meta":{"additionalProperties":true,"description":"The line's own values again (`id`, `type`, `order_id`, `unit_price`, `subtotal` and so on). Always an object.","type":"object"},"id":{"example":"Owr88lhAk28aqL","type":"string"},"inventory_status":{"description":"Stock status of the line.","type":["string","null"]},"job":{"additionalProperties":true,"type":"object"},"lock_version":{"description":"The line's own lock version (a microsecond timestamp).","type":["integer","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_unique_key":{"description":"The order's `unique_key`. The line's own `unique_key` is not in the answer: use `id`.","example":"ord_EXAMPLEuniqueKey","type":"string"},"position":{"example":200000,"type":"integer"},"pricing":{"additionalProperties":true,"type":"object"},"pricing_rule_applied":{"description":"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.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"11.05","type":"string"},"after_total":{"description":"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.","example":{"dp":6,"value":11050000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: that starting price, as a decimal string with at least 2 decimal places.","example":"8.50","type":"string"},"base_type":{"description":"Full summary only: what the rule started from: the supplier price for catalog lines, the product's own price for other lines.","enum":["supplier_price","base_price"],"type":"string"},"normal_price":{"description":"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`.","example":"11.05","type":["string","null"]},"original_total":{"description":"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.","example":{"dp":6,"value":8500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The line keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`product` on a line.","example":"product","type":"string"}},"type":["object","null"]},"product":{"additionalProperties":true,"type":"object"},"quantity":{"additionalProperties":true,"description":"The quantity, trailing zeros dropped: 10 is `{ \"value\": 10, \"dp\": 0 }`.","type":"object"},"subtotal":{"description":"`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.","example":{"dp":4,"value":1250000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"trashed":{"description":"true when the line was deleted.","example":false,"type":"boolean"},"type":{"description":"The kind of line: db_catalog, user_simple, db_variant, custom or fee.","example":"user_simple","type":"string"},"unit_price":{"description":"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.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"}},"type":"object"},"lock_version":{"description":"The order's lock versions after this call. Each is a whole number (a microsecond timestamp) that changes on every save, or null.","properties":{"order":{"properties":{"invoice_lock_version":{"type":["integer","null"]},"job_lock_version":{"type":["integer","null"]},"order_item_lock_version":{"type":["integer","null"]},"order_lock_version":{"description":"The order's own `lock_version`.","type":["integer","null"]},"payment_lock_version":{"type":["integer","null"]},"shipment_lock_version":{"type":["integer","null"]}},"type":"object"}},"required":["order"],"type":"object"},"object_type":{"const":"order_item","example":"order_item","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add a line item to a sales order or quote","tags":["Sales order line items"],"x-yoprint-docs":{"errors":[{"fix":"Look up the supplier cost with the catalog pricing lookup and send it in `pricing.catalog`, or send `customer_supplied: true` when the customer provides the item.","status":422,"when":"A new catalog line (`db_catalog`) has no `pricing.catalog` and is not customer-supplied: `validation_failed`, with \"Enter the catalog cost for this line.\" on `pricing.catalog` in `error.fields`. Nothing is saved."},{"fix":"Read `error.fields`; send whole numbers in `value` and the decimal places in `dp` (for example `{\"value\": 1250, \"dp\": 2}` for 12.50).","status":422,"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":"Use an id from Products, or a catalog item id.","status":422,"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 a job id from this order's jobs.","status":422,"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":"Fix the job's services in the web app, then retry.","status":422,"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":"Resume it in Products, or choose another product.","status":422,"when":"The product, or its size or color, is phased out or deleted (`product_phased_out`, `product_deleted`, `variant_phased_out`, `variant_deleted`)."},{"fix":"Check the amount and its decimal places.","status":422,"when":"A price, quantity or calculated total is out of range (`amount_out_of_range`)."},{"fix":"Ask the team owner for sales order edit permission, or assign the user to the order.","status":403,"when":"The API key's role can't edit this order (`user_is_not_authorized`)."},{"fix":"Check the id.","status":404,"when":"The order or line does not exist in this team: `error.code` is null and `error.message` says \"No query results for …\"."}],"group":"Sales","notes":["Prices keep up to 6 decimal places and quantities up to 8. The product price is then rounded to 2 decimal places (3 when you give 3 or more).","A variant product has one line per size and color: send each variant's own id. Put a product's sizes on one job so quantity breaks apply.","Get a catalog item's current supplier cost from the catalog pricing lookup before adding it.","The order number (SO1001) is not an id here: use the order's `id` or `unique_key`."],"permission":"Needs permission to edit this sales order or quote:\n\n- The team owner\n- A role with `update_all_order`\n- A role with `update_self_order`, when the order was created by or is assigned to the API key's user\n- The person who created a draft, with `create_order`\n\nQuotes use the same sales order permissions.","related":["v2_public_order_item_bulk","v2_public_order_item_update","v2_public_order_item_index","v2_public_job_store","v2_public_order_show","v1_public_real_time_data_fetcher_pricing","v1_public_products_index"],"rules":["`product.type` picks the kind of line; send the `pricing.type` that matches it: `db_catalog` takes `catalog_product_pricing`; `user_simple` and `db_variant` take `product_cost_service`; `custom` takes `custom_product`; `fee` takes `fee`. YoPrint refuses a mismatch with 422 `validation_failed` (`error.fields` names `pricing.type`).","`product.properties.customer_supplied` is required for every kind except fees.","A new catalog line must carry its catalog cost in `pricing.catalog` (`provider`, `selected`, `date` and `total`, all four required). Without it the line is refused with 422 `validation_failed` and `error.fields` `pricing.catalog`: \"Enter the catalog cost for this line.\" The only exception is a line the customer supplies (`product.properties.customer_supplied` true, 1, \"1\" or \"true\"): it needs neither `pricing.catalog` nor `pricing.product`.","A line linked to a job must use a job of the same order. A line with `job.type` standalone has no decoration price.","A custom line needs `pricing.product.total`; a fee needs `pricing.product.total` of 0 or more.","A phased-out or deleted product, size or color can't be added.","`position` is a whole number. `weight.total` takes its `value` and `dp` as strings.","Lines that an integration brought in can't be created through the API (`is_external` is refused)."],"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."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}/order_item/bulk":{"post":{"description":"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.\n\nThe body is a JSON **array** of operations. Each has your own `bid`, an `action` and, depending on the action:\n\n- `create`: `payload` is the body of Add a line item;\n- `update`: `cart_item_id` (the line's id) and `payload`, the body of Update a line item (send only what changes);\n- `delete`: `cart_item_id` only.\n\nWhatever 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.\n\nThe optional header `X-Yoprint-Order-Item-Save-Intent` says what the save is for. The web app sends `save`.\n\n- `save`: when nothing in the batch changes anything, nothing is written and `has_changes` is false;\n- `recalculate`: always recalculates, even when only a description or position changed;\n- left out (or any other value): the older behavior, where `has_changes` is always true.\n\nAmounts 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.\n\n`{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.\n\nThe 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.\n\nA new line is refused with HTTP 422 if the product or variant cannot be sold:\n\n- Simple product phased out: 422 `product_phased_out` (`error.product_id` names it)\n- Simple product deleted: 422 `product_deleted` (`error.product_id` names it)\n- Size or color phased out: 422 `variant_phased_out` (`error.variant_id` names it)\n- Size or color deleted: 422 `variant_deleted` (`error.variant_id` names it)\n\nThis 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`.","operationId":"v2_public_order_item_bulk","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"order_unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}},{"description":"`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.","in":"header","name":"X-Yoprint-Order-Item-Save-Intent","required":false,"schema":{"enum":["save","recalculate"],"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"mixed":{"summary":"Change one line's quantity and delete another","value":[{"action":"update","bid":"u1","cart_item_id":"Owr88lhAk28aqL","payload":{"quantity":{"total":{"dp":0,"value":30},"type":"unit"}}},{"action":"delete","bid":"d1","cart_item_id":"HF0BYICEJ09rG2"}]},"size_run":{"summary":"Add two sizes of a variant product to one job","value":[{"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"}}}]}},"schema":{"description":"The operations, each with your own `bid`.","items":{"discriminator":{"mapping":{"create":"#/components/schemas/AddLine","delete":"#/components/schemas/DeleteLine","update":"#/components/schemas/ChangeLine"},"propertyName":"action"},"oneOf":[{"$ref":"#/components/schemas/AddLine"},{"$ref":"#/components/schemas/ChangeLine"},{"$ref":"#/components/schemas/DeleteLine"}],"title":"Operation","x-yoprint-discriminator":{"mapping":{"create":"Add a line","delete":"Delete a line","update":"Change a line"},"propertyPath":"action"}},"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"action_performed":"CREATED","bid":"b1","has_changes":true,"item":{"id":"Aj4yrI88nPeeJR","job":{"id":"K6iF8n29iwOZnj","scoped_id":"JOB-1001","type":"linked","unique_key":"job_EXAMPLEuniqueKey"},"lock_version":1793696400234567,"order_id":"V4keXwwxMQyXw7","order_unique_key":"ord_EXAMPLEuniqueKey","position":100000,"pricing":{"product":{"override":false,"total":{"dp":6,"value":12500000}},"type":"product_cost_service"},"product":{"properties":{"customer_supplied":false,"id":"TGbMAohWcL31V0"},"type":"db_variant"},"quantity":{"total":{"dp":0,"value":12},"type":"unit"},"subtotal":{"dp":4,"value":1500000},"trashed":false,"type":"db_variant","unit_price":{"dp":6,"value":12500000}},"lock_version":{"order":{"invoice_lock_version":1793696400123456,"job_lock_version":1793696400123456,"order_item_lock_version":1793696400234567,"order_lock_version":1793696400234567,"payment_lock_version":1793696400123456,"shipment_lock_version":null}},"object_type":"order_item"},{"action_performed":"CREATED","bid":"b2","has_changes":true,"item":{"id":"an9jhUMlXwOTLr","job":{"id":"K6iF8n29iwOZnj","scoped_id":"JOB-1001","type":"linked","unique_key":"job_EXAMPLEuniqueKey"},"lock_version":1793696400234567,"order_id":"V4keXwwxMQyXw7","order_unique_key":"ord_EXAMPLEuniqueKey","position":200000,"pricing":{"product":{"override":false,"total":{"dp":6,"value":12500000}},"type":"product_cost_service"},"product":{"properties":{"customer_supplied":false,"id":"ZrdJ9i78QVmdhr"},"type":"db_variant"},"quantity":{"total":{"dp":0,"value":18},"type":"unit"},"subtotal":{"dp":4,"value":2250000},"trashed":false,"type":"db_variant","unit_price":{"dp":6,"value":12500000}},"lock_version":{"order":{"invoice_lock_version":1793696400123456,"job_lock_version":1793696400123456,"order_item_lock_version":1793696400234567,"order_lock_version":1793696400234567,"payment_lock_version":1793696400123456,"shipment_lock_version":null}},"object_type":"order_item"}],"has_changes":true,"status":200,"success":true},"schema":{"properties":{"data":{"description":"Every line of the order after the save.","items":{"additionalProperties":true,"properties":{"action_performed":{"description":"Ignore this field here: always `CREATED` in this answer.","type":"string"},"bid":{"description":"Your `bid` for a line this request created; null for other lines.","type":["string","null"]},"has_changes":{"description":"Ignore this field here: always `true` on every row. Read the top-level `has_changes` next to `data`.","type":"boolean"},"item":{"additionalProperties":true,"description":"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).","properties":{"_meta":{"additionalProperties":true,"description":"The line's own values again (`id`, `type`, `order_id`, `unit_price`, `subtotal` and so on). Always an object.","type":"object"},"id":{"example":"Owr88lhAk28aqL","type":"string"},"inventory_status":{"description":"Stock status of the line.","type":["string","null"]},"job":{"additionalProperties":true,"type":"object"},"lock_version":{"description":"The line's own lock version (a microsecond timestamp).","type":["integer","null"]},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_unique_key":{"description":"The order's `unique_key`. The line's own `unique_key` is not in the answer: use `id`.","example":"ord_EXAMPLEuniqueKey","type":"string"},"position":{"example":200000,"type":"integer"},"pricing":{"additionalProperties":true,"type":"object"},"pricing_rule_applied":{"description":"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.","properties":{"after":{"description":"Full summary only: the price after the rule, as a decimal string.","example":"11.05","type":"string"},"after_total":{"description":"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.","example":{"dp":6,"value":11050000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"base":{"description":"Full summary only: that starting price, as a decimal string with at least 2 decimal places.","example":"8.50","type":"string"},"base_type":{"description":"Full summary only: what the rule started from: the supplier price for catalog lines, the product's own price for other lines.","enum":["supplier_price","base_price"],"type":"string"},"normal_price":{"description":"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`.","example":"11.05","type":["string","null"]},"original_total":{"description":"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.","example":{"dp":6,"value":8500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"pricing_group_id":{"description":"The pricing group whose rule applied.","example":"PvlX5QRtc6cV6V","type":["string","null"]},"pricing_group_name":{"description":"Full summary only: the group's name now.","example":"Wholesale","type":["string","null"]},"pricing_group_removed":{"description":"Full summary only: true when the group was removed since. The line keeps its price.","type":["boolean","null"]},"pricing_rule_id":{"description":"The rule that applied.","example":"GsFEqlEx4WIp7n","type":["string","null"]},"rule":{"description":"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.","properties":{"id":{"example":"GsFEqlEx4WIp7n","type":"string"},"label":{"example":"Tees over 48 pieces","type":["string","null"]},"position":{"example":2,"type":"integer"}},"type":["object","null"]},"type":{"description":"`product` on a line.","example":"product","type":"string"}},"type":["object","null"]},"product":{"additionalProperties":true,"type":"object"},"quantity":{"additionalProperties":true,"description":"The quantity, trailing zeros dropped: 10 is `{ \"value\": 10, \"dp\": 0 }`.","type":"object"},"subtotal":{"description":"`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.","example":{"dp":4,"value":1250000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"trashed":{"description":"true when the line was deleted.","example":false,"type":"boolean"},"type":{"description":"The kind of line: db_catalog, user_simple, db_variant, custom or fee.","example":"user_simple","type":"string"},"unit_price":{"description":"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.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"}},"type":"object"},"lock_version":{"description":"The order's lock versions after this call. Each is a whole number (a microsecond timestamp) that changes on every save, or null.","properties":{"order":{"properties":{"invoice_lock_version":{"type":["integer","null"]},"job_lock_version":{"type":["integer","null"]},"order_item_lock_version":{"type":["integer","null"]},"order_lock_version":{"description":"The order's own `lock_version`.","type":["integer","null"]},"payment_lock_version":{"type":["integer","null"]},"shipment_lock_version":{"type":["integer","null"]}},"type":"object"}},"required":["order"],"type":"object"},"object_type":{"const":"order_item","example":"order_item","type":"string"}},"type":"object"},"type":"array"},"has_changes":{"description":"false when the batch changed nothing (with the `save` intent).","type":"boolean"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data","has_changes"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/BulkValidationPayloadResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add, change and delete line items in one save","tags":["Sales order line items"],"x-yoprint-docs":{"errors":[{"fix":"Fix the operation named by `bid` and resend the whole batch.","status":422,"when":"One operation is invalid (`bulk_validation_payload_failed`, with `error.bid` and `error.fields`)."},{"fix":"Use line ids from this order.","status":422,"when":"`cart_item_id` is not a line of this order: `validation_error` \"Order item not found\"."},{"fix":"Read `error.fields`; send whole numbers in `value` and the decimal places in `dp` (for example `{\"value\": 1250, \"dp\": 2}` for 12.50).","status":422,"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":"Use an id from Products, or a catalog item id.","status":422,"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 a job id from this order's jobs.","status":422,"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":"Fix the job's services in the web app, then retry.","status":422,"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":"Resume it in Products, or choose another product.","status":422,"when":"The product, or its size or color, is phased out or deleted (`product_phased_out`, `product_deleted`, `variant_phased_out`, `variant_deleted`)."},{"fix":"Check the amount and its decimal places.","status":422,"when":"A price, quantity or calculated total is out of range (`amount_out_of_range`)."},{"fix":"Ask the team owner for sales order edit permission, or assign the user to the order.","status":403,"when":"The API key's role can't edit this order (`user_is_not_authorized`)."},{"fix":"Check the id.","status":404,"when":"The order or line does not exist in this team: `error.code` is null and `error.message` says \"No query results for …\"."}],"group":"Sales","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."],"permission":"Needs permission to edit this sales order or quote:\n\n- The team owner\n- A role with `update_all_order`\n- A role with `update_self_order`, when the order was created by or is assigned to the API key's user\n- The person who created a draft, with `create_order`\n\nQuotes use the same sales order permissions.","related":["v2_public_order_item_store","v2_public_order_item_update","v2_public_order_item_destroy","v2_public_order_item_index"],"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."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}/production_note":{"put":{"description":"Sets the order's production note, for your shop floor. The customer does not see it.\n\nWorks on drafts, published and deleted orders. The answer is the order. `{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.","operationId":"v2_public_order_production_note_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"order_unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"production_note":"Ship in two boxes."},"schema":{"properties":{"production_note":{"description":"The production note. Send `null` to clear it. Leave the field out to change nothing.","type":["string","null"]}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[],"calc_deposit_total":67500,"customer":{"id":"63KcENAAsKuipY","is_external":false,"name":"Northwind Apparel","tax_exempt":false},"customer_id":"63KcENAAsKuipY","customer_po_number":"PO-1188","deposit_amount_due":{"dp":4,"value":175000},"deposit_required":true,"deposit_total":50000,"due_date":"2026-11-14T00:00:00+00:00","id":"V4keXwwxMQyXw7","internal_status":"published","invoiced_discount_subtotal":{"dp":4,"value":0},"invoiced_order_item_subtotal":{"dp":4,"value":1250000},"invoiced_shipment_subtotal":{"dp":4,"value":0},"invoiced_tax_subtotal":{"dp":4,"value":100000},"invoiced_total":{"dp":4,"value":1350000},"is_rush":false,"issue_date":"2026-11-03T00:00:00+00:00","mode":"view","name":"Spring team shirts","object_type":"sales_order","order_balance_due":{"dp":4,"value":850000},"order_item_cart_total":{"dp":4,"value":1250000},"paid_amount":50000,"prod_note":"Ship in two boxes.","quote":false,"scoped_id":"SO1001","status":{"color":"#2196f3","customer_label":"In Progress","id":"52CuV8sWcDZLPm","label":"In production","position":2,"role":"order","trashed":false,"type":"in_progress"},"status_id":"52CuV8sWcDZLPm","total_qty_need_ordering":"0.00000000","trashed":false,"type":"order","unique_key":"ord_EXAMPLEuniqueKey"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A sales order or quote.","properties":{"approval_status":{"description":"`requested`, `sent-to-customer`, `viewed-by-customer`, `need-changes` or `approved`; null without approvals.","type":["string","null"]},"assigned_users":{"description":"The team members in the order's Assigned To list (always included).","items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"auto_invoice_managed":{"description":"true when YoPrint keeps one invoice in step with the order.","type":"boolean"},"auto_invoice_shipment_price_type":{"description":"`DONOTMANAGE`, `NONE`, `MARKUP` or `MARGIN`.","type":["string","null"]},"auto_invoice_shipment_rate":{"description":"The MARKUP or MARGIN percentage. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"auto_invoice_type":{"description":"How the automatic invoice is built. Always `single_invoice` today.","type":["string","null"]},"billing_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"billing_address_id":{"type":["string","null"]},"calc_deposit_total":{"description":"The deposit amount, rounded to 2 decimal places: the percentage of `order_item_cart_total`, or of the invoiced total once every line is invoiced (or the invoiced total reaches the order's); 0 unless `deposit_required`. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `invoiced_discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `invoiced_order_item_subtotal`, which already includes billed shipping. This older field adds `invoiced_shipment_subtotal` to it once more. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `invoiced_tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `invoiced_total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"client_note":{"description":"The Client Note.","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_by":{"description":"Created By (a team member id).","type":["string","null"]},"creator_name":{"type":["string","null"]},"cust_due_date":{"description":"Customer in-hands date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"Always present on order answers, lists included: the customer record, or null when the order has none. Get a sales order also nests the customer's contacts, addresses, brand profiles, tags, files and assigned users in it.","properties":{"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"id":{"example":"63KcENAAsKuipY","type":"string"},"is_external":{"description":"true for a customer synced from an integration.","type":"boolean"},"name":{"example":"Northwind Apparel","type":"string"},"tax_exempt":{"type":"boolean"}},"type":["object","null"]},"customer_billing_contact_id":{"description":"The id of the contact on the order (the same contact as `customer_contact_id`), or null.","type":["string","null"]},"customer_contact_id":{"type":["string","null"]},"customer_has_email":{"type":"boolean"},"customer_id":{"example":"63KcENAAsKuipY","type":["string","null"]},"customer_po_number":{"example":"PO-1188","type":["string","null"]},"customer_profile_id":{"description":"Brand profile.","type":["string","null"]},"deposit_amount_due":{"description":"Deposit still to pay (negative once overpaid). A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"deposit_due":{"description":"Deposit due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"deposit_required":{"type":"boolean"},"deposit_total":{"description":"The deposit as a **percentage** of the order. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","type":["integer","number","string","null"]},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"external_ids":{"description":"The order's links to records in other systems. An empty list when there are none.","items":{"additionalProperties":true,"description":"One link to a record in another system (Shopify, QuickBooks and so on): `id`, `external_integration_id`, `external_id`, `data`, `created_at`, `updated_at` and the nested `external_integration`.","type":"object"},"type":"array"},"external_type":{"description":"`shopify` for a Shopify order; null for YoPrint orders.","type":["string","null"]},"from_legacy":{"description":"true for an order that was moved over from the old format.","type":"boolean"},"full_amount_due":{"description":"Full payment due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"grouped_pdf":{"description":"PDF links, grouped: `Main` (only for roles with `view_order_finance`), `Job` (not on Shopify orders), `Shipment` and the team's templates.","items":{"additionalProperties":true,"properties":{"documents":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"label":{"example":"Main","type":"string"}},"type":"object"},"type":"array"},"has_external_integration_sync_error":{"description":"true when the last sync with an integration failed.","type":"boolean"},"has_invoice":{"description":"true when the order has at least one invoice, so a zero invoiced total can be told apart from no invoice.","type":"boolean"},"has_not_invoiced_items":{"description":"true when some line items are not on an invoice yet.","type":"boolean"},"has_over_invoiced_items":{"description":"true when some line items are invoiced for more than the order has.","type":"boolean"},"has_shipment_items_not_allocated":{"description":"true when some line items are not on a shipment yet.","type":"boolean"},"has_shipment_items_over_allocated":{"description":"true when some line items are on shipments for more than the order has.","type":"boolean"},"has_valid_invoice":{"description":"true when at least one of the order's invoices is in a valid state.","type":"boolean"},"has_valid_shipment":{"description":"true when at least one of the order's shipments is in a valid state.","type":"boolean"},"id":{"description":"The order's hash id: use it in every other call.","example":"V4keXwwxMQyXw7","type":"string"},"internal_status":{"description":"`draft` until published.","enum":["draft","published"],"type":"string"},"inventory_status":{"description":"Stock status of the order's lines: `not_committed`, `committed`, `partially_committed`, `not_applicable` or `pending`.","type":["string","null"]},"invoice_lock_version":{"description":"Changes whenever the order's invoices change.","type":["integer","string","null"]},"invoiced_discount_subtotal":{"description":"Discounts on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_order_item_subtotal":{"description":"The lines and shipping fees the order's invoices bill (the sum of their `cart_item_subtotal`); 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_shipment_subtotal":{"description":"The shipping fees in `invoiced_order_item_subtotal`; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_tax_subtotal":{"description":"Tax on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_total":{"description":"Total of the order's invoices. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"is_client_note_editable":{"description":"false for a Shopify order, whose client note comes from Shopify.","type":"boolean"},"is_external":{"description":"true for an order synced from an integration such as Shopify.","type":"boolean"},"is_legacy":{"description":"true for an order made in the old format.","type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"job_lock_version":{"description":"Changes whenever the order's jobs change.","type":["integer","string","null"]},"last_payment_request_date":{"description":"When a payment reminder was last emailed for the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"lock_version":{"description":"Changes on every save.","type":["integer","string","null"]},"mode":{"description":"Older flag: `create` for a draft, `view` once published.","enum":["create","view","edit"],"type":"string"},"name":{"example":"Spring team shirts","type":["string","null"]},"object_type":{"enum":["sales_order","quote"],"type":"string"},"order_balance_due":{"description":"Invoiced total minus paid. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_cart_total":{"description":"The value of the order's lines: the order's own total before invoicing. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_lock_version":{"description":"Changes whenever the order's line items change.","type":["integer","string","null"]},"order_margin_percentage":{"description":"Margin, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_markup_percentage":{"description":"Markup, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_profit":{"description":"Profit. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"paid_amount":{"description":"Paid so far. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"payment_lock_version":{"description":"Changes whenever the order's payments change.","type":["integer","string","null"]},"payment_term_id":{"type":["string","null"]},"pricing_group_id":{"type":["string","null"]},"pricing_strategy":{"description":"`job_separately`, `job_together` or `service_loc_together`.","type":["string","null"]},"prod_note":{"description":"The production note.","type":["string","null"]},"producible_item_count":{"description":"Quantity to produce.","type":["number","integer","string","null"]},"quickbook_disable_sync":{"description":"true when QuickBooks sync is off for this order.","type":"boolean"},"quickbook_disable_sync_at":{"description":"When the switch was last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_disable_sync_by":{"description":"The team member who last changed the switch, or null.","type":["string","null"]},"quickbook_disable_sync_reason":{"description":"The note given at the last change of the order's QuickBooks sync switch (off or back on), at most 500 characters, or null.","type":["string","null"]},"quickbook_last_error_sync":{"description":"When a QuickBooks sync of the order last failed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_last_success_sync":{"description":"When QuickBooks last accepted the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbooks_hold":{"description":"Set when YoPrint holds back a QuickBooks payment covering this order: `code` is `changed`, `deleted` or `rejected` (the payment was changed or deleted in QuickBooks, or QuickBooks refused a change), and `detail` is `already_deposited` (the payment is in a QuickBooks bank deposit) or null. Null when nothing is held.","properties":{"code":{"enum":["changed","deleted","rejected"],"type":"string"},"detail":{"type":["string","null"]}},"type":["object","null"]},"quote":{"description":"Older flag: true for a quote.","type":"boolean"},"scoped_id":{"description":"The order number people see, `SO` and at least four digits (quotes too). Not an id.","example":"SO1001","type":"string"},"ship_due_date":{"description":"Ship due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shipment_billable_fee_invoice_status":{"description":"Whether those shipping fees are on an invoice. Null when there is nothing to bill.","type":["string","null"]},"shipment_billable_fee_total":{"description":"The shipping fees you bill the customer on the order's shipments. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_cost_total":{"description":"Shipping cost incurred. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_lock_version":{"description":"Changes whenever the order's shipments change.","type":["integer","string","null"]},"shipping_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"shipping_address_id":{"type":["string","null"]},"shopify_last_error_sync":{"description":"When a Shopify sync of the order last failed. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_last_success_sync":{"description":"When Shopify last accepted the order. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_terminal_topic":{"description":"Shopify orders only: the Shopify event name behind the order's final state there. Null on YoPrint orders. The answer can also hold more `shopify_*` fields (`shopify_admin_url`, `shopify_compliance_deletion`, `shopify_finance_notices`, `shopify_has_fulfillment_conflict`, `shopify_last_fulfillment_conflict_at`): they are null or empty on YoPrint orders.","type":["string","null"]},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"The order's status (always included).","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_completion_date":{"description":"When the order's status last moved to an end status. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status_id":{"description":"The order's status (from the team's sales order or quote statuses).","example":"52CuV8sWcDZLPm","type":"string"},"status_last_change_date":{"description":"Last status change. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"tags":{"items":{"additionalProperties":true,"properties":{"color_hex":{"description":"Tag color, for example `#E53935`.","type":["string","null"]},"id":{"example":"7qYPMmbLZR9oFg","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"total_qty_need_ordering":{"description":"Quantity still to buy, as a decimal string with 8 decimal places (`\"24.00000000\"`).","example":"0.00000000","type":"string"},"trashed":{"description":"true when the order is deleted.","type":"boolean"},"type":{"description":"Older name for `object_type`.","enum":["order","quote"],"type":"string"},"unallocated_amount":{"description":"Payments not yet allocated to an invoice. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"unique_key":{"description":"The order's unique key (`ord_…`); accepted wherever `{order_unique_key}` is.","example":"ord_EXAMPLEuniqueKey","type":"string"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"version":{"description":"The order format version.","type":["integer","string","null"]},"wallet_currency_iso":{"description":"The order's currency code (`USD` and so on), or null on older orders without one.","example":"USD","type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"required":["id","unique_key","scoped_id","object_type","internal_status"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Set the production note of a sales order or quote","tags":["Sales orders"],"x-yoprint-docs":{"errors":[{"fix":"Send a string or null.","status":422,"when":"The note is not a string, or the Shopify order was deleted in Shopify."},{"fix":"Ask the team owner for sales order edit permission.","status":403,"when":"The API key's role can't edit this order."}],"group":"Sales","permission":"Needs permission to edit this sales order or quote:\n\n- The team owner\n- A role with `update_all_order`\n- A role with `update_self_order`, when the order was created by or is assigned to the API key's user\n- The person who created a draft, with `create_order`\n\nQuotes use the same sales order permissions.","related":["v2_public_order_customer_note_update"],"rules":["Refused when the Shopify order was deleted in Shopify (`shopify_order_deleted_externally`)."],"side_effects":["On a published order, records the change in the order history.","Refreshes the order for people who have it open in the web app."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}/publish":{"patch":{"description":"Publishes a draft: what the Publish button does in the web app. The order or quote then counts as created, shows in lists and reports, and can take payments, approvals and comments.\n\nPublishing checks four things and reports them in `data.validation`: the order has a customer (`has_customer`), at least one line (`has_order_items`), no line on a phased-out or deleted product, size or color (`has_sellable_items`), and its pricing group is still in use (`removed_pricing_group`).\n\nWhen a check fails the draft is not published: the answer is still 200, with `data.valid: false`. `data.validation.unsellable_items` lists each unsellable line with its `reason` (`product_phased_out`, `product_deleted`, `variant_phased_out` or `variant_deleted`): replace or remove those lines. `data.validation.removed_pricing_group` is null, or names the draft's pricing group when it was removed (`{ id, name, removed, disabled }`): choose another group with the `change_pricing_group` action. Then publish again.\n\nWhen all checks pass the answer is `data.valid: true`. Do not rely on the HTTP status code alone: check `success` and `data.valid` in the response body to confirm the draft was published.\n\n`{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.","operationId":"v2_public_order_publish","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"order_unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"accepted":{"summary":"Done","value":{"data":{"id":"V4keXwwxMQyXw7","lock_version":{"invoice_lock_version":1793696400123456,"job_lock_version":1793696400123456,"order_item_lock_version":1793696400234567,"order_lock_version":1793696400234567,"payment_lock_version":1793696400123456,"shipment_lock_version":null},"valid":true,"validation":{"has_customer":true,"has_order_items":true,"has_sellable_items":true,"unsellable_items":[]}},"status":200,"success":true}},"refused":{"summary":"Refused with HTTP 200: `success` is false","value":{"error":{"code":"action_not_allowed","message":null},"status":500,"success":false}}},"schema":{"oneOf":[{"properties":{"data":{"additionalProperties":true,"description":"The publish result. Check `valid`.","properties":{"id":{"example":"V4keXwwxMQyXw7","type":"string"},"lock_version":{"description":"The order's lock versions after the call: whole numbers (microsecond timestamps) or null. Always an object with these six keys.","properties":{"invoice_lock_version":{"type":["integer","null"]},"job_lock_version":{"type":["integer","null"]},"order_item_lock_version":{"type":["integer","null"]},"order_lock_version":{"description":"The order's own `lock_version`.","type":["integer","null"]},"payment_lock_version":{"type":["integer","null"]},"shipment_lock_version":{"type":["integer","null"]}},"type":"object"},"valid":{"description":"true when the order was published.","type":"boolean"},"validation":{"additionalProperties":true,"properties":{"has_customer":{"type":"boolean"},"has_order_items":{"type":"boolean"},"has_sellable_items":{"type":"boolean"},"unsellable_items":{"description":"Lines on a phased-out or deleted product, size or color, in line order; `[]` when there are none.","items":{"additionalProperties":true,"properties":{"color_id":{"description":"Variant lines only.","type":["string","null"]},"id":{"description":"The line.","type":"string"},"job_id":{"description":"The line's job, or null.","type":["string","null"]},"product_color":{"description":"Variant lines only.","type":["string","null"]},"product_name":{"type":["string","null"]},"product_size":{"description":"Variant lines only.","type":["string","null"]},"product_type":{"enum":["user_simple","db_variant"],"type":"string"},"reason":{"enum":["product_phased_out","product_deleted","variant_phased_out","variant_deleted"],"type":"string"},"size_id":{"description":"Variant lines only.","type":["string","null"]}},"type":"object"},"type":"array"}},"required":["has_customer","has_order_items","has_sellable_items","unsellable_items"],"type":"object"}},"required":["id","valid","validation"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"const":true,"example":true,"type":"boolean"}},"required":["success","status","data"],"title":"Success","type":"object"},{"$ref":"#/components/schemas/ErrorResponse"}]}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Publish a draft sales order or quote","tags":["Sales orders"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Add a customer or lines, replace the unsellable lines, or choose another pricing group (`change_pricing_group`), then publish again.","status":200,"when":"A check failed: `data.valid` is false and `data.validation` says which."},{"fix":"Check `success` in every reply. Read the order first: `internal_status` must be `draft`.","status":200,"when":"The order is not a draft: `success: false`, `error.code` `action_not_allowed` (the body's `status` says 500)."},{"fix":"Ask the team owner for sales order edit permission.","status":403,"when":"The API key's role can't edit this order."},{"fix":"Check the id; restore a deleted draft first.","status":404,"when":"No such order in this team, or it is deleted."}],"group":"Sales","notes":["Do not rely on the HTTP status code alone. Always check `success` and `data.valid` in the response body: a 200 does not mean it was published."],"permission":"Needs permission to edit this sales order or quote:\n\n- The team owner\n- A role with `update_all_order`\n- A role with `update_self_order`, when the order was created by or is assigned to the API key's user\n- The person who created a draft, with `create_order`\n\nQuotes use the same sales order permissions.","related":["v2_public_order_create","v2_public_order_item_store","v2_public_order_single_action"],"rules":["Only drafts can be published. Publishing an order that is already published answers **HTTP 200** with `{\"status\": 500, \"success\": false, \"error\": {\"code\": \"action_not_allowed\", \"message\": null}}` and changes nothing. Always check `success` and `data.valid` in the response body, not the HTTP status code.","A draft without a customer, without lines, with an unsellable line, or on a removed pricing group is not published."],"side_effects":["Sends the `order.created` webhook (`quote.created` for a quote).","Works out stock status for the order's lines and jobs, and updates the customer's totals.","When the team syncs to QuickBooks Online automatically, publishing a sales order that already has invoices (for example a copy made with `clone_order`) queues a sync.","Emails nobody. Customer Portal pages the customer has open refresh."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}/restore":{"patch":{"description":"Brings back a deleted sales order or quote with its lines, jobs, invoices, shipments and messages.\n\nRestoring an order that isn't deleted answers **HTTP 200** with `{\"status\": 500, \"success\": false, \"error\": {\"code\": \"action_not_allowed\", \"message\": null}}`. Do not rely on the HTTP status code alone: check `success` in the response body to confirm the restore succeeded. The answer is otherwise the restored order.\n\n`{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.","operationId":"v2_public_order_restore","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"order_unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"accepted":{"summary":"Done","value":{"data":{"assigned_users":[],"calc_deposit_total":67500,"customer":{"id":"63KcENAAsKuipY","is_external":false,"name":"Northwind Apparel","tax_exempt":false},"customer_id":"63KcENAAsKuipY","customer_po_number":"PO-1188","deposit_amount_due":{"dp":4,"value":175000},"deposit_required":true,"deposit_total":50000,"due_date":"2026-11-14T00:00:00+00:00","id":"V4keXwwxMQyXw7","internal_status":"published","invoiced_discount_subtotal":{"dp":4,"value":0},"invoiced_order_item_subtotal":{"dp":4,"value":1250000},"invoiced_shipment_subtotal":{"dp":4,"value":0},"invoiced_tax_subtotal":{"dp":4,"value":100000},"invoiced_total":{"dp":4,"value":1350000},"is_rush":false,"issue_date":"2026-11-03T00:00:00+00:00","mode":"view","name":"Spring team shirts","object_type":"sales_order","order_balance_due":{"dp":4,"value":850000},"order_item_cart_total":{"dp":4,"value":1250000},"paid_amount":50000,"quote":false,"scoped_id":"SO1001","status":{"color":"#2196f3","customer_label":"In Progress","id":"52CuV8sWcDZLPm","label":"In production","position":2,"role":"order","trashed":false,"type":"in_progress"},"status_id":"52CuV8sWcDZLPm","total_qty_need_ordering":"0.00000000","trashed":false,"type":"order","unique_key":"ord_EXAMPLEuniqueKey"},"status":200,"success":true}},"refused":{"summary":"Refused with HTTP 200: `success` is false","value":{"error":{"code":"action_not_allowed","message":null},"status":500,"success":false}}},"schema":{"oneOf":[{"properties":{"data":{"additionalProperties":true,"description":"A sales order or quote.","properties":{"approval_status":{"description":"`requested`, `sent-to-customer`, `viewed-by-customer`, `need-changes` or `approved`; null without approvals.","type":["string","null"]},"assigned_users":{"description":"The team members in the order's Assigned To list (always included).","items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"example":"PydH0WtBhSeiNU","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"description":"IANA time zone, for example `America/Chicago`.","type":["string","null"]}},"type":"object"},"type":"array"},"auto_invoice_managed":{"description":"true when YoPrint keeps one invoice in step with the order.","type":"boolean"},"auto_invoice_shipment_price_type":{"description":"`DONOTMANAGE`, `NONE`, `MARKUP` or `MARGIN`.","type":["string","null"]},"auto_invoice_shipment_rate":{"description":"The MARKUP or MARGIN percentage. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 12500000, \"dp\": 6 }` is 12.50). Kept with 6 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":6,"value":12500000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"auto_invoice_type":{"description":"How the automatic invoice is built. Always `single_invoice` today.","type":["string","null"]},"billing_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"billing_address_id":{"type":["string","null"]},"calc_deposit_total":{"description":"The deposit amount, rounded to 2 decimal places: the percentage of `order_item_cart_total`, or of the invoiced total once every line is invoiced (or the invoiced total reaches the order's); 0 unless `deposit_required`. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_discount":{"deprecated":true,"description":"**Deprecated:** use `invoiced_discount_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_subtotal":{"deprecated":true,"description":"**Deprecated:** use `invoiced_order_item_subtotal`, which already includes billed shipping. This older field adds `invoiced_shipment_subtotal` to it once more. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_tax":{"deprecated":true,"description":"**Deprecated:** use `invoiced_tax_subtotal`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"calc_total":{"deprecated":true,"description":"**Deprecated:** use `invoiced_total`, the same amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"client_note":{"description":"The Client Note.","type":["string","null"]},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"created_by":{"description":"Created By (a team member id).","type":["string","null"]},"creator_name":{"type":["string","null"]},"cust_due_date":{"description":"Customer in-hands date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"Always present on order answers, lists included: the customer record, or null when the order has none. Get a sales order also nests the customer's contacts, addresses, brand profiles, tags, files and assigned users in it.","properties":{"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"id":{"example":"63KcENAAsKuipY","type":"string"},"is_external":{"description":"true for a customer synced from an integration.","type":"boolean"},"name":{"example":"Northwind Apparel","type":"string"},"tax_exempt":{"type":"boolean"}},"type":["object","null"]},"customer_billing_contact_id":{"description":"The id of the contact on the order (the same contact as `customer_contact_id`), or null.","type":["string","null"]},"customer_contact_id":{"type":["string","null"]},"customer_has_email":{"type":"boolean"},"customer_id":{"example":"63KcENAAsKuipY","type":["string","null"]},"customer_po_number":{"example":"PO-1188","type":["string","null"]},"customer_profile_id":{"description":"Brand profile.","type":["string","null"]},"deposit_amount_due":{"description":"Deposit still to pay (negative once overpaid). A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"deposit_due":{"description":"Deposit due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"deposit_required":{"type":"boolean"},"deposit_total":{"description":"The deposit as a **percentage** of the order. A percentage ×1000: `8250` is 8.25%. With `X-Yoprint-Decimal-Format: exact-v1`, a value that isn't a whole number comes back as a string.","type":["integer","number","string","null"]},"due_date":{"description":"Production due. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"external_ids":{"description":"The order's links to records in other systems. An empty list when there are none.","items":{"additionalProperties":true,"description":"One link to a record in another system (Shopify, QuickBooks and so on): `id`, `external_integration_id`, `external_id`, `data`, `created_at`, `updated_at` and the nested `external_integration`.","type":"object"},"type":"array"},"external_type":{"description":"`shopify` for a Shopify order; null for YoPrint orders.","type":["string","null"]},"from_legacy":{"description":"true for an order that was moved over from the old format.","type":"boolean"},"full_amount_due":{"description":"Full payment due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"grouped_pdf":{"description":"PDF links, grouped: `Main` (only for roles with `view_order_finance`), `Job` (not on Shopify orders), `Shipment` and the team's templates.","items":{"additionalProperties":true,"properties":{"documents":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"label":{"example":"Main","type":"string"}},"type":"object"},"type":"array"},"has_external_integration_sync_error":{"description":"true when the last sync with an integration failed.","type":"boolean"},"has_invoice":{"description":"true when the order has at least one invoice, so a zero invoiced total can be told apart from no invoice.","type":"boolean"},"has_not_invoiced_items":{"description":"true when some line items are not on an invoice yet.","type":"boolean"},"has_over_invoiced_items":{"description":"true when some line items are invoiced for more than the order has.","type":"boolean"},"has_shipment_items_not_allocated":{"description":"true when some line items are not on a shipment yet.","type":"boolean"},"has_shipment_items_over_allocated":{"description":"true when some line items are on shipments for more than the order has.","type":"boolean"},"has_valid_invoice":{"description":"true when at least one of the order's invoices is in a valid state.","type":"boolean"},"has_valid_shipment":{"description":"true when at least one of the order's shipments is in a valid state.","type":"boolean"},"id":{"description":"The order's hash id: use it in every other call.","example":"V4keXwwxMQyXw7","type":"string"},"internal_status":{"description":"`draft` until published.","enum":["draft","published"],"type":"string"},"inventory_status":{"description":"Stock status of the order's lines: `not_committed`, `committed`, `partially_committed`, `not_applicable` or `pending`.","type":["string","null"]},"invoice_lock_version":{"description":"Changes whenever the order's invoices change.","type":["integer","string","null"]},"invoiced_discount_subtotal":{"description":"Discounts on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_order_item_subtotal":{"description":"The lines and shipping fees the order's invoices bill (the sum of their `cart_item_subtotal`); 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_shipment_subtotal":{"description":"The shipping fees in `invoiced_order_item_subtotal`; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_tax_subtotal":{"description":"Tax on the order's invoices; 0 until invoiced. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"invoiced_total":{"description":"Total of the order's invoices. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"is_client_note_editable":{"description":"false for a Shopify order, whose client note comes from Shopify.","type":"boolean"},"is_external":{"description":"true for an order synced from an integration such as Shopify.","type":"boolean"},"is_legacy":{"description":"true for an order made in the old format.","type":"boolean"},"is_rush":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"job_lock_version":{"description":"Changes whenever the order's jobs change.","type":["integer","string","null"]},"last_payment_request_date":{"description":"When a payment reminder was last emailed for the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"lock_version":{"description":"Changes on every save.","type":["integer","string","null"]},"mode":{"description":"Older flag: `create` for a draft, `view` once published.","enum":["create","view","edit"],"type":"string"},"name":{"example":"Spring team shirts","type":["string","null"]},"object_type":{"enum":["sales_order","quote"],"type":"string"},"order_balance_due":{"description":"Invoiced total minus paid. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_cart_total":{"description":"The value of the order's lines: the order's own total before invoicing. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_item_lock_version":{"description":"Changes whenever the order's line items change.","type":["integer","string","null"]},"order_margin_percentage":{"description":"Margin, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_markup_percentage":{"description":"Markup, in percent. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"order_profit":{"description":"Profit. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 1250, \"dp\": 2 }` is 12.50). Kept with 2 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":2,"value":1250},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"paid_amount":{"description":"Paid so far. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"payment_lock_version":{"description":"Changes whenever the order's payments change.","type":["integer","string","null"]},"payment_term_id":{"type":["string","null"]},"pricing_group_id":{"type":["string","null"]},"pricing_strategy":{"description":"`job_separately`, `job_together` or `service_loc_together`.","type":["string","null"]},"prod_note":{"description":"The production note.","type":["string","null"]},"producible_item_count":{"description":"Quantity to produce.","type":["number","integer","string","null"]},"quickbook_disable_sync":{"description":"true when QuickBooks sync is off for this order.","type":"boolean"},"quickbook_disable_sync_at":{"description":"When the switch was last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_disable_sync_by":{"description":"The team member who last changed the switch, or null.","type":["string","null"]},"quickbook_disable_sync_reason":{"description":"The note given at the last change of the order's QuickBooks sync switch (off or back on), at most 500 characters, or null.","type":["string","null"]},"quickbook_last_error_sync":{"description":"When a QuickBooks sync of the order last failed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbook_last_success_sync":{"description":"When QuickBooks last accepted the order. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"quickbooks_hold":{"description":"Set when YoPrint holds back a QuickBooks payment covering this order: `code` is `changed`, `deleted` or `rejected` (the payment was changed or deleted in QuickBooks, or QuickBooks refused a change), and `detail` is `already_deposited` (the payment is in a QuickBooks bank deposit) or null. Null when nothing is held.","properties":{"code":{"enum":["changed","deleted","rejected"],"type":"string"},"detail":{"type":["string","null"]}},"type":["object","null"]},"quote":{"description":"Older flag: true for a quote.","type":"boolean"},"scoped_id":{"description":"The order number people see, `SO` and at least four digits (quotes too). Not an id.","example":"SO1001","type":"string"},"ship_due_date":{"description":"Ship due date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shipment_billable_fee_invoice_status":{"description":"Whether those shipping fees are on an invoice. Null when there is nothing to bill.","type":["string","null"]},"shipment_billable_fee_total":{"description":"The shipping fees you bill the customer on the order's shipments. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_cost_total":{"description":"Shipping cost incurred. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_lock_version":{"description":"Changes whenever the order's shipments change.","type":["integer","string","null"]},"shipping_address":{"additionalProperties":true,"description":"An address, as the address operations return it.","properties":{"city":{"type":["string","null"]},"country_code":{"type":["string","null"]},"id":{"example":"RNG2OuYC20YzXs","type":"string"},"is_primary":{"type":"boolean"},"label":{"type":["string","null"]},"postcode":{"type":["string","null"]},"role":{"description":"`billing`, `shipping` or a warehouse role.","type":["string","null"]},"state_code":{"type":["string","null"]}},"type":["object","null"]},"shipping_address_id":{"type":["string","null"]},"shopify_last_error_sync":{"description":"When a Shopify sync of the order last failed. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_last_success_sync":{"description":"When Shopify last accepted the order. Shopify orders only. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"shopify_terminal_topic":{"description":"Shopify orders only: the Shopify event name behind the order's final state there. Null on YoPrint orders. The answer can also hold more `shopify_*` fields (`shopify_admin_url`, `shopify_compliance_deletion`, `shopify_finance_notices`, `shopify_has_fulfillment_conflict`, `shopify_last_fulfillment_conflict_at`): they are null or empty on YoPrint orders.","type":["string","null"]},"start_date":{"description":"Production start. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"The order's status (always included).","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_completion_date":{"description":"When the order's status last moved to an end status. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"status_id":{"description":"The order's status (from the team's sales order or quote statuses).","example":"52CuV8sWcDZLPm","type":"string"},"status_last_change_date":{"description":"Last status change. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"tags":{"items":{"additionalProperties":true,"properties":{"color_hex":{"description":"Tag color, for example `#E53935`.","type":["string","null"]},"id":{"example":"7qYPMmbLZR9oFg","type":"string"},"name":{"example":"Rush","type":"string"}},"type":"object"},"type":"array"},"total_qty_need_ordering":{"description":"Quantity still to buy, as a decimal string with 8 decimal places (`\"24.00000000\"`).","example":"0.00000000","type":"string"},"trashed":{"description":"true when the order is deleted.","type":"boolean"},"type":{"description":"Older name for `object_type`.","enum":["order","quote"],"type":"string"},"unallocated_amount":{"description":"Payments not yet allocated to an invoice. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"unique_key":{"description":"The order's unique key (`ord_…`); accepted wherever `{order_unique_key}` is.","example":"ord_EXAMPLEuniqueKey","type":"string"},"updated_at":{"description":"Last changed. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"version":{"description":"The order format version.","type":["integer","string","null"]},"wallet_currency_iso":{"description":"The order's currency code (`USD` and so on), or null on older orders without one.","example":"USD","type":["string","null"]},"warehouse_id":{"type":["string","null"]}},"required":["id","unique_key","scoped_id","object_type","internal_status"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"const":true,"example":true,"type":"boolean"}},"required":["success","status","data"],"title":"Success","type":"object"},{"$ref":"#/components/schemas/ErrorResponse"}]}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Restore a deleted sales order or quote","tags":["Sales orders"],"x-yoprint-docs":{"body":"none","errors":[{"fix":"Ask the team owner for sales order edit permission.","status":403,"when":"The API key's role can't edit this order."},{"fix":"Check `success` in the response body, not the HTTP status code. Read the order first: `trashed` must be true.","status":200,"when":"The order is not deleted: `success: false`, `error.code` `action_not_allowed` (the body's `status` says 500)."},{"fix":"Shopify orders can't be restored through the API.","status":422,"when":"A Shopify order: \"Cannot restore Shopify-synced order from API.\""},{"fix":"Check the id. Find deleted orders with the filter `trashed_only`.","status":404,"when":"No such order in this team."}],"group":"Sales","notes":["Do not rely on the HTTP status code alone. Check `success` in the response body to confirm the restore succeeded.","Payments moved to the customer's credit when the order was deleted stay as credit."],"permission":"Needs permission to edit this sales order or quote:\n\n- The team owner\n- A role with `update_all_order`\n- A role with `update_self_order`, when the order was created by or is assigned to the API key's user\n- The person who created a draft, with `create_order`\n\nQuotes use the same sales order permissions.","related":["v2_public_order_destroy","v2_public_sales_order_credit_pay_with_customer_credit"],"rules":["Only deleted orders can be restored. Restoring an order that is not deleted answers **HTTP 200** with `{\"status\": 500, \"success\": false, \"error\": {\"code\": \"action_not_allowed\", \"message\": null}}`. Always check `success` in the response body, not the HTTP status code."],"side_effects":["Sends the `order.restored` webhook (`quote.restored` for a quote); on a published order updates the customer's totals. Customer Portal pages the order's customer has open refresh (a live update, not an email).","Stock is not reserved again: the lines come back not committed. Shippo labels voided by the delete stay voided."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{unique_key}/invoice":{"get":{"description":"Returns the invoices of an order with their lines. `{unique_key}` is the order's `id` (for example `V4keXwwxMQyXw7`). The `ord_` unique key does not work here: it gives an empty list with status 200, not an error, so an empty list does not prove the order has none. An unknown id returns an empty list.","operationId":"v2_public_sales_order_invoice_index_for_order","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"id":"QRbvVd2ZKcvSTB","is_paid":false,"issue_date":"2026-11-03T00:00:00+00:00","items":[],"order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","paid_amount":50000,"scoped_id":"1001","total":{"dp":4,"value":1350000}}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"An invoice.","properties":{"auto_invoice_managed":{"type":"boolean"},"billing_address_id":{"type":["string","null"]},"calc_deposit_total":{"description":"The order's deposit amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"cart_item_subtotal":{"description":"Lines subtotal. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"The customer record, with the same fields as Get a customer (`GET /v1/api/store/{team_slug}/customer/{hash_id}`); the main ones are listed here.","properties":{"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"id":{"example":"63KcENAAsKuipY","type":"string"},"is_external":{"description":"true for a customer synced from an integration.","type":"boolean"},"name":{"example":"Northwind Apparel","type":"string"},"tax_exempt":{"type":"boolean"}},"type":["object","null"]},"discount_subtotal":{"description":"Discount. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"id":{"example":"QRbvVd2ZKcvSTB","type":"string"},"is_paid":{"type":"boolean"},"is_valid":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"items":{"description":"The invoice lines.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"paid_amount":{"description":"Paid on this invoice. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"pdf_url":{"description":"The invoice PDF links, despite the name: a list, first the standard invoice, then one per invoice PDF template the team has turned on.","items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"label":{"example":"Invoice","type":"string"},"object_type":{"example":"invoice","type":"string"},"url":{"description":"Link to the PDF.","type":"string"}},"type":"object"},"type":"array"},"scoped_id":{"description":"The invoice number, from the team's invoice counter.","example":"1001","type":"string"},"shipment_subtotal":{"description":"Shipping. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_tax_subtotal":{"description":"Tax on shipping. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipping_address_id":{"type":["string","null"]},"tax_subtotal":{"description":"Tax. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"total":{"description":"Invoice total. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"}},"required":["id","order_id","total"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the invoices of a sales order","tags":["Invoices"],"x-yoprint-docs":{"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_sales_order_invoice_create","v2_public_invoice_show"]}},"post":{"description":"Creates an invoice for an order, optionally with its lines in the same call.\n\nThe invoice starts with the order's billing and shipping address and issue date unless you send `billing_address_id`, `shipping_address_id` or `issue_date`. It gets the team's next invoice number.\n\nSend `{}` for an empty invoice. Lines go in `item_actions`, in the same shape as the invoice line bulk operation: each entry has your `bid`, an `action` (`create`, `update` or `delete`), `cart_item_id` for updates and deletes, and a `payload`. Without `item_actions` the invoice is created empty. `tax_selection` (with both `expected_tax` and `desired_tax`) sets the invoice's tax as Set the tax of an invoice does; `resort_items: true` re-sorts the lines.\n\nSend 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 422 `amount_out_of_range`.\n\nThe answer is the invoice (with its lines when you sent `item_actions`, `tax_selection` or `resort_items`). `{unique_key}` is the order's `id` (for example `V4keXwwxMQyXw7`) or its `unique_key` (`ord_…`).","operationId":"v2_public_sales_order_invoice_create","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"issue_date":"2026-11-03","item_actions":[{"action":"create","bid":"i1","payload":{"product":{"type":"order_item","properties":{"id":"Owr88lhAk28aqL"}},"quantity":{"type":"unit","total":{"value":10,"dp":0}},"tax":{"type":"taxable"},"position":100}},{"action":"create","bid":"i2","payload":{"product":{"type":"order_item","properties":{"id":"HF0BYICEJ09rG2"}},"quantity":{"type":"unit","total":{"value":12,"dp":0}},"tax":{"type":"taxable"},"position":200}}],"tax_selection":{"desired_tax":{"properties":{"id":"9jbPSC9ybBqXYJ"},"type":"user_tax"},"expected_tax":null}},"schema":{"properties":{"billing_address_id":{"description":"The billing address id. Default: the order's.","type":["string","null"]},"issue_date":{"description":"The invoice date (ISO 8601). Default: the order's issue date.","format":"date","type":"string"},"item_actions":{"description":"Invoice line operations, each with your own `bid`: `create` with `payload`; `update` with `cart_item_id` and `payload`; `delete` with `cart_item_id`.","items":{"properties":{"action":{"enum":["update","create","delete"],"type":"string"},"bid":{"type":"string"},"cart_item_id":{"description":"For `update` and `delete`: the invoice line's id.","type":"string"},"payload":{"additionalProperties":true,"description":"Required for `create` and `update`: one invoice line, the same body as Add a line to an invoice. Three common shapes. A sales order line: `{ \"product\": { \"type\": \"order_item\", \"properties\": { \"id\": \"<order line id>\" } }, \"quantity\": { \"type\": \"unit\", \"total\": { \"value\": 10, \"dp\": 0 } }, \"tax\": { \"type\": \"taxable\" }, \"position\": 100 }`. A shipping fee: `{ \"product\": { \"type\": \"shipment_fee\", \"properties\": { \"name\": \"Shipping\" } }, \"pricing\": { \"type\": \"fee\", \"product\": { \"total\": { \"value\": 1500, \"dp\": 2 } } }, \"position\": 200 }`. A percent discount: `{ \"product\": { \"type\": \"invoice_discount\", \"properties\": { \"type\": \"percent\", \"rate\": { \"value\": 10, \"dp\": 0 }, \"applies_to_shipping\": false } }, \"position\": 300 }`. Tax lines go in `tax_selection`, not here.","type":"object"}},"required":["bid","action"],"type":"object"},"type":"array"},"resort_items":{"description":"true to re-sort the invoice's lines.","type":"boolean"},"shipping_address_id":{"description":"The shipping address id. Default: the order's.","type":["string","null"]},"tax_selection":{"description":"The invoice's tax: send both `expected_tax` (the tax line you expect now, or null) and `desired_tax` (the tax you want, or null).","properties":{"desired_tax":{"properties":{"properties":{"additionalProperties":true,"description":"The tax's settings: for `user_tax`, `{ \"id\": tax preset id }`.","type":"object"},"type":{"enum":["auto_tax","user_tax","override_tax"],"type":"string"}},"type":["object","null"]},"expected_tax":{"properties":{"id":{"description":"The current tax line's id.","type":"string"},"lock_version":{"minimum":0,"type":"integer"}},"type":["object","null"]}},"type":"object"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"id":"QRbvVd2ZKcvSTB","is_paid":false,"issue_date":"2026-11-03T00:00:00+00:00","items":[{"id":"Lbzkl5xay8Ep8O","invoice_id":"QRbvVd2ZKcvSTB","type":"order_item"},{"id":"lHgM83jCmkQAnD","invoice_id":"QRbvVd2ZKcvSTB","type":"order_item"},{"id":"aYaSY9SejbWJK9","invoice_id":"QRbvVd2ZKcvSTB","type":"user_tax"}],"order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","paid_amount":0,"scoped_id":"1001","total":{"dp":4,"value":1350000}},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"An invoice.","properties":{"auto_invoice_managed":{"type":"boolean"},"billing_address_id":{"type":["string","null"]},"calc_deposit_total":{"description":"The order's deposit amount. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"cart_item_subtotal":{"description":"Lines subtotal. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"created_at":{"description":"Created. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer":{"additionalProperties":true,"description":"The customer record, with the same fields as Get a customer (`GET /v1/api/store/{team_slug}/customer/{hash_id}`); the main ones are listed here.","properties":{"default_payment_term_id":{"type":["string","null"]},"default_pricing_group_id":{"type":["string","null"]},"id":{"example":"63KcENAAsKuipY","type":"string"},"is_external":{"description":"true for a customer synced from an integration.","type":"boolean"},"name":{"example":"Northwind Apparel","type":"string"},"tax_exempt":{"type":"boolean"}},"type":["object","null"]},"discount_subtotal":{"description":"Discount. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"id":{"example":"QRbvVd2ZKcvSTB","type":"string"},"is_paid":{"type":"boolean"},"is_valid":{"type":"boolean"},"issue_date":{"description":"Issue date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"items":{"description":"The invoice lines.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"paid_amount":{"description":"Paid on this invoice. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","type":["integer","number","string","null"]},"pdf_url":{"description":"The invoice PDF links, despite the name: a list, first the standard invoice, then one per invoice PDF template the team has turned on.","items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"label":{"example":"Invoice","type":"string"},"object_type":{"example":"invoice","type":"string"},"url":{"description":"Link to the PDF.","type":"string"}},"type":"object"},"type":"array"},"scoped_id":{"description":"The invoice number, from the team's invoice counter. A new invoice created without lines answers it as a number (`6`); with lines, and in every later read, it is a string (`\"6\"`). Compare it as text.","example":"1001","type":["string","integer"]},"shipment_subtotal":{"description":"Shipping. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipment_tax_subtotal":{"description":"Tax on shipping. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"shipping_address_id":{"type":["string","null"]},"tax_subtotal":{"description":"Tax. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"total":{"description":"Invoice total. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"}},"required":["id","order_id","total"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create an invoice for a sales order","tags":["Invoices"],"x-yoprint-docs":{"errors":[{"fix":"Read `error.message`; fix the named line by its `bid`.","status":422,"when":"A Shopify or auto-invoiced order, or an invalid line or tax selection."}],"group":"Invoices and payments","permission":"Any member of the team.","related":["v2_public_invoice_item_bulk","v2_public_invoice_tax_selection_update","v2_public_invoice_show","v2_public_order_single_action"],"rules":["Refused for Shopify orders: \"Cannot create invoice for a Shopify-synced order.\"","Refused when the order keeps its invoice up to date automatically: \"You cannot create an invoice for an auto managed order.\" Turn that off with the `configure_order_auto_invoice_managed` action first.","When `tax_selection` is sent it must contain both `expected_tax` and `desired_tax` (either may be null)."],"side_effects":["Creates the invoice and its lines and refreshes the order for people who have it open in the web app; on a published sales order, Customer Portal pages the customer has open refresh too. Nothing is emailed.","With `item_actions`, recalculates the order's invoiced totals and spreads its payments across the invoices again (money of a payment frozen by an open dispute or review stays where it is)."]}}},"/v2/api/store/{team_slug}/v2/sales_order/{unique_key}/shipment":{"get":{"description":"Returns the shipments of an order with their lines, estimates and packages. `{unique_key}` is the order's `id` (for example `V4keXwwxMQyXw7`). The `ord_` unique key does not work here: it gives an empty list with status 200, not an error, so an empty list does not prove the order has none. An unknown id returns an empty list.","operationId":"v2_public_sales_order_shipment_index_for_order","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The sales order's or quote's `id` (a hash id). The `ord_` unique key and the order number do not work here.","example":"V4keXwwxMQyXw7","in":"path","name":"unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"billable_fee_total":{"dp":0,"value":0},"cost_total":{"dp":0,"value":0},"delivery_notes":"Leave at reception.","id":"qAKg4jO63uFqjs","order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","ready_to_ship":false,"scoped_id":"SHIP-1001","shipping_address_id":"RNG2OuYC20YzXs","status":{"color":"#9e9e9e","customer_label":"Pending","id":"43J0pEwV4RKUdO","label":"To pack","position":1,"role":"shipment","trashed":false,"type":"start"},"status_id":"43J0pEwV4RKUdO"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A shipment.","properties":{"billable_fee_total":{"description":"Shipping charged to the customer. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"cost_total":{"description":"Shipping cost. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"customer_due_date":{"description":"The order's in-hands date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_id":{"type":["string","null"]},"delivery_notes":{"type":["string","null"]},"id":{"example":"qAKg4jO63uFqjs","type":"string"},"internal_notes":{"type":["string","null"]},"is_external":{"type":"boolean"},"is_valid":{"type":"boolean"},"items":{"description":"Shipment lines (list only).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"ready_to_ship":{"type":"boolean"},"receiver_contact_id":{"type":["string","null"]},"scoped_id":{"description":"The shipment number.","example":"SHIP-1001","type":"string"},"shipment_estimates":{"description":"Shipping estimates (list only).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"shipment_packages":{"description":"Packages (list only).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"shipping_address_id":{"type":["string","null"]},"shipping_type_id":{"type":["string","null"]},"status":{"additionalProperties":true,"description":"A status, as the status operations return it.","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_id":{"example":"lziIhzgc0acXFc","type":"string"}},"required":["id","order_id","status_id"],"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the shipments of a sales order","tags":["Shipments"],"x-yoprint-docs":{"group":"Shipping","permission":"Any member of the team.","related":["v2_public_sales_order_shipment_create","v2_public_shipment_show"]}},"post":{"description":"Creates an empty shipment for an order: one address, one shipping type. Add its lines with the shipment line operations afterwards.\n\nThe shipment takes the team's next shipment number, the starting shipment status, the customer's primary brand profile, and the team's default shipping type unless you send one.\n\n**Safe retries:** send your own `operation_key`. Sending the same key with the same fields again returns the shipment already created instead of a second one.\n\nThe answer is the shipment. `{unique_key}` is the order's `id` (for example `V4keXwwxMQyXw7`) or its `unique_key` (`ord_…`).","operationId":"v2_public_sales_order_shipment_create","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"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","in":"path","name":"unique_key","required":true,"schema":{"example":"V4keXwwxMQyXw7","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"delivery_notes":"Leave at reception.","operation_key":"ship-1001-a","shipping_address_id":"RNG2OuYC20YzXs"},"schema":{"properties":{"customer_id":{"description":"Accepted but ignored: the shipment always belongs to the order's customer.","type":"string"},"customer_profile_id":{"description":"Accepted but ignored: the shipment takes the customer's primary brand profile.","type":["string","null"]},"delivery_notes":{"type":"string"},"internal_notes":{"type":"string"},"operation_key":{"description":"Your idempotency key for this create, up to 100 characters.","maxLength":100,"type":["string","null"]},"receiver_contact_id":{"description":"The contact who receives it.","type":["string","null"]},"scoped_id":{"description":"Your own shipment number, without the `SHIP-` the answer puts in front of it. Leave it out for the team's next number.","type":"string"},"shipping_address_id":{"description":"The address to ship to.","type":"string"},"shipping_type_id":{"description":"A shipping type id. Leave it out for the team's default.","type":["string","null"]}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"billable_fee_total":{"dp":0,"value":0},"cost_total":{"dp":0,"value":0},"delivery_notes":"Leave at reception.","id":"qAKg4jO63uFqjs","is_external":null,"order_id":"V4keXwwxMQyXw7","order_scoped_id":"SO1001","ready_to_ship":false,"scoped_id":"SHIP-1001","shipping_address_id":"RNG2OuYC20YzXs","status":{"color":"#9e9e9e","customer_label":"Pending","id":"43J0pEwV4RKUdO","label":"To pack","position":1,"role":"shipment","trashed":false,"type":"start"},"status_id":"43J0pEwV4RKUdO"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A shipment.","properties":{"billable_fee_total":{"description":"Shipping charged to the customer. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"cost_total":{"description":"Shipping cost. A decimal pair: the amount is `value` ÷ 10^`dp` (`{ \"value\": 125000, \"dp\": 4 }` is 12.50). Kept with 4 decimal places; an amount never set can come as `{ \"value\": 0, \"dp\": 0 }`. Read `dp` every time: it can differ between fields and records.","example":{"dp":4,"value":125000},"properties":{"dp":{"description":"How many of those digits are after the decimal point.","type":"integer"},"value":{"description":"The digits without the decimal point. A string only with `X-Yoprint-Decimal-Format: exact-v1`, when too large for a JSON number.","type":["integer","string","null"]}},"required":["value","dp"],"type":"object"},"customer_due_date":{"description":"The order's in-hands date. ISO 8601 with offset, or null.","format":"date-time","type":["string","null"]},"customer_id":{"type":["string","null"]},"delivery_notes":{"type":["string","null"]},"id":{"example":"qAKg4jO63uFqjs","type":"string"},"internal_notes":{"type":["string","null"]},"is_external":{"description":"`null` in this answer for a new shipment; read the shipment back (Get a shipment) for the stored value, `false` unless it was synced from an integration. A repeated create with the same `operation_key` answers the stored shipment, with `false`.","type":["boolean","null"]},"is_valid":{"type":"boolean"},"items":{"description":"Shipment lines (list only).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_id":{"example":"V4keXwwxMQyXw7","type":"string"},"order_scoped_id":{"example":"SO1001","type":"string"},"ready_to_ship":{"type":"boolean"},"receiver_contact_id":{"type":["string","null"]},"scoped_id":{"description":"The shipment number.","example":"SHIP-1001","type":"string"},"shipment_estimates":{"description":"Shipping estimates (list only).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"shipment_packages":{"description":"Packages (list only).","items":{"additionalProperties":true,"type":"object"},"type":"array"},"shipping_address_id":{"type":["string","null"]},"shipping_type_id":{"type":["string","null"]},"status":{"additionalProperties":true,"description":"A status, as the status operations return it.","properties":{"color":{"description":"A hex color, such as `#2196f3`.","type":"string"},"customer_label":{"description":"What customers see in the customer portal. When none is set: `Pending` for `start`, `In Progress` for `in_progress` and `pre_production`, `Completed` for `end`.","type":"string"},"id":{"example":"52CuV8sWcDZLPm","type":"string"},"label":{"description":"The status name people see.","type":"string"},"pipeline_id":{"description":"The task preset, for `pipeline` statuses only; absent for other roles.","type":"string"},"position":{"description":"Sort order within its list, lowest first.","type":"integer"},"role":{"description":"Which list the status belongs to: `order`, `quote`, `job`, `shipment`, `purchase_order`, `pipeline` or `customer_message`.","type":"string"},"trashed":{"description":"true for a deleted status.","type":"boolean"},"type":{"description":"`start` is the first status of its list and `end` the last; `pre_production` and `in_progress` are the ones in between.","enum":["start","pre_production","in_progress","end"],"type":"string"}},"required":["id","role","type","label","customer_label","color","position","trashed"],"type":["object","null"]},"status_id":{"example":"lziIhzgc0acXFc","type":"string"}},"required":["id","order_id","status_id"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Create a shipment for a sales order","tags":["Shipments"],"x-yoprint-docs":{"errors":[{"fix":"Set the order's customer first, or check the ids.","status":422,"when":"No customer on a published order (\"Select a customer before creating a shipment.\"), or a bad id."},{"fix":"Resend the first request unchanged, or use a new key.","status":422,"when":"The `operation_key` was used before with other fields (`shipment_create_operation_payload_conflict`), or its shipment was deleted (`shipment_create_operation_removed`)."}],"group":"Shipping","permission":"Any member of the team.","related":["v2_public_shipment_item_bulk","v2_public_shipment_update","v2_public_sales_order_shipment_change_status"],"rules":["A published order needs a customer first: \"Select a customer before creating a shipment.\"","The same `operation_key` with different fields is refused with 422 `shipment_create_operation_payload_conflict`. Reusing the key of a shipment that was deleted since is refused with 422 `shipment_create_operation_removed`.","Refused when the Shopify order was deleted in Shopify."],"side_effects":["Refreshes the order for people who have it open in the web app; on a published order, Customer Portal pages the customer has open refresh too."]}}},"/v2/api/store/{team_slug}/v2/shipment/item/{unique_key}":{"delete":{"description":"Removes one line from a shipment and recalculates it. Returns the action envelope (`DELETED`; `NONE` if it was already removed). Labels and packages are not touched.","operationId":"v2_public_shipment_item_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment line's `id` (a hash id), as its answers show it. Its unique key (`shpitm_...`) also works, but API answers don't include it.","example":"u8mEG7LHUtS55s","in":"path","name":"unique_key","required":true,"schema":{"example":"u8mEG7LHUtS55s","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"action_performed":"DELETED","has_changes":true,"item":{"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"u8mEG7LHUtS55s","is_external":false,"lock_version":1730000000000000,"position":100,"pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"total":{"dp":0,"value":0},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"shipment_id":"MQyJUnd3oty75h","type":"order_item","weight":{"type":"use_system"}},"lock_version":{"order":{"invoice_lock_version":1730000000000000,"job_lock_version":1730000000000000,"order_item_lock_version":1730000000000000,"order_lock_version":1730000000000000,"payment_lock_version":1730000000000000,"shipment_lock_version":1730000000000000},"shipment":{"shipment_item_lock_version":1730000000000000,"shipment_lock_version":1730000000000000}},"object_type":"shipment_item"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"What happened, and the line.","properties":{"action_performed":{"description":"`NONE` when nothing changed.","enum":["CREATED","UPDATED","DELETED","NONE"],"type":"string"},"has_changes":{"type":"boolean"},"item":{"additionalProperties":true,"description":"A shipment line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only details of the line.","type":"object"},"auto_invoice_managed":{"type":"boolean"},"billable_fee_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping cost lines only: what is billed (after override, markup or margin); `pricing.product_cost.total` is the cost. 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."},"external_ids":{"description":"Links to external systems; usually empty.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The shipment line.","example":"u8mEG7LHUtS55s","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Returned but not checked on shipment lines.","type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"For `system`, `_meta.unit_price` is the order line's unit price and `_meta.subtotal` is that price × this shipment line's quantity (`_meta.total` is always 0); for `shipment_cost`, `product_cost` has `override` (always true for lines saved through the API), `total` (the cost), `pricing_mode` and `pricing_mode_total` (decimal pairs at 6 decimal places).","properties":{"type":{"enum":["system","shipment_cost"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details; for `order_item`, `parent` describes the order line.","type":"object"},"properties":{"additionalProperties":true,"description":"For `order_item`, `id` is the order line; for `shipment_cost`, `name`, `description`, `shipment_package_id`, `shipment_estimate_id`.","type":"object"},"type":{"enum":["order_item","shipment_cost"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"type":{"description":"Same as `product.type`.","type":"string"},"weight":{"additionalProperties":true,"description":"The order line's weight (`_meta.total`, `_meta.unit`).","type":"object"}},"type":"object"},"lock_version":{"additionalProperties":true,"description":"Lock versions after the change.","properties":{"order":{"additionalProperties":true,"description":"The order's lock versions: `job_lock_version`, `invoice_lock_version`, `order_item_lock_version`, `shipment_lock_version`, `payment_lock_version`, `order_lock_version`.","type":"object"},"shipment":{"additionalProperties":true,"description":"The shipment's lock versions: `shipment_item_lock_version`, `shipment_lock_version`.","type":"object"}},"type":"object"},"object_type":{"const":"shipment_item","example":"shipment_item","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Remove a line from a shipment","tags":["Shipment line items"],"x-yoprint-docs":{"errors":[{"fix":"Handle it in Shopify, or publish the order.","status":422,"when":"A Shopify or draft rule (see rules)."},{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order."},{"fix":"Check the id.","status":404,"when":"The line isn't your team's."}],"group":"Shipping","permission":"Needs permission to edit the shipment's order: the team owner, a role whose Manage Sales Orders permission is \"update all\", or \"update assigned\" when you created the order or are assigned to it, or, on a draft order, its creator when their role can create sales orders. Otherwise 403 `user_is_not_authorized`. Reading needs only team membership.","related":["v2_public_shipment_item_index"],"rules":["A locked Shopify shipment (or one with a broken Shopify link): 422 `validation_error` \"Cannot delete Shopify-synced shipment item from API.\" A line fulfilled by a third party can't be removed either.","An externally synced shipment on a draft order: \"Publish this order before deleting an externally synced shipment item.\""],"side_effects":["Recalculates the shipment's cost and billable fee totals and the order's shipping totals.","Updates each order line's shipped status (not allocated, partly, fully or over-allocated).","On an Auto Invoice order, shipping cost lines are mirrored as shipping fees on the managed invoice.","Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open. No webhook or email is sent."]}},"get":{"description":"Returns one shipment line: `product` (for `order_item`, `_meta.parent` holds the order line), `pricing`, `quantity`, `weight`, `position` and `lock_version`.","operationId":"v2_public_shipment_item_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment line's `id` (a hash id), as its answers show it. Its unique key (`shpitm_...`) also works, but API answers don't include it.","example":"u8mEG7LHUtS55s","in":"path","name":"unique_key","required":true,"schema":{"example":"u8mEG7LHUtS55s","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"u8mEG7LHUtS55s","is_external":false,"lock_version":1730000000000000,"position":100,"pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"total":{"dp":0,"value":0},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"shipment_id":"MQyJUnd3oty75h","type":"order_item","weight":{"type":"use_system"}},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A shipment line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only details of the line.","type":"object"},"auto_invoice_managed":{"type":"boolean"},"billable_fee_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping cost lines only: what is billed (after override, markup or margin); `pricing.product_cost.total` is the cost. 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."},"external_ids":{"description":"Links to external systems; usually empty.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The shipment line.","example":"u8mEG7LHUtS55s","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Returned but not checked on shipment lines.","type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"For `system`, `_meta.unit_price` is the order line's unit price and `_meta.subtotal` is that price × this shipment line's quantity (`_meta.total` is always 0); for `shipment_cost`, `product_cost` has `override` (always true for lines saved through the API), `total` (the cost), `pricing_mode` and `pricing_mode_total` (decimal pairs at 6 decimal places).","properties":{"type":{"enum":["system","shipment_cost"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details; for `order_item`, `parent` describes the order line.","type":"object"},"properties":{"additionalProperties":true,"description":"For `order_item`, `id` is the order line; for `shipment_cost`, `name`, `description`, `shipment_package_id`, `shipment_estimate_id`.","type":"object"},"type":{"enum":["order_item","shipment_cost"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"type":{"description":"Same as `product.type`.","type":"string"},"weight":{"additionalProperties":true,"description":"The order line's weight (`_meta.total`, `_meta.unit`).","type":"object"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a shipment line","tags":["Shipment line items"],"x-yoprint-docs":{"errors":[{"fix":"Check the id.","status":404,"when":"The line isn't your team's."}],"group":"Shipping","permission":"Any member of the team.","related":["v2_public_shipment_item_update","v2_public_shipment_item_destroy"]}},"put":{"description":"Changes one shipment line and recalculates the shipment. Send only what you change; returns the action envelope (`UPDATED`, or `NONE` when nothing changed).\n\n- An `order_item` line can change its `quantity` and `position`, not the order line it points at.\n- A `shipment_cost` line can change `name`, `description`, `shipment_package_id`, `shipment_estimate_id` (null unlinks) and its `pricing`.\n\nNumbers are `{ value, dp }` pairs: `value` is the number without its decimal point and `dp` the count of decimal places, so 12.50 is `{ \"value\": 1250, \"dp\": 2 }` (or `{ \"value\": 125, \"dp\": 1 }`). `value` is a JSON integer or a digit string, never a float: `12.5` is refused. Quantities take up to 8 decimal places; shipping costs and a pricing mode's rate take 6. More significant decimals than that are a 422, not rounded. Send very large numbers as strings. Answers send prices at the stored scale (6 decimal places), quantities without trailing zeros, and `_meta.subtotal` (price × quantity) at the combined scale, compacted when it would exceed a safe integer: always read `dp`.","operationId":"v2_public_shipment_item_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment line's `id` (a hash id), as its answers show it. Its unique key (`shpitm_...`) also works, but API answers don't include it.","example":"u8mEG7LHUtS55s","in":"path","name":"unique_key","required":true,"schema":{"example":"u8mEG7LHUtS55s","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"cost":{"summary":"Change a shipping cost","value":{"pricing":{"product_cost":{"pricing_mode":"none","total":{"dp":2,"value":1500}},"type":"shipment_cost"}}},"quantity":{"summary":"Ship 12 instead","value":{"quantity":{"total":{"dp":0,"value":12},"type":"unit"}}}},"schema":{"properties":{"position":{"type":"integer"},"pricing":{"additionalProperties":true,"description":"Shipping cost lines: `{ type: shipment_cost, product_cost: { total, pricing_mode } }`. `type` is required whenever you send `pricing`.","required":["type"],"type":"object"},"product":{"properties":{"properties":{"additionalProperties":true,"type":"object"},"type":{"description":"Must be the line's current kind.","enum":["order_item","shipment_cost"],"type":"string"}},"required":["type"],"type":"object"},"quantity":{"properties":{"total":{"description":"The new quantity.","example":{"dp":0,"value":12},"properties":{"dp":{"description":"How many of its digits come after the decimal point, 0 to 30.","maximum":30,"minimum":0,"type":"integer"},"value":{"description":"The number without its decimal point, as a JSON integer or a string of digits (an optional leading `-`, no leading zeros, no decimal point).","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","description":"Required whenever you send `quantity`.","type":"string"}},"required":["type"],"type":"object"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"action_performed":"UPDATED","has_changes":true,"item":{"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"u8mEG7LHUtS55s","is_external":false,"lock_version":1730000000000000,"position":100,"pricing":{"_meta":{"subtotal":{"dp":0,"value":150},"total":{"dp":0,"value":0},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":12},"type":"unit"},"shipment_id":"MQyJUnd3oty75h","type":"order_item","weight":{"type":"use_system"}},"lock_version":{"order":{"invoice_lock_version":1730000000000000,"job_lock_version":1730000000000000,"order_item_lock_version":1730000000000000,"order_lock_version":1730000000000000,"payment_lock_version":1730000000000000,"shipment_lock_version":1730000000000000},"shipment":{"shipment_item_lock_version":1730000000000000,"shipment_lock_version":1730000000000000}},"object_type":"shipment_item"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"What happened, and the line.","properties":{"action_performed":{"description":"`NONE` when nothing changed.","enum":["CREATED","UPDATED","DELETED","NONE"],"type":"string"},"has_changes":{"type":"boolean"},"item":{"additionalProperties":true,"description":"A shipment line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only details of the line.","type":"object"},"auto_invoice_managed":{"type":"boolean"},"billable_fee_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping cost lines only: what is billed (after override, markup or margin); `pricing.product_cost.total` is the cost. 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."},"external_ids":{"description":"Links to external systems; usually empty.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The shipment line.","example":"u8mEG7LHUtS55s","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Returned but not checked on shipment lines.","type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"For `system`, `_meta.unit_price` is the order line's unit price and `_meta.subtotal` is that price × this shipment line's quantity (`_meta.total` is always 0); for `shipment_cost`, `product_cost` has `override` (always true for lines saved through the API), `total` (the cost), `pricing_mode` and `pricing_mode_total` (decimal pairs at 6 decimal places).","properties":{"type":{"enum":["system","shipment_cost"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details; for `order_item`, `parent` describes the order line.","type":"object"},"properties":{"additionalProperties":true,"description":"For `order_item`, `id` is the order line; for `shipment_cost`, `name`, `description`, `shipment_package_id`, `shipment_estimate_id`.","type":"object"},"type":{"enum":["order_item","shipment_cost"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"type":{"description":"Same as `product.type`.","type":"string"},"weight":{"additionalProperties":true,"description":"The order line's weight (`_meta.total`, `_meta.unit`).","type":"object"}},"type":"object"},"lock_version":{"additionalProperties":true,"description":"Lock versions after the change.","properties":{"order":{"additionalProperties":true,"description":"The order's lock versions: `job_lock_version`, `invoice_lock_version`, `order_item_lock_version`, `shipment_lock_version`, `payment_lock_version`, `order_lock_version`.","type":"object"},"shipment":{"additionalProperties":true,"description":"The shipment's lock versions: `shipment_item_lock_version`, `shipment_lock_version`.","type":"object"}},"type":"object"},"object_type":{"const":"shipment_item","example":"shipment_item","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a shipment line","tags":["Shipment line items"],"x-yoprint-docs":{"errors":[{"fix":"Read `error.message` and `error.fields`.","status":422,"when":"Validation or a business rule fails."},{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order."},{"fix":"Check the id.","status":404,"when":"The line isn't your team's."}],"group":"Shipping","notes":["`lock_version` is returned but not checked on shipment lines: the last write wins."],"permission":"Needs permission to edit the shipment's order: the team owner, a role whose Manage Sales Orders permission is \"update all\", or \"update assigned\" when you created the order or are assigned to it, or, on a draft order, its creator when their role can create sales orders. Otherwise 403 `user_is_not_authorized`. Reading needs only team membership.","related":["v2_public_shipment_item_show","v2_public_shipment_item_bulk"],"rules":["A line's kind can't change: 422 \"Cannot update the product type...\".","A locked Shopify shipment (or one with a broken Shopify link): 422 `validation_error` \"Cannot update Shopify-synced shipment item from API.\"","An externally synced line on a draft order: 422 `validation_error` \"Publish this order before updating an externally synced shipment item.\", with `error.context.reason` `parent_order_publish_required`.","`quantity.type` is required whenever you send `quantity`, and `pricing.type` whenever you send `pricing` (422 `validation_failed`)."],"side_effects":["Recalculates the shipment's cost and billable fee totals and the order's shipping totals.","Updates each order line's shipped status (not allocated, partly, fully or over-allocated).","On an Auto Invoice order, shipping cost lines are mirrored as shipping fees on the managed invoice.","Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open. No webhook or email is sent."]}}},"/v2/api/store/{team_slug}/v2/shipment/{hash_id}/estimates":{"get":{"description":"Returns every saved shipping estimate of a shipment, with its stored rates. Not paged. Doesn't call Shippo.","operationId":"v2_public_shipment_estimate_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"MQyJUnd3oty75h","in":"path","name":"hash_id","required":true,"schema":{"example":"MQyJUnd3oty75h","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"created_at":"2026-11-03T15:00:00+00:00","frontend_data":[],"frontend_data_version":null,"goshippo_selected_rate_id":"rate_0001","goshippo_shipment_id":"shipment_0001","id":"tVjoZLKlSwZFF5","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","shippo_address_from":{"city":"Austin","company":"","country":"US","email":"","name":"Northwind Apparel","phone":"+1 201 555 0123","state":"TX","street1":"100 Example Street","street2":"","zip":"78701"},"shippo_address_to":{"city":"Denver","company":"","country":"US","email":"alex@example.com","name":"Alex Rivera","phone":"","state":"CO","street1":"100 Example Street","street2":"","zip":"80202"},"shippo_carrier_accounts":[],"shippo_extra":null,"shippo_object_id":"shipment_0001","shippo_parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"shippo_rates":[{"amount":"12.40","amount_local":"12.40","arrives_by":null,"attributes":["CHEAPEST"],"carrier_account":"carrier_0001","currency":"USD","currency_local":"USD","duration_terms":"Delivery in 2 to 5 days.","estimated_days":3,"included_insurance_price":null,"messages":[],"object_created":"2026-11-03T15:00:00Z","object_id":"rate_0001","object_updated":"2026-11-03T15:00:00Z","provider":"USPS","provider_image_200":"https://example.com/usps_200.png","provider_image_75":"https://example.com/usps_75.png","servicelevel":{"extended_token":"usps_ground_advantage","name":"Ground Advantage","terms":"","token":"usps_ground_advantage"},"shipment":"shipment_0001"}],"shippo_shipment_date":"2026-11-03T15:00:00Z","shippo_status":"SUCCESS","type":"integration_shippo"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A saved shipping estimate.","properties":{"created_at":{"format":"date-time","type":"string"},"frontend_data":{"description":"What you sent as `frontend_data`; an empty list `[]` when you sent none.","type":["object","array"]},"frontend_data_version":{"description":"What you sent, or null."},"goshippo_selected_rate_id":{"description":"The rate chosen when it was saved.","example":"rate_0001","type":["string","null"]},"goshippo_shipment_id":{"description":"The Shippo shipment.","example":"shipment_0001","type":["string","null"]},"id":{"description":"The estimate.","example":"tVjoZLKlSwZFF5","type":"string"},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":["string","null"]},"shippo_address_from":{"additionalProperties":true,"type":"object"},"shippo_address_to":{"additionalProperties":true,"type":"object"},"shippo_carrier_accounts":{"items":{"type":"string"},"type":"array"},"shippo_extra":{"description":"The label options, or null."},"shippo_object_id":{"type":["string","null"]},"shippo_parcels":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"shippo_rates":{"description":"Every rate of that Shippo shipment, as saved (`amount` is a decimal string).","items":{"additionalProperties":true,"description":"A rate, with exactly these keys. Keys Shippo leaves out come back as empty strings.","properties":{"amount":{"example":"12.40","type":"string"},"amount_local":{"example":"12.40","type":"string"},"arrives_by":{"example":null,"type":["string","null"]},"attributes":{"description":"Shippo's tags, for example `CHEAPEST`.","example":["CHEAPEST"],"items":{"type":"string"},"type":"array"},"carrier_account":{"example":"carrier_0001","type":"string"},"currency":{"example":"USD","type":"string"},"currency_local":{"example":"USD","type":"string"},"duration_terms":{"example":"Delivery in 2 to 5 days.","type":["string","null"]},"estimated_days":{"example":3,"type":["integer","null"]},"included_insurance_price":{"example":null,"type":["string","null"]},"messages":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"object_created":{"example":"2026-11-03T15:00:00Z","type":"string"},"object_id":{"description":"The rate id. Send it as `rate_id` to buy this label.","example":"rate_0001","type":"string"},"object_updated":{"example":"2026-11-03T15:00:00Z","type":"string"},"provider":{"example":"USPS","type":"string"},"provider_image_200":{"example":"https://example.com/usps_200.png","type":"string"},"provider_image_75":{"description":"A URL of the carrier logo.","example":"https://example.com/usps_75.png","type":"string"},"servicelevel":{"additionalProperties":false,"description":"Exactly these four keys; null when Shippo sends no service level.","properties":{"extended_token":{"example":"usps_ground_advantage","type":"string"},"name":{"example":"Ground Advantage","type":"string"},"terms":{"example":"","type":"string"},"token":{"example":"usps_ground_advantage","type":"string"}},"type":"object"},"shipment":{"description":"The Shippo shipment this rate belongs to.","example":"shipment_0001","type":"string"}},"type":"object"},"type":"array"},"shippo_shipment_date":{"type":["string","null"]},"shippo_status":{"example":"SUCCESS","type":["string","null"]},"type":{"example":"integration_shippo","type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the shipping estimates of a shipment","tags":["Shipping rates and estimates"],"x-yoprint-docs":{"group":"Shipping","notes":["An id that isn't one of your shipments returns an empty list, not a 404."],"permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_shipment_estimate_show","v2_public_shipment_estimate_create_goshippo"]}}},"/v2/api/store/{team_slug}/v2/shipment/{hash_id}/label/external":{"post":{"description":"Records on a shipment a label you bought outside YoPrint (for example on the carrier's site), so the shipment has its tracking number. Nothing is bought and Shippo isn't called.\n\nYoPrint stores the carrier and tracking number only: no cost, size, weight or label file. Returns the new package.","operationId":"v2_public_shipment_label_create_external","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"MQyJUnd3oty75h","in":"path","name":"hash_id","required":true,"schema":{"example":"MQyJUnd3oty75h","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"other":{"summary":"Another carrier","value":{"provider_name":"DHL","provider_service_code":"other","provider_tracking_number":"0000000000"}},"ups":{"summary":"A UPS label","value":{"provider_service_code":"ups","provider_tracking_number":"1Z0000000000000000"}}},"schema":{"properties":{"provider_name":{"description":"The carrier name. Required when `provider_service_code` is `other`.","example":"DHL","type":"string"},"provider_service_code":{"description":"The carrier. `ups` and `fedex` set the carrier name for you.","enum":["ups","fedex","other"],"type":"string"},"provider_tracking_number":{"description":"The tracking number. Not checked for duplicates.","example":"1Z0000000000000000","type":"string"}},"required":["provider_service_code","provider_tracking_number"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"charges":null,"created_at":"2026-11-03T15:00:00+00:00","height":null,"id":"Jol7U29J3CvdKC","is_master":true,"length":null,"order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","parent_id":null,"provider_name":"UPS","provider_service_code":"ups","provider_service_name":null,"provider_shipment_id":null,"provider_tracking_number":"1Z0000000000000000","shipment_has_third_party_fulfilled_items":false,"shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","status":"pending","type":"external_label","weight":null,"width":null},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A package.","properties":{"charges":{"description":"The label cost. For a multi-parcel label every package repeats the rate's full amount: read the master's value and don't add packages up. Null for external labels. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12400,"type":["integer","number","string","null"]},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"from_address":{"description":"The address record behind `from_address_id`, or null when it is not set."},"from_address_id":{"description":"Older packages only: the ship-from address record; null otherwise.","example":null,"type":["string","null"]},"goshippo":{"additionalProperties":true,"description":"Shippo labels only: the Shippo details (shipment, rate, carrier, addresses, parcels).","properties":{"address_from":{"description":"The ship-from address sent to Shippo."},"address_return":{"description":"The return address sent to Shippo."},"address_to":{"description":"The ship-to address sent to Shippo."},"carrier_id":{"description":"The Shippo carrier account.","type":["string","null"]},"parcel_id":{"description":"The Shippo parcel.","type":["string","null"]},"parcels":{"description":"The parcels of the Shippo shipment."},"provider":{"type":["string","null"]},"provider_image_200":{"type":["string","null"]},"provider_image_75":{"type":["string","null"]},"provider_tracking_number":{"type":["string","null"]},"rate_id":{"description":"The Shippo rate bought.","type":["string","null"]},"shipment_data":{"description":"The Shippo shipment the rate came from."},"shipment_id":{"description":"The Shippo shipment.","type":["string","null"]}},"type":"object"},"height":{"description":"Parcel size and weight as stored, in `length_unit` and `weight_unit`. Null for external labels.","type":["number","string","null"]},"id":{"description":"The package.","example":"o6foWpSAayc79D","type":"string"},"is_master":{"description":"The first package of a label (the others have `parent_id`).","type":"boolean"},"length":{"type":["number","string","null"]},"length_unit":{"description":"Shippo labels only, upper case.","example":"IN","type":["string","null"]},"order_external_ids":{"description":"The order's links to external systems.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_external_type":{"description":"`shopify` when the order came from Shopify.","type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"example":"sales_order","type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"parent_id":{"description":"The master package, for the other parcels of a multi-parcel label.","example":null,"type":["string","null"]},"pdf":{"description":"Not on external labels: the label file. `label` and `description` are fixed texts that always say 4 x 6, whatever your label size setting.","items":{"additionalProperties":true,"properties":{"description":{"example":"Postage label individually to be printed 4\" x 6\" label","type":"string"},"label":{"example":"Postage Label (4 in x 6 in label)","type":"string"},"url":{"description":"For a Shippo label, Shippo's signed link to the label file: don't publish it.","type":"string"}},"type":"object"},"type":"array"},"provider_name":{"description":"The carrier.","example":"USPS","type":["string","null"]},"provider_saturday_delivery":{"description":"Shippo labels only (absent on external labels); always false today.","type":"boolean"},"provider_service_code":{"description":"For external labels, `ups`, `fedex` or `other`. For Shippo labels it may be null: read the service from `provider_service_name`.","type":["string","null"]},"provider_service_name":{"example":"Ground Advantage","type":["string","null"]},"provider_shipment_id":{"description":"The Shippo transaction id (Shippo labels).","type":["string","null"]},"provider_tracking_number":{"example":"9400100000000000000000","type":["string","null"]},"shipment_external_type":{"description":"`shopify` when the shipment is linked to Shopify.","type":["string","null"]},"shipment_has_third_party_fulfilled_items":{"type":"boolean"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":"string"},"shipment_shopify_sync":{"description":"Shopify sync state of the shipment."},"status":{"enum":["pending","ready-to-ship","shipped","delivered"],"example":"pending","type":"string"},"to_address":{"description":"The address record behind `to_address_id`, or null when it is not set."},"to_address_id":{"description":"Older packages only: the ship-to address record; null otherwise.","example":null,"type":["string","null"]},"type":{"description":"`goshippo` a label bought through Shippo; `external_label` a label recorded from elsewhere.","enum":["goshippo","external_label","single_label"],"example":"goshippo","type":"string"},"weight":{"type":["number","string","null"]},"weight_unit":{"description":"Shippo labels only, upper case.","example":"LB","type":["string","null"]},"width":{"type":["number","string","null"]}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Record a label bought elsewhere","tags":["Shipping labels"],"x-yoprint-docs":{"errors":[{"fix":"Fix the named field or rule.","status":422,"when":"A missing tracking number, an unknown `provider_service_code`, `other` without `provider_name`, a quote, or a Shopify or carrier conflict."},{"fix":"Check the shipment id.","status":404,"when":"The shipment isn't your team's."}],"group":"Shipping","permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_shipment_package_index","v2_public_shipment_package_update"],"rules":["Only for sales orders: 422 \"External labels can't be attached to a quote. Convert it to a sales order first.\"","Unlike a Shippo label, the order doesn't have to be published.","On a shipment linked to Shopify: 422 `shopify_managed_shipment_locked`, `shopify_fulfilled_shipment_package_locked` (\"This shipment has already been fulfilled to Shopify. Void fulfillment first to edit packages or create labels.\") or `shopify_broken_link_shipment_locked`; 422 \"Shipment label cannot be created because shipment contains items fulfilled by a third-party.\"; and 422 when the carrier differs from the carrier of the shipment's other packages (Shopify needs one carrier per fulfillment)."],"side_effects":["Creates a package with status `pending`. For an order from Shopify with tracking sync on, sends the tracking to Shopify, which may email the customer.","Customer Portal pages the order's customer has open refresh."]}}},"/v2/api/store/{team_slug}/v2/shipment/{hash_id}/label/goshippo":{"post":{"description":"**This spends real money.** Each successful call buys a label from the carrier and Shippo charges your team's Shippo account. The API can't undo a purchase: deleting the package later only asks Shippo for a refund, which Shippo and the carrier may refuse, and a refused refund is not reported back. Anyone whose role can view the order can buy: edit rights are not needed.\n\nBuys the label for a rate from Get shipping rates and records it on a YoPrint shipment. Send the rate's `object_id` as `rate_id`: the addresses, parcels, service and options all come from the rate. The label file type is your Shippo integration's label size setting (4x6 PDF unless changed).\n\nTo bill the label's cost to the customer, send `create_shipping_cost_line_item: true`: after the purchase YoPrint adds one \"Shipping Cost\" line to the shipment, linked to the master package, for the label's cost (on an Auto Invoice order it then reaches the managed invoice as a shipping fee). Without it nothing is added, as before, and you can add the line yourself with Add a line to a shipment.\n\nReturns the new packages: one per parcel of the rate, the first one the master, each with its tracking number, cost (`charges`, in thousandths, repeated on every package of a multi-parcel label) and a `pdf` entry whose `url` is Shippo's signed link to the label file: don't publish it. Next to `data`, `shipping_cost_line_item` says what happened to the shipping cost line.\n\nBefore you call: the shipment must belong to a published sales order (not a quote), and you should have shown the rate and its price to whoever approves the spend.\n\n**Retries:** Never retry a label purchase automatically, whatever the error. Follow these steps instead:\n\n1. **Check if the label was already bought.** List the shipment's packages (`GET /v2/shipment/{shipment_id}/package`). If a package with that carrier and service is present, the label was bought. Do not retry.\n2. **Check your Shippo account.** If no package appears in YoPrint, a purchase might still have succeeded: when YoPrint buys a label in Shippo but encounters an error reading back or saving it, it returns HTTP 500 and queues a background refund request to Shippo. Check your Shippo dashboard to see whether a label or refund was created.\n3. **When to stop (do not reuse the rate).** Never repeat the purchase call with the same `rate_id`. YoPrint holds only a temporary 10-second lock on `rate_id`. Once cleared or expired, repeating the call sends a new purchase to Shippo, risking a duplicate charge (or 422 `label_error` for multi-parcel rates).\n4. **When to retry safely.** If both YoPrint and Shippo confirm no label was purchased, request fresh shipping rates (`POST /v2/shipment/{shipment_id}/goshippo-rates`), choose a rate, and buy using the newly issued `rate_id`.\n\nTo avoid buying twice: send one purchase per shipment at a time and wait for its answer, however long it takes (give the call a client timeout of at least 120 seconds: a single-parcel purchase can take up to about 42 seconds and a multi-parcel one about 90); never resend while it is pending; after any error or timeout, list the shipment's packages and check your Shippo account before anything else; and if you do buy again, get new rates first.\n\nBefore you buy:\n\n1. Build the rate request from the shipment, its Ship To and its brand profile or company location (see Get shipping rates), and check the rate's `address_from`, `address_to` and `parcels` match the shipment.\n2. Show the rate's carrier, service and `amount` to a person and get their approval. AI agents must always ask.\n3. Check the shipment has no package for this rate yet.\n4. Buy soon after rating. YoPrint doesn't record how long Shippo keeps a rate buyable; if the purchase is refused, rate again.\n\nMoney here: a rate's `amount` is a decimal string in `currency` (`\"12.40\"`); parse it as a decimal. After purchase, each package's `charges` is that amount cut to 3 decimal places, in thousandths, an older encoding (`12400` is 12.40; usually a whole number of thousandths; a finer value comes back as a fractional number, or as an exact decimal string with `X-Yoprint-Decimal-Format: exact-v1`). On a multi-parcel label, every package repeats the rate's full amount: read the master package's value and don't add the packages up. See [Money and quantities](/concepts/money-and-quantities/).\n\nThe order of calls:\n\n1. Optional: List Shippo carrier accounts, to limit rates to some of your accounts.\n2. Get shipping rates with the addresses and parcels. Note the top-level `object_id` (the Shippo shipment) and the chosen rate's `object_id` (`rates[].object_id`).\n3. Optional: Save a shipping estimate on the YoPrint shipment, to keep the quote.\n4. Buy a shipping label with the rate's `object_id` as `rate_id`. This is the only step that costs money.\n5. Print: Download labels as one PDF. Track: Get live tracking for a package.","operationId":"v2_public_shipment_label_create_goshippo","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"MQyJUnd3oty75h","in":"path","name":"hash_id","required":true,"schema":{"example":"MQyJUnd3oty75h","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"create_shipping_cost_line_item":true,"rate_id":"rate_0001"},"schema":{"properties":{"create_shipping_cost_line_item":{"default":false,"description":"true to add a \"Shipping Cost\" line for the label to the shipment after the purchase. Default false: nothing is added.","type":"boolean"},"rate_id":{"description":"The `rates[].object_id` to buy, from Get shipping rates (or an estimate's `goshippo_selected_rate_id`).","example":"rate_0001","type":"string"},"shipment_estimate_id":{"description":"Optional: the `id` of one of this shipment's shipping estimates, to link the shipping cost line to it. It must belong to this shipment, even when you don't ask for the line.","example":"EK98YtlL5ViAlx","type":["string","null"]}},"required":["rate_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"charges":12400,"created_at":"2026-11-03T15:00:00+00:00","goshippo":{"parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"provider":"USPS","rate_id":"rate_0001"},"height":"4","id":"o6foWpSAayc79D","is_master":true,"length":"12","length_unit":"IN","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","parent_id":null,"pdf":[{"description":"Postage label individually to be printed 4\" x 6\" label","label":"Postage Label (4 in x 6 in label)","url":"https://example.com/labels/o6foWpSAayc79D.pdf"}],"provider_name":"USPS","provider_saturday_delivery":false,"provider_service_code":null,"provider_service_name":"Ground Advantage","provider_shipment_id":"transaction_0001","provider_tracking_number":"9400100000000000000000","shipment_has_third_party_fulfilled_items":false,"shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","status":"pending","type":"goshippo","weight":"2","weight_unit":"LB","width":"10"}],"shipping_cost_line_item":{"shipment_item_id":"Tt8N6jGCrroTHW","status":"created"},"status":200,"success":true},"schema":{"properties":{"data":{"description":"One package per parcel of the rate: the master first, then the others (with `parent_id`).","items":{"additionalProperties":true,"description":"A package.","properties":{"charges":{"description":"The label cost. For a multi-parcel label every package repeats the rate's full amount: read the master's value and don't add packages up. Null for external labels. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12400,"type":["integer","number","string","null"]},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"from_address":{"description":"The address record behind `from_address_id`, or null when it is not set."},"from_address_id":{"description":"Older packages only: the ship-from address record; null otherwise.","example":null,"type":["string","null"]},"goshippo":{"additionalProperties":true,"description":"Shippo labels only: the Shippo details (shipment, rate, carrier, addresses, parcels).","properties":{"address_from":{"description":"The ship-from address sent to Shippo."},"address_return":{"description":"The return address sent to Shippo."},"address_to":{"description":"The ship-to address sent to Shippo."},"carrier_id":{"description":"The Shippo carrier account.","type":["string","null"]},"parcel_id":{"description":"The Shippo parcel.","type":["string","null"]},"parcels":{"description":"The parcels of the Shippo shipment."},"provider":{"type":["string","null"]},"provider_image_200":{"type":["string","null"]},"provider_image_75":{"type":["string","null"]},"provider_tracking_number":{"type":["string","null"]},"rate_id":{"description":"The Shippo rate bought.","type":["string","null"]},"shipment_data":{"description":"The Shippo shipment the rate came from."},"shipment_id":{"description":"The Shippo shipment.","type":["string","null"]}},"type":"object"},"height":{"description":"Parcel size and weight as stored, in `length_unit` and `weight_unit`. Null for external labels.","type":["number","string","null"]},"id":{"description":"The package.","example":"o6foWpSAayc79D","type":"string"},"is_master":{"description":"The first package of a label (the others have `parent_id`).","type":"boolean"},"length":{"type":["number","string","null"]},"length_unit":{"description":"Shippo labels only, upper case.","example":"IN","type":["string","null"]},"order_external_ids":{"description":"The order's links to external systems.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_external_type":{"description":"`shopify` when the order came from Shopify.","type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"example":"sales_order","type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"parent_id":{"description":"The master package, for the other parcels of a multi-parcel label.","example":null,"type":["string","null"]},"pdf":{"description":"Not on external labels: the label file. `label` and `description` are fixed texts that always say 4 x 6, whatever your label size setting.","items":{"additionalProperties":true,"properties":{"description":{"example":"Postage label individually to be printed 4\" x 6\" label","type":"string"},"label":{"example":"Postage Label (4 in x 6 in label)","type":"string"},"url":{"description":"For a Shippo label, Shippo's signed link to the label file: don't publish it.","type":"string"}},"type":"object"},"type":"array"},"provider_name":{"description":"The carrier.","example":"USPS","type":["string","null"]},"provider_saturday_delivery":{"description":"Shippo labels only (absent on external labels); always false today.","type":"boolean"},"provider_service_code":{"description":"For external labels, `ups`, `fedex` or `other`. For Shippo labels it may be null: read the service from `provider_service_name`.","type":["string","null"]},"provider_service_name":{"example":"Ground Advantage","type":["string","null"]},"provider_shipment_id":{"description":"The Shippo transaction id (Shippo labels).","type":["string","null"]},"provider_tracking_number":{"example":"9400100000000000000000","type":["string","null"]},"shipment_external_type":{"description":"`shopify` when the shipment is linked to Shopify.","type":["string","null"]},"shipment_has_third_party_fulfilled_items":{"type":"boolean"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":"string"},"shipment_shopify_sync":{"description":"Shopify sync state of the shipment."},"status":{"enum":["pending","ready-to-ship","shipped","delivered"],"example":"pending","type":"string"},"to_address":{"description":"The address record behind `to_address_id`, or null when it is not set."},"to_address_id":{"description":"Older packages only: the ship-to address record; null otherwise.","example":null,"type":["string","null"]},"type":{"description":"`goshippo` a label bought through Shippo; `external_label` a label recorded from elsewhere.","enum":["goshippo","external_label","single_label"],"example":"goshippo","type":"string"},"weight":{"type":["number","string","null"]},"weight_unit":{"description":"Shippo labels only, upper case.","example":"LB","type":["string","null"]},"width":{"type":["number","string","null"]}},"type":"object"},"type":"array"},"shipping_cost_line_item":{"description":"What happened to the shipping cost line. Always present.","properties":{"shipment_item_id":{"description":"The shipment line's `id` for `created` and `existing`; null otherwise.","type":["string","null"]},"status":{"description":"`not_requested` without `create_shipping_cost_line_item: true`; `created` or `existing` when the shipment has the line; `skipped_third_party_billing` when a third party pays for the label; `failed` when adding it failed (the label is still bought).","enum":["not_requested","created","existing","skipped_third_party_billing","failed"],"type":"string"}},"required":["status","shipment_item_id"],"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data","shipping_cost_line_item"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Buy a shipping label (charges your Shippo account)","tags":["Shipping labels"],"x-yoprint-docs":{"errors":[{"fix":"Send the rate's `object_id` as `rate_id`.","status":422,"when":"`rate_id` is missing, or `create_shipping_cost_line_item` isn't a boolean (`validation_failed`)."},{"fix":"Send an estimate `id` from List the shipping estimates of a shipment, or leave it out.","status":422,"when":"`shipment_estimate_id` isn't an estimate of this shipment (`validation_error`, \"The shipping estimate does not belong to this shipment.\"). Nothing was bought."},{"fix":"Check your Shippo account for a label from the earlier attempt before you buy another.","status":422,"when":"Shippo already used this rate (`label_error`: \"Shippo has already used this rate for an earlier label attempt, so it can't be bought again. Get rates again and choose a rate...\")."},{"fix":"Fix the cause, get rates again and buy the new rate.","status":422,"when":"Shippo answered the purchase with a status other than `SUCCESS` (`label_error`, with Shippo's message; `error` also carries Shippo's `object_id`, `status` and `messages`), for example an invalid address."},{"fix":"Resolve the named rule first.","status":422,"when":"A quote, an unpublished order, a Shopify or carrier conflict, or the FedEx parcel limit (see rules)."},{"fix":"Connect Shippo in the web app first.","status":422,"when":"Shippo isn't connected or is disabled (`goshippo_not_enabled`)."},{"fix":"Ask the team owner for permission to view this order, or to be assigned to it.","status":403,"when":"Your role can't view this order (`user_is_not_authorized`). It is checked before the quote, Shippo and publish checks, and nothing was bought."},{"fix":"Check the shipment id.","status":404,"when":"The shipment isn't your team's."},{"fix":"Don't retry. List the shipment's packages and check your Shippo account first.","status":500,"when":"Shippo failed or timed out mid-purchase, Shippo refused the purchase call itself (a 4xx other than an already used multi-parcel rate), or YoPrint couldn't read back or save a bought label (it then asks Shippo for a refund in the background). A label may or may not have been bought."},{"fix":"Wait, then list the shipment's packages: the first attempt may have bought the label.","status":422,"when":"Another purchase of the same `rate_id` started less than 10 seconds ago and hasn't succeeded: it is still running, or it failed (a failure keeps the lock until 10 seconds after that start). `error.code` is `validation_error` and the message is \"Locking Token has Been Called: \" followed by your request's `locking_token` field, if you sent one (nothing otherwise)."}],"group":"Shipping","notes":["Never retry a label purchase automatically, whatever the error. Follow these steps instead:\n\n1. **Check if the label was already bought.** List the shipment's packages (`GET /v2/shipment/{shipment_id}/package`). If a package with that carrier and service is present, the label was bought. Do not retry.\n2. **Check your Shippo account.** If no package appears in YoPrint, a purchase might still have succeeded: when YoPrint buys a label in Shippo but encounters an error reading back or saving it, it returns HTTP 500 and queues a background refund request to Shippo. Check your Shippo dashboard to see whether a label or refund was created.\n3. **When to stop (do not reuse the rate).** Never repeat the purchase call with the same `rate_id`. YoPrint holds only a temporary 10-second lock on `rate_id`. Once cleared or expired, repeating the call sends a new purchase to Shippo, risking a duplicate charge (or 422 `label_error` for multi-parcel rates).\n4. **When to retry safely.** If both YoPrint and Shippo confirm no label was purchased, request fresh shipping rates (`POST /v2/shipment/{shipment_id}/goshippo-rates`), choose a rate, and buy using the newly issued `rate_id`.","To avoid buying twice: send one purchase per shipment at a time and wait for its answer, however long it takes (give the call a client timeout of at least 120 seconds: a single-parcel purchase can take up to about 42 seconds and a multi-parcel one about 90); never resend while it is pending; after any error or timeout, list the shipment's packages and check your Shippo account before anything else; and if you do buy again, get new rates first.","You can't buy only some parcels of a multi-parcel rate.","Read `shipping_cost_line_item.status`: `created` (the line was added; `shipment_item_id` is its `id`), `existing` (the package already had one), `not_requested`, `skipped_third_party_billing`, or `failed`. After a lost answer, adding the line again with Add a line to a shipment and the same `shipment_package_id` returns the line if it already exists.","To void a label, delete its package: YoPrint then asks Shippo for a refund in the background. Whether you get the money back is up to Shippo and the carrier, and a refused refund is not reported back.","AI agents: always ask a person to confirm the rate and price before calling this."],"permission":"Needs permission to view the shipment's order: the team owner, a role whose Manage Sales Orders permission is \"view all\", or \"view assigned\" when you created the order or are assigned to it. Otherwise 403 `user_is_not_authorized`. Edit rights are not needed, so a role that can only view orders can do this too. Limit who holds API keys. Needs a connected, enabled Shippo integration (Settings > Integrations > Shippo Shipping). Without one the reply is 422 `goshippo_not_enabled` with no message.","related":["v2_public_shipment_rate_goshippo","v2_public_shipment_package_index","v2_public_shipment_label_compile_goshippo","v2_public_shipment_package_destroy","v2_public_shipment_item_create"],"rules":["Only for sales orders: a quote's shipment gets 422 \"Shipping labels can't be bought for a quote. Convert it to a sales order first.\"","The sales order must be published: otherwise 422 \"No Permission - you cannot purchase goShippo label in an unpublished order/quote\".","FedEx allows at most 12 parcels per shipment: 422 `goshippo_fedex_package_limit_exceeded`.","`shipment_estimate_id`, when sent, must be an estimate of this shipment: otherwise 422 `validation_error` \"The shipping estimate does not belong to this shipment.\", checked before anything is bought.","The shipping cost line (with `create_shipping_cost_line_item: true`) is added once per label: its cost is the master package's `charges` (quantity 1, pricing mode none), and a second request for the same package returns the line already there. It is left out when the rate bills a third party (Shippo `extra.billing.type` set to anything other than `SENDER`), so the customer isn't charged twice.","A rate is not guaranteed to be bought only once. YoPrint holds a 10-second lock per `rate_id` from the start of a purchase (cleared at once on success; after a failure it stays until 10 seconds after the start); a purchase can run longer than 10 seconds, because each of its Shippo calls may take up to 14. A repeat outside the lock goes to Shippo, which refuses a used multi-parcel rate (`label_error`); YoPrint has no record of what Shippo does with a reused single-parcel rate, so treat any repeat as a possible second charge.","On a shipment linked to Shopify: 422 `shopify_managed_shipment_locked`, `shopify_fulfilled_shipment_package_locked` (\"This shipment has already been fulfilled to Shopify. Void fulfillment first to edit packages or create labels.\") or `shopify_broken_link_shipment_locked`; 422 \"Shipment label cannot be created because shipment contains items fulfilled by a third-party.\"; and 422 when the carrier differs from the carrier of the shipment's other packages (Shopify needs one carrier per fulfillment)."],"side_effects":["SPENDS REAL MONEY: buys the label from Shippo, charged to your team's Shippo account. It can't be undone through the API.","If YoPrint buys the label in Shippo but fails while reading back or saving it, the request returns HTTP 500 and YoPrint queues a background refund request to Shippo for that label (the refund's outcome is not reported).","Creates one package per parcel on the shipment, with tracking number, carrier, service and cost.","With `create_shipping_cost_line_item: true`: adds the shipping cost line after packages are saved. Partial success: if saving the shipping cost line fails, the label and packages are still preserved and the call returns HTTP 200. Check `shipping_cost_line_item.status`: if `failed`, add the shipping cost line manually.","For an order from Shopify with tracking sync on, sends the tracking to Shopify, which may email the customer.","YoPrint itself sends no email. Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open."]}}},"/v2/api/store/{team_slug}/v2/shipment/{hash_id}/packages":{"get":{"description":"Returns every package of a shipment: Shippo labels, labels recorded from elsewhere, and single labels. Each has its carrier, service, tracking number, size, weight, `charges` (in thousandths: 12.40 is 12400; on a multi-parcel label every package repeats the full amount, so read the master's), `status` and, for Shippo, the label file. Not paged.\n\nThe path takes the shipment's hash id; unique keys don't work here. A value that isn't a hash id gives 404, but a hash id that isn't one of your shipments answers 200 with an empty list.","operationId":"v2_public_shipment_package_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"MQyJUnd3oty75h","in":"path","name":"hash_id","required":true,"schema":{"example":"MQyJUnd3oty75h","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"charges":12400,"created_at":"2026-11-03T15:00:00+00:00","goshippo":{"parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"provider":"USPS","rate_id":"rate_0001"},"height":"4","id":"o6foWpSAayc79D","is_master":true,"length":"12","length_unit":"IN","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","parent_id":null,"pdf":[{"description":"Postage label individually to be printed 4\" x 6\" label","label":"Postage Label (4 in x 6 in label)","url":"https://example.com/labels/o6foWpSAayc79D.pdf"}],"provider_name":"USPS","provider_saturday_delivery":false,"provider_service_code":null,"provider_service_name":"Ground Advantage","provider_shipment_id":"transaction_0001","provider_tracking_number":"9400100000000000000000","shipment_has_third_party_fulfilled_items":false,"shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","status":"pending","type":"goshippo","weight":"2","weight_unit":"LB","width":"10"}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A package.","properties":{"charges":{"description":"The label cost. For a multi-parcel label every package repeats the rate's full amount: read the master's value and don't add packages up. Null for external labels. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12400,"type":["integer","number","string","null"]},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"from_address":{"description":"The address record behind `from_address_id`, or null when it is not set."},"from_address_id":{"description":"Older packages only: the ship-from address record; null otherwise.","example":null,"type":["string","null"]},"goshippo":{"additionalProperties":true,"description":"Shippo labels only: the Shippo details (shipment, rate, carrier, addresses, parcels).","properties":{"address_from":{"description":"The ship-from address sent to Shippo."},"address_return":{"description":"The return address sent to Shippo."},"address_to":{"description":"The ship-to address sent to Shippo."},"carrier_id":{"description":"The Shippo carrier account.","type":["string","null"]},"parcel_id":{"description":"The Shippo parcel.","type":["string","null"]},"parcels":{"description":"The parcels of the Shippo shipment."},"provider":{"type":["string","null"]},"provider_image_200":{"type":["string","null"]},"provider_image_75":{"type":["string","null"]},"provider_tracking_number":{"type":["string","null"]},"rate_id":{"description":"The Shippo rate bought.","type":["string","null"]},"shipment_data":{"description":"The Shippo shipment the rate came from."},"shipment_id":{"description":"The Shippo shipment.","type":["string","null"]}},"type":"object"},"height":{"description":"Parcel size and weight as stored, in `length_unit` and `weight_unit`. Null for external labels.","type":["number","string","null"]},"id":{"description":"The package.","example":"o6foWpSAayc79D","type":"string"},"is_master":{"description":"The first package of a label (the others have `parent_id`).","type":"boolean"},"length":{"type":["number","string","null"]},"length_unit":{"description":"Shippo labels only, upper case.","example":"IN","type":["string","null"]},"order_external_ids":{"description":"The order's links to external systems.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_external_type":{"description":"`shopify` when the order came from Shopify.","type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"example":"sales_order","type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"parent_id":{"description":"The master package, for the other parcels of a multi-parcel label.","example":null,"type":["string","null"]},"pdf":{"description":"Not on external labels: the label file. `label` and `description` are fixed texts that always say 4 x 6, whatever your label size setting.","items":{"additionalProperties":true,"properties":{"description":{"example":"Postage label individually to be printed 4\" x 6\" label","type":"string"},"label":{"example":"Postage Label (4 in x 6 in label)","type":"string"},"url":{"description":"For a Shippo label, Shippo's signed link to the label file: don't publish it.","type":"string"}},"type":"object"},"type":"array"},"provider_name":{"description":"The carrier.","example":"USPS","type":["string","null"]},"provider_saturday_delivery":{"description":"Shippo labels only (absent on external labels); always false today.","type":"boolean"},"provider_service_code":{"description":"For external labels, `ups`, `fedex` or `other`. For Shippo labels it may be null: read the service from `provider_service_name`.","type":["string","null"]},"provider_service_name":{"example":"Ground Advantage","type":["string","null"]},"provider_shipment_id":{"description":"The Shippo transaction id (Shippo labels).","type":["string","null"]},"provider_tracking_number":{"example":"9400100000000000000000","type":["string","null"]},"shipment_external_type":{"description":"`shopify` when the shipment is linked to Shopify.","type":["string","null"]},"shipment_has_third_party_fulfilled_items":{"type":"boolean"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":"string"},"shipment_shopify_sync":{"description":"Shopify sync state of the shipment."},"status":{"enum":["pending","ready-to-ship","shipped","delivered"],"example":"pending","type":"string"},"to_address":{"description":"The address record behind `to_address_id`, or null when it is not set."},"to_address_id":{"description":"Older packages only: the ship-to address record; null otherwise.","example":null,"type":["string","null"]},"type":{"description":"`goshippo` a label bought through Shippo; `external_label` a label recorded from elsewhere.","enum":["goshippo","external_label","single_label"],"example":"goshippo","type":"string"},"weight":{"type":["number","string","null"]},"weight_unit":{"description":"Shippo labels only, upper case.","example":"LB","type":["string","null"]},"width":{"type":["number","string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the packages of a shipment","tags":["Shipment packages"],"x-yoprint-docs":{"errors":[{"fix":"Use the shipment's `id`, and treat an empty list as \"check the id\".","status":404,"when":"The value isn't a hash id (a unique key or a document number, for example). A hash id that isn't one of your shipments answers 200 with `[]` instead."}],"group":"Shipping","notes":["A Shippo label's `pdf` URL is Shippo's signed link to the file: don't publish it."],"permission":"Any member of the team.","related":["v2_public_shipment_package_show","v2_public_shipment_label_create_goshippo","v2_public_shipment_label_compile_goshippo"]}}},"/v2/api/store/{team_slug}/v2/shipment/{hash_id}/shipment_estimate/goshippo":{"post":{"description":"Saves a Shippo rate quote on a YoPrint shipment, as a shipping estimate. Nothing is bought.\n\nGet rates first, then send the reply's top-level `object_id` as `goshippo_shipment_id`, and the rate you picked as `goshippo_selected_rate_id`. YoPrint reads that Shippo shipment back and stores it with all its rates. Returns the estimate (`shippo_rates`, `shippo_address_from`, `shippo_parcels`, ...).\n\nAn estimate is a quote you can show or bill for. Buying the label is a separate call that takes a rate id; you can pass the estimate's `id` there as `shipment_estimate_id`, only to link the label's shipping cost line to it.","operationId":"v2_public_shipment_estimate_create_goshippo","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's hash id (`id`). Hash ids only: a unique key or a document number gives 404.","example":"MQyJUnd3oty75h","in":"path","name":"hash_id","required":true,"schema":{"example":"MQyJUnd3oty75h","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"goshippo_selected_rate_id":"rate_0001","goshippo_shipment_id":"shipment_0001"},"schema":{"properties":{"frontend_data":{"additionalProperties":true,"description":"Your own data to keep with the estimate (the web app stores its form here).","type":"object"},"frontend_data_version":{"description":"Required with `frontend_data`: your format version for it.","example":1},"goshippo_selected_rate_id":{"description":"The `rates[].object_id` you chose. Not checked against the shipment.","example":"rate_0001","type":"string"},"goshippo_shipment_id":{"description":"The top-level `object_id` from Get shipping rates.","example":"shipment_0001","type":"string"}},"required":["goshippo_shipment_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-03T15:00:00+00:00","frontend_data":[],"frontend_data_version":null,"goshippo_selected_rate_id":"rate_0001","goshippo_shipment_id":"shipment_0001","id":"tVjoZLKlSwZFF5","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","shippo_address_from":{"city":"Austin","company":"","country":"US","email":"","name":"Northwind Apparel","phone":"+1 201 555 0123","state":"TX","street1":"100 Example Street","street2":"","zip":"78701"},"shippo_address_to":{"city":"Denver","company":"","country":"US","email":"alex@example.com","name":"Alex Rivera","phone":"","state":"CO","street1":"100 Example Street","street2":"","zip":"80202"},"shippo_carrier_accounts":[],"shippo_extra":null,"shippo_object_id":"shipment_0001","shippo_parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"shippo_rates":[{"amount":"12.40","amount_local":"12.40","arrives_by":null,"attributes":["CHEAPEST"],"carrier_account":"carrier_0001","currency":"USD","currency_local":"USD","duration_terms":"Delivery in 2 to 5 days.","estimated_days":3,"included_insurance_price":null,"messages":[],"object_created":"2026-11-03T15:00:00Z","object_id":"rate_0001","object_updated":"2026-11-03T15:00:00Z","provider":"USPS","provider_image_200":"https://example.com/usps_200.png","provider_image_75":"https://example.com/usps_75.png","servicelevel":{"extended_token":"usps_ground_advantage","name":"Ground Advantage","terms":"","token":"usps_ground_advantage"},"shipment":"shipment_0001"}],"shippo_shipment_date":"2026-11-03T15:00:00Z","shippo_status":"SUCCESS","type":"integration_shippo"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A saved shipping estimate.","properties":{"created_at":{"format":"date-time","type":"string"},"frontend_data":{"description":"What you sent as `frontend_data`; an empty list `[]` when you sent none.","type":["object","array"]},"frontend_data_version":{"description":"What you sent, or null."},"goshippo_selected_rate_id":{"description":"The rate chosen when it was saved.","example":"rate_0001","type":["string","null"]},"goshippo_shipment_id":{"description":"The Shippo shipment.","example":"shipment_0001","type":["string","null"]},"id":{"description":"The estimate.","example":"tVjoZLKlSwZFF5","type":"string"},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":["string","null"]},"shippo_address_from":{"additionalProperties":true,"type":"object"},"shippo_address_to":{"additionalProperties":true,"type":"object"},"shippo_carrier_accounts":{"items":{"type":"string"},"type":"array"},"shippo_extra":{"description":"The label options, or null."},"shippo_object_id":{"type":["string","null"]},"shippo_parcels":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"shippo_rates":{"description":"Every rate of that Shippo shipment, as saved (`amount` is a decimal string).","items":{"additionalProperties":true,"description":"A rate, with exactly these keys. Keys Shippo leaves out come back as empty strings.","properties":{"amount":{"example":"12.40","type":"string"},"amount_local":{"example":"12.40","type":"string"},"arrives_by":{"example":null,"type":["string","null"]},"attributes":{"description":"Shippo's tags, for example `CHEAPEST`.","example":["CHEAPEST"],"items":{"type":"string"},"type":"array"},"carrier_account":{"example":"carrier_0001","type":"string"},"currency":{"example":"USD","type":"string"},"currency_local":{"example":"USD","type":"string"},"duration_terms":{"example":"Delivery in 2 to 5 days.","type":["string","null"]},"estimated_days":{"example":3,"type":["integer","null"]},"included_insurance_price":{"example":null,"type":["string","null"]},"messages":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"object_created":{"example":"2026-11-03T15:00:00Z","type":"string"},"object_id":{"description":"The rate id. Send it as `rate_id` to buy this label.","example":"rate_0001","type":"string"},"object_updated":{"example":"2026-11-03T15:00:00Z","type":"string"},"provider":{"example":"USPS","type":"string"},"provider_image_200":{"example":"https://example.com/usps_200.png","type":"string"},"provider_image_75":{"description":"A URL of the carrier logo.","example":"https://example.com/usps_75.png","type":"string"},"servicelevel":{"additionalProperties":false,"description":"Exactly these four keys; null when Shippo sends no service level.","properties":{"extended_token":{"example":"usps_ground_advantage","type":"string"},"name":{"example":"Ground Advantage","type":"string"},"terms":{"example":"","type":"string"},"token":{"example":"usps_ground_advantage","type":"string"}},"type":"object"},"shipment":{"description":"The Shippo shipment this rate belongs to.","example":"shipment_0001","type":"string"}},"type":"object"},"type":"array"},"shippo_shipment_date":{"type":["string","null"]},"shippo_status":{"example":"SUCCESS","type":["string","null"]},"type":{"example":"integration_shippo","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Save a shipping estimate","tags":["Shipping rates and estimates"],"x-yoprint-docs":{"errors":[{"fix":"Get rates again and send the new `object_id`.","status":422,"when":"Shippo rejected the shipment id (Shippo answered 400): `validation_error`, \"The shipping rate could not be loaded. Get shipping rates again and choose a rate before saving.\" Other Shippo failures, possibly including an unknown id, are a 500."},{"fix":"Send the required fields.","status":422,"when":"`goshippo_shipment_id` is missing, or `frontend_data` is sent without `frontend_data_version`."},{"fix":"Connect Shippo in the web app first.","status":422,"when":"Shippo isn't connected or is disabled (`goshippo_not_enabled`)."},{"fix":"Check the shipment id.","status":404,"when":"The shipment isn't your team's."},{"fix":"Check the addresses, parcels and ids, then retry once. Do not loop.","status":500,"when":"Shippo refused the request or could not be reached. Shippo errors are not translated into 4xx replies."}],"group":"Shipping","permission":"Any member of the team. No sales order permission is checked. Needs a connected, enabled Shippo integration (Settings > Integrations > Shippo Shipping). Without one the reply is 422 `goshippo_not_enabled` with no message.","related":["v2_public_shipment_rate_goshippo","v2_public_shipment_estimate_index","v2_public_shipment_label_create_goshippo"],"rules":["Works on shipments of quotes and sales orders, in any status.","Each call adds a new estimate; sending the same ids twice saves two."],"side_effects":["Reads the Shippo shipment (it buys nothing) and saves an estimate. Open Admin Portal pages refresh."]}}},"/v2/api/store/{team_slug}/v2/shipment/{unique_key}":{"delete":{"description":"Deletes a shipment with its lines, packages and shipping estimates. It can't be undone.\n\nEvery Shippo label on it is voided: YoPrint asks Shippo for a refund in the background (refusals are not reported back). For a Shopify shipment, its Shopify fulfillment is cancelled first, while you wait.\n\nDeleting a shipment that is already deleted succeeds and changes nothing.","operationId":"v2_public_shipment_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's `id` (a hash id), as its answers show it. Its unique key (`shp_...`) also works, but API answers don't include it.","example":"MQyJUnd3oty75h","in":"path","name":"unique_key","required":true,"schema":{"example":"MQyJUnd3oty75h","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a shipment","tags":["Shipments"],"x-yoprint-docs":{"errors":[{"fix":"Publish the order, or handle the shipment in Shopify.","status":422,"when":"A draft order with labels or external links, a third-party fulfilled item, a Shopify lock (`shopify_managed_shipment_locked`, `shopify_broken_link_shipment_locked`) or an order deleted in Shopify (`shopify_order_deleted_externally`)."},{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order (`user_is_not_authorized`). Nothing is deleted."},{"fix":"Check the id.","status":404,"when":"The shipment isn't your team's."}],"group":"Shipping","permission":"Needs permission to edit the shipment's order: the team owner, a role whose Manage Sales Orders permission is \"update all\", or \"update assigned\" when you created the order or are assigned to it, or, on a draft order, its creator when their role can create sales orders. Otherwise 403 `user_is_not_authorized`. Reading needs only team membership.","related":["v2_public_shipment_show","v2_public_shipment_package_destroy","v2_public_sales_order_shipment_destroy_all"],"rules":["The role check comes first: a shipment that is already deleted still needs permission to edit its order.","On a draft order, a shipment with a Shippo label can't be deleted: \"Publish this order before deleting a shipment with a shipping label.\" The same applies to Shopify-linked and other externally synced shipments.","A Shopify shipment with items fulfilled by a third party can't be deleted.","A shipment managed by Shopify, or with a broken Shopify link, can't be deleted (`shopify_managed_shipment_locked`, `shopify_broken_link_shipment_locked`).","On an order deleted in Shopify: 422 `shopify_order_deleted_externally`.","If Shopify refuses to cancel the fulfillment, the shipment is not deleted and the error is returned."],"side_effects":["Requests a refund from Shippo for each Shippo label, in the background.","Cancels the Shopify fulfillment of a Shopify shipment (calls Shopify while you wait).","Recalculates the order lines' shipped status and the order's shipping totals; on an Auto Invoice order, updates its shipping fee lines.","Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open."]}},"get":{"description":"A shipment sends some or all of a sales order's (or quote's) lines to one address, by one shipping type. One order can have many shipments. Each shipment line points at an order line with a quantity, or is a shipping cost line; packages hold the labels and tracking numbers.\n\nReturns the shipment with its lines (`items`), packages (`shipment_packages`) and shipping estimates (`shipment_estimates`): order and customer, shipping type, Ship To as `shipping_address_id` plus the full address in `shipping_address` (null when none), the receiver contact as `receiver_contact_id` only (read it with Get a contact by id), `ready_to_ship` (every job of its lines is Completed), `status_id` plus the full `status` object, `external_mutation_source` (which side may change a Shopify shipment), notes, `cost_total` and `billable_fee_total` as `{ value, dp }` pairs, and `pdf` links (packing slip and shipment labels; they carry their own access token).\n\n`scoped_id` reads back as `SHIP-<number>`.","operationId":"v2_public_shipment_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's `id` (a hash id), as its answers show it. Its unique key (`shp_...`) also works, but API answers don't include it.","example":"MQyJUnd3oty75h","in":"path","name":"unique_key","required":true,"schema":{"example":"MQyJUnd3oty75h","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"billable_fee_total":{"dp":4,"value":124000},"cost_total":{"dp":4,"value":124000},"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"customer_id":"ifAHmADekGZ6id","customer_profile_id":null,"delivery_notes":"Leave at the loading dock.","external_ids":[],"external_mutation_source":"unknown","external_type":null,"from_legacy":false,"has_third_party_fulfilled_items":false,"id":"MQyJUnd3oty75h","internal_notes":null,"is_external":false,"is_valid":true,"items":[{"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"u8mEG7LHUtS55s","is_external":false,"lock_version":1730000000000000,"position":100,"pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"total":{"dp":0,"value":0},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"shipment_id":"MQyJUnd3oty75h","type":"order_item","weight":{"type":"use_system"}},{"auto_invoice_managed":false,"billable_fee_total":{"dp":6,"value":12400000},"external_ids":[],"external_type":null,"from_legacy":false,"id":"bLpxVNJLniZ4dm","is_external":false,"lock_version":1730000000000000,"position":900,"pricing":{"product_cost":{"override":true,"pricing_mode":"none","pricing_mode_total":{"dp":6,"value":0},"total":{"dp":6,"value":12400000}},"type":"shipment_cost"},"product":{"properties":{"description":null,"name":"USPS Ground Advantage","shipment_estimate_id":null,"shipment_package_id":"o6foWpSAayc79D"},"type":"shipment_cost"},"quantity":{"total":{"dp":0,"value":1},"type":"unit"},"shipment_id":"MQyJUnd3oty75h","type":"shipment_cost"}],"last_sync_source":null,"lock_version":1730000000000000,"order_external_ids":[],"order_external_type":null,"order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","packed_by":null,"pdf":[{"description":"Packing slip with white labeling","label":"Packing Slip","object_type":"shipment","url":"https://example.com/pdf/packing-slip.pdf"}],"ready_to_ship":false,"receiver_contact_id":null,"scoped_id":"SHIP-12","ship_to_status":"okay","shipment_estimates":[{"created_at":"2026-11-03T15:00:00+00:00","frontend_data":[],"frontend_data_version":null,"goshippo_selected_rate_id":"rate_0001","goshippo_shipment_id":"shipment_0001","id":"tVjoZLKlSwZFF5","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","shippo_address_from":{"city":"Austin","company":"","country":"US","email":"","name":"Northwind Apparel","phone":"+1 201 555 0123","state":"TX","street1":"100 Example Street","street2":"","zip":"78701"},"shippo_address_to":{"city":"Denver","company":"","country":"US","email":"alex@example.com","name":"Alex Rivera","phone":"","state":"CO","street1":"100 Example Street","street2":"","zip":"80202"},"shippo_carrier_accounts":[],"shippo_extra":null,"shippo_object_id":"shipment_0001","shippo_parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"shippo_rates":[{"amount":"12.40","amount_local":"12.40","arrives_by":null,"attributes":["CHEAPEST"],"carrier_account":"carrier_0001","currency":"USD","currency_local":"USD","duration_terms":"Delivery in 2 to 5 days.","estimated_days":3,"included_insurance_price":null,"messages":[],"object_created":"2026-11-03T15:00:00Z","object_id":"rate_0001","object_updated":"2026-11-03T15:00:00Z","provider":"USPS","provider_image_200":"https://example.com/usps_200.png","provider_image_75":"https://example.com/usps_75.png","servicelevel":{"extended_token":"usps_ground_advantage","name":"Ground Advantage","terms":"","token":"usps_ground_advantage"},"shipment":"shipment_0001"}],"shippo_shipment_date":"2026-11-03T15:00:00Z","shippo_status":"SUCCESS","type":"integration_shippo"}],"shipment_packages":[{"charges":12400,"created_at":"2026-11-03T15:00:00+00:00","goshippo":{"parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"provider":"USPS","rate_id":"rate_0001"},"height":"4","id":"o6foWpSAayc79D","is_master":true,"length":"12","length_unit":"IN","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","parent_id":null,"pdf":[{"description":"Postage label individually to be printed 4\" x 6\" label","label":"Postage Label (4 in x 6 in label)","url":"https://example.com/labels/o6foWpSAayc79D.pdf"}],"provider_name":"USPS","provider_saturday_delivery":false,"provider_service_code":null,"provider_service_name":"Ground Advantage","provider_shipment_id":"transaction_0001","provider_tracking_number":"9400100000000000000000","shipment_has_third_party_fulfilled_items":false,"shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","status":"pending","type":"goshippo","weight":"2","weight_unit":"LB","width":"10"}],"shipping_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"shipping_address_id":"117KfwwfreX15N","shipping_type_id":"6OTWtTOpYcBz8q","status":{"color":"#9e9e9e","customer_label":"Pending","id":"AvY6ZbnrTJqpUI","label":"Pending","position":1,"role":"shipment","trashed":false,"type":"start"},"status_id":"AvY6ZbnrTJqpUI","version":2},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A shipment.","properties":{"billable_fee_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping cost lines (what is billed), at the stored scale (4 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."},"cost_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping cost lines (the cost), at the stored scale (4 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."},"customer":{"oneOf":[{"additionalProperties":true,"description":"The customer (the full customer record).","properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":"string"},"name":{"example":"Northwind Apparel","type":"string"}},"type":"object"},{"type":"null"}]},"customer_due_date":{"description":"The order's customer due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_po_number":{"type":["string","null"]},"customer_profile_id":{"description":"The brand profile printed on the documents.","example":null,"type":["string","null"]},"delivery_notes":{"type":["string","null"]},"external_ids":{"description":"The shipment's links to external systems (a Shopify fulfillment); usually empty.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_mutation_source":{"description":"Who may change a Shopify shipment: `shopify` means it is managed in Shopify and locked here; `unknown` on non-Shopify orders.","enum":["shopify","yoprint","broken_link","unknown"],"type":"string"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"has_third_party_fulfilled_items":{"type":"boolean"},"id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"internal_notes":{"type":["string","null"]},"is_external":{"type":["boolean","integer","null"]},"is_valid":{"description":"Has lines, a shipping type, an address, and the order's customer.","type":"boolean"},"items":{"description":"The lines.","items":{"additionalProperties":true,"description":"A shipment line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only details of the line.","type":"object"},"auto_invoice_managed":{"type":"boolean"},"billable_fee_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping cost lines only: what is billed (after override, markup or margin); `pricing.product_cost.total` is the cost. 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."},"external_ids":{"description":"Links to external systems; usually empty.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The shipment line.","example":"u8mEG7LHUtS55s","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Returned but not checked on shipment lines.","type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"For `system`, `_meta.unit_price` is the order line's unit price and `_meta.subtotal` is that price × this shipment line's quantity (`_meta.total` is always 0); for `shipment_cost`, `product_cost` has `override` (always true for lines saved through the API), `total` (the cost), `pricing_mode` and `pricing_mode_total` (decimal pairs at 6 decimal places).","properties":{"type":{"enum":["system","shipment_cost"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details; for `order_item`, `parent` describes the order line.","type":"object"},"properties":{"additionalProperties":true,"description":"For `order_item`, `id` is the order line; for `shipment_cost`, `name`, `description`, `shipment_package_id`, `shipment_estimate_id`.","type":"object"},"type":{"enum":["order_item","shipment_cost"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"type":{"description":"Same as `product.type`.","type":"string"},"weight":{"additionalProperties":true,"description":"The order line's weight (`_meta.total`, `_meta.unit`).","type":"object"}},"type":"object"},"type":"array"},"last_sync_source":{"type":["string","null"]},"lock_version":{"type":"integer"},"order_external_ids":{"description":"The order's links to external systems.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_external_type":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"example":"sales_order","type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"packed_by":{"description":"Who packed it.","example":null,"type":["string","null"]},"pdf":{"description":"The packing slip and the shipment label in Letter, 4\" x 6\" and 1\" x 2-1/8\" sizes (`is_custom` absent), then one entry per enabled custom shipment PDF template (`label`, `type`, `description`, `url`, the `show_in_*` flags, `is_custom: true`).","items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"is_custom":{"description":"True on custom template entries.","type":"boolean"},"label":{"example":"Packing Slip","type":"string"},"object_type":{"example":"shipment","type":"string"},"url":{"description":"A download link with its own access token.","type":"string"}},"type":"object"},"type":"array"},"ready_to_ship":{"description":"Every job of its lines is in a Completed status.","type":"boolean"},"receiver_contact_id":{"description":"The receiver contact.","example":null,"type":["string","null"]},"scoped_id":{"description":"The shipment number with its prefix. Update a shipment takes only the digits.","example":"SHIP-12","type":"string"},"ship_due_date":{"description":"The order's ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"ship_to_status":{"enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"shipment_estimates":{"description":"The saved shipping estimates.","items":{"additionalProperties":true,"description":"A saved shipping estimate.","properties":{"created_at":{"format":"date-time","type":"string"},"frontend_data":{"description":"What you sent as `frontend_data`; an empty list `[]` when you sent none.","type":["object","array"]},"frontend_data_version":{"description":"What you sent, or null."},"goshippo_selected_rate_id":{"description":"The rate chosen when it was saved.","example":"rate_0001","type":["string","null"]},"goshippo_shipment_id":{"description":"The Shippo shipment.","example":"shipment_0001","type":["string","null"]},"id":{"description":"The estimate.","example":"tVjoZLKlSwZFF5","type":"string"},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":["string","null"]},"shippo_address_from":{"additionalProperties":true,"type":"object"},"shippo_address_to":{"additionalProperties":true,"type":"object"},"shippo_carrier_accounts":{"items":{"type":"string"},"type":"array"},"shippo_extra":{"description":"The label options, or null."},"shippo_object_id":{"type":["string","null"]},"shippo_parcels":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"shippo_rates":{"description":"Every rate of that Shippo shipment, as saved (`amount` is a decimal string).","items":{"additionalProperties":true,"description":"A rate, with exactly these keys. Keys Shippo leaves out come back as empty strings.","properties":{"amount":{"example":"12.40","type":"string"},"amount_local":{"example":"12.40","type":"string"},"arrives_by":{"example":null,"type":["string","null"]},"attributes":{"description":"Shippo's tags, for example `CHEAPEST`.","example":["CHEAPEST"],"items":{"type":"string"},"type":"array"},"carrier_account":{"example":"carrier_0001","type":"string"},"currency":{"example":"USD","type":"string"},"currency_local":{"example":"USD","type":"string"},"duration_terms":{"example":"Delivery in 2 to 5 days.","type":["string","null"]},"estimated_days":{"example":3,"type":["integer","null"]},"included_insurance_price":{"example":null,"type":["string","null"]},"messages":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"object_created":{"example":"2026-11-03T15:00:00Z","type":"string"},"object_id":{"description":"The rate id. Send it as `rate_id` to buy this label.","example":"rate_0001","type":"string"},"object_updated":{"example":"2026-11-03T15:00:00Z","type":"string"},"provider":{"example":"USPS","type":"string"},"provider_image_200":{"example":"https://example.com/usps_200.png","type":"string"},"provider_image_75":{"description":"A URL of the carrier logo.","example":"https://example.com/usps_75.png","type":"string"},"servicelevel":{"additionalProperties":false,"description":"Exactly these four keys; null when Shippo sends no service level.","properties":{"extended_token":{"example":"usps_ground_advantage","type":"string"},"name":{"example":"Ground Advantage","type":"string"},"terms":{"example":"","type":"string"},"token":{"example":"usps_ground_advantage","type":"string"}},"type":"object"},"shipment":{"description":"The Shippo shipment this rate belongs to.","example":"shipment_0001","type":"string"}},"type":"object"},"type":"array"},"shippo_shipment_date":{"type":["string","null"]},"shippo_status":{"example":"SUCCESS","type":["string","null"]},"type":{"example":"integration_shippo","type":"string"}},"type":"object"},"type":"array"},"shipment_packages":{"description":"The packages.","items":{"additionalProperties":true,"description":"A package.","properties":{"charges":{"description":"The label cost. For a multi-parcel label every package repeats the rate's full amount: read the master's value and don't add packages up. Null for external labels. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12400,"type":["integer","number","string","null"]},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"from_address":{"description":"The address record behind `from_address_id`, or null when it is not set."},"from_address_id":{"description":"Older packages only: the ship-from address record; null otherwise.","example":null,"type":["string","null"]},"goshippo":{"additionalProperties":true,"description":"Shippo labels only: the Shippo details (shipment, rate, carrier, addresses, parcels).","properties":{"address_from":{"description":"The ship-from address sent to Shippo."},"address_return":{"description":"The return address sent to Shippo."},"address_to":{"description":"The ship-to address sent to Shippo."},"carrier_id":{"description":"The Shippo carrier account.","type":["string","null"]},"parcel_id":{"description":"The Shippo parcel.","type":["string","null"]},"parcels":{"description":"The parcels of the Shippo shipment."},"provider":{"type":["string","null"]},"provider_image_200":{"type":["string","null"]},"provider_image_75":{"type":["string","null"]},"provider_tracking_number":{"type":["string","null"]},"rate_id":{"description":"The Shippo rate bought.","type":["string","null"]},"shipment_data":{"description":"The Shippo shipment the rate came from."},"shipment_id":{"description":"The Shippo shipment.","type":["string","null"]}},"type":"object"},"height":{"description":"Parcel size and weight as stored, in `length_unit` and `weight_unit`. Null for external labels.","type":["number","string","null"]},"id":{"description":"The package.","example":"o6foWpSAayc79D","type":"string"},"is_master":{"description":"The first package of a label (the others have `parent_id`).","type":"boolean"},"length":{"type":["number","string","null"]},"length_unit":{"description":"Shippo labels only, upper case.","example":"IN","type":["string","null"]},"order_external_ids":{"description":"The order's links to external systems.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_external_type":{"description":"`shopify` when the order came from Shopify.","type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"example":"sales_order","type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"parent_id":{"description":"The master package, for the other parcels of a multi-parcel label.","example":null,"type":["string","null"]},"pdf":{"description":"Not on external labels: the label file. `label` and `description` are fixed texts that always say 4 x 6, whatever your label size setting.","items":{"additionalProperties":true,"properties":{"description":{"example":"Postage label individually to be printed 4\" x 6\" label","type":"string"},"label":{"example":"Postage Label (4 in x 6 in label)","type":"string"},"url":{"description":"For a Shippo label, Shippo's signed link to the label file: don't publish it.","type":"string"}},"type":"object"},"type":"array"},"provider_name":{"description":"The carrier.","example":"USPS","type":["string","null"]},"provider_saturday_delivery":{"description":"Shippo labels only (absent on external labels); always false today.","type":"boolean"},"provider_service_code":{"description":"For external labels, `ups`, `fedex` or `other`. For Shippo labels it may be null: read the service from `provider_service_name`.","type":["string","null"]},"provider_service_name":{"example":"Ground Advantage","type":["string","null"]},"provider_shipment_id":{"description":"The Shippo transaction id (Shippo labels).","type":["string","null"]},"provider_tracking_number":{"example":"9400100000000000000000","type":["string","null"]},"shipment_external_type":{"description":"`shopify` when the shipment is linked to Shopify.","type":["string","null"]},"shipment_has_third_party_fulfilled_items":{"type":"boolean"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":"string"},"shipment_shopify_sync":{"description":"Shopify sync state of the shipment."},"status":{"enum":["pending","ready-to-ship","shipped","delivered"],"example":"pending","type":"string"},"to_address":{"description":"The address record behind `to_address_id`, or null when it is not set."},"to_address_id":{"description":"Older packages only: the ship-to address record; null otherwise.","example":null,"type":["string","null"]},"type":{"description":"`goshippo` a label bought through Shippo; `external_label` a label recorded from elsewhere.","enum":["goshippo","external_label","single_label"],"example":"goshippo","type":"string"},"weight":{"type":["number","string","null"]},"weight_unit":{"description":"Shippo labels only, upper case.","example":"LB","type":["string","null"]},"width":{"type":["number","string","null"]}},"type":"object"},"type":"array"},"shipping_address":{"description":"Ship To, the full address, always included (null when none).","oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"shipping_address_id":{"description":"Ship To.","example":"117KfwwfreX15N","type":["string","null"]},"shipping_type_id":{"description":"The shipping type.","example":"6OTWtTOpYcBz8q","type":["string","null"]},"shopify_sync":{"description":"Shopify sync state, for Shopify shipments."},"status":{"description":"The shipment status, always included.","oneOf":[{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},{"type":"null"}]},"status_id":{"description":"The shipment status.","example":"AvY6ZbnrTJqpUI","type":["string","null"]},"type":{"type":["string","null"]},"version":{"example":2,"type":"integer"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a shipment","tags":["Shipments"],"x-yoprint-docs":{"errors":[{"fix":"Use an id from the order's shipment list or Filter shipments.","status":404,"when":"The shipment isn't your team's."}],"group":"Shipping","notes":["Very old shipments (`version` 1) come back in the old shipment shape, without the v2 includes."],"permission":"Any member of the team.","related":["v2_public_shipment_update","v2_public_shipment_item_index","v2_public_shipment_package_index","v2_public_sales_order_shipment_index_for_order"]}},"put":{"description":"Changes a shipment's number, shipping type, address, receiver contact, brand profile, packer and notes. Send only what you change; returns the shipment.\n\nThis doesn't change the shipment's status (use Change the status of a shipment), its lines, packages or totals. A shipment that is Completed or has labels can still be edited.","operationId":"v2_public_shipment_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's `id` (a hash id), as its answers show it. Its unique key (`shp_...`) also works, but API answers don't include it.","example":"MQyJUnd3oty75h","in":"path","name":"unique_key","required":true,"schema":{"example":"MQyJUnd3oty75h","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"delivery_notes":"Leave at the loading dock.","shipping_address_id":"117KfwwfreX15N","shipping_type_id":"6OTWtTOpYcBz8q"},"schema":{"properties":{"customer_id":{"description":"Ignored: the shipment's customer is always the order's.","type":"string"},"customer_profile_id":{"description":"The brand profile whose details print on the documents. Null clears it.","type":["string","null"]},"delivery_notes":{"description":"Notes for delivery. Null clears them.","type":["string","null"]},"internal_notes":{"description":"Internal notes. Null clears them.","type":["string","null"]},"packed_by":{"description":"The user who packed it. Null clears it.","type":["string","null"]},"receiver_contact_id":{"description":"The receiver contact. Null clears it.","type":["string","null"]},"scoped_id":{"description":"The shipment number without the `SHIP-` prefix, as a string. Not checked for duplicates. Don't echo the `SHIP-...` value you read.","type":"string"},"shipping_address_id":{"description":"The ship-to address. Null clears it.","type":["string","null"]},"shipping_type_id":{"description":"The shipping type. Can't be cleared. Fulfill By Shopify is reserved for Shopify shipments.","example":"V4keXwwxMQyXw7","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"billable_fee_total":{"dp":4,"value":124000},"cost_total":{"dp":4,"value":124000},"customer":{"id":"ifAHmADekGZ6id","name":"Northwind Apparel"},"customer_id":"ifAHmADekGZ6id","customer_profile_id":null,"delivery_notes":"Leave at the loading dock.","external_ids":[],"external_mutation_source":"unknown","external_type":null,"from_legacy":false,"has_third_party_fulfilled_items":false,"id":"MQyJUnd3oty75h","internal_notes":null,"is_external":false,"is_valid":true,"last_sync_source":null,"lock_version":1730000000000000,"order_external_ids":[],"order_external_type":null,"order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","packed_by":null,"pdf":[{"description":"Packing slip with white labeling","label":"Packing Slip","object_type":"shipment","url":"https://example.com/pdf/packing-slip.pdf"}],"ready_to_ship":false,"receiver_contact_id":null,"scoped_id":"SHIP-12","ship_to_status":"okay","shipping_address":{"address1":"100 Example Street","address2":null,"city":"Austin","country":"United States","country_code":"US","id":"117KfwwfreX15N","label":"Main office","postcode":"78701","state":"Texas","state_code":"TX"},"shipping_address_id":"117KfwwfreX15N","shipping_type_id":"6OTWtTOpYcBz8q","status":{"color":"#9e9e9e","customer_label":"Pending","id":"AvY6ZbnrTJqpUI","label":"Pending","position":1,"role":"shipment","trashed":false,"type":"start"},"status_id":"AvY6ZbnrTJqpUI","version":2},"status":200,"success":true},"schema":{"properties":{"data":{"allOf":[{"$ref":"#/components/schemas/Shipment"},{"additionalProperties":true,"description":"A shipment.","properties":{"billable_fee_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping cost lines (what is billed), at the stored scale (4 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."},"cost_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping cost lines (the cost), at the stored scale (4 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."},"customer":{"oneOf":[{"additionalProperties":true,"description":"The customer (the full customer record).","properties":{"id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":"string"},"name":{"example":"Northwind Apparel","type":"string"}},"type":"object"},{"type":"null"}]},"customer_due_date":{"description":"The order's customer due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_po_number":{"type":["string","null"]},"customer_profile_id":{"description":"The brand profile printed on the documents.","example":null,"type":["string","null"]},"delivery_notes":{"type":["string","null"]},"external_ids":{"description":"The shipment's links to external systems (a Shopify fulfillment); usually empty.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_mutation_source":{"description":"Who may change a Shopify shipment: `shopify` means it is managed in Shopify and locked here; `unknown` on non-Shopify orders.","enum":["shopify","yoprint","broken_link","unknown"],"type":"string"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"has_third_party_fulfilled_items":{"type":"boolean"},"id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"internal_notes":{"type":["string","null"]},"is_external":{"type":["boolean","integer","null"]},"is_valid":{"description":"Has lines, a shipping type, an address, and the order's customer.","type":"boolean"},"last_sync_source":{"type":["string","null"]},"lock_version":{"type":"integer"},"order_external_ids":{"description":"The order's links to external systems.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_external_type":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"example":"sales_order","type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"packed_by":{"description":"Who packed it.","example":null,"type":["string","null"]},"pdf":{"description":"The packing slip and the shipment label in Letter, 4\" x 6\" and 1\" x 2-1/8\" sizes (`is_custom` absent), then one entry per enabled custom shipment PDF template (`label`, `type`, `description`, `url`, the `show_in_*` flags, `is_custom: true`).","items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"is_custom":{"description":"True on custom template entries.","type":"boolean"},"label":{"example":"Packing Slip","type":"string"},"object_type":{"example":"shipment","type":"string"},"url":{"description":"A download link with its own access token.","type":"string"}},"type":"object"},"type":"array"},"ready_to_ship":{"description":"Every job of its lines is in a Completed status.","type":"boolean"},"receiver_contact_id":{"description":"The receiver contact.","example":null,"type":["string","null"]},"scoped_id":{"description":"The shipment number with its prefix. Update a shipment takes only the digits.","example":"SHIP-12","type":"string"},"ship_due_date":{"description":"The order's ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"ship_to_status":{"enum":["okay","empty","diff_from_order","diff_from_customer"],"type":"string"},"shipping_address":{"description":"Ship To, the full address, always included (null when none).","oneOf":[{"additionalProperties":true,"description":"An address.","properties":{"address1":{"example":"100 Example Street","type":["string","null"]},"address2":{"type":["string","null"]},"city":{"example":"Austin","type":["string","null"]},"country":{"example":"United States","type":["string","null"]},"country_code":{"example":"US","type":["string","null"]},"id":{"description":"The address.","example":"117KfwwfreX15N","type":"string"},"label":{"example":"Main office","type":["string","null"]},"postcode":{"example":"78701","type":["string","null"]},"state":{"example":"Texas","type":["string","null"]},"state_code":{"example":"TX","type":["string","null"]}},"type":"object"},{"type":"null"}]},"shipping_address_id":{"description":"Ship To.","example":"117KfwwfreX15N","type":["string","null"]},"shipping_type_id":{"description":"The shipping type.","example":"6OTWtTOpYcBz8q","type":["string","null"]},"shopify_sync":{"description":"Shopify sync state, for Shopify shipments."},"status":{"description":"The shipment status, always included.","oneOf":[{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},{"type":"null"}]},"status_id":{"description":"The shipment status.","example":"AvY6ZbnrTJqpUI","type":["string","null"]},"type":{"type":["string","null"]},"version":{"example":2,"type":"integer"}},"type":"object"}]},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a shipment","tags":["Shipments"],"x-yoprint-docs":{"errors":[{"fix":"Fix the named field or make the change in Shopify.","status":422,"when":"Validation (`validation_failed`) or a Shopify rule (see rules)."},{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order."},{"fix":"Check the id.","status":404,"when":"The shipment isn't your team's."}],"group":"Shipping","permission":"Needs permission to edit the shipment's order: the team owner, a role whose Manage Sales Orders permission is \"update all\", or \"update assigned\" when you created the order or are assigned to it, or, on a draft order, its creator when their role can create sales orders. Otherwise 403 `user_is_not_authorized`. Reading needs only team membership.","related":["v2_public_shipment_show","v2_public_sales_order_shipment_change_status","v1_public_shipping_type_index"],"rules":["An id of 0 or below is refused: \"Choose a valid shipping address.\" (and the same for the other ids).","Only the listed fields can be cleared with null; elsewhere null means \"not sent\".","On a shipment linked to Shopify, changes are refused with 422 `shopify_managed_shipment_locked`, `shopify_fulfilled_shipment_locked` or `shopify_broken_link_shipment_locked`; on an order deleted in Shopify with `shopify_order_deleted_externally`.","On a Shopify order the address and receiver contact can't change: 422 `shopify_shipment_snapshot_update_boundary`.","An externally synced shipment on a draft order can't be updated: \"Publish this order before updating an externally synced shipment.\"","Choosing Fulfill By Shopify on a shipment not managed by Shopify: 422 `shopify_system_shipping_type_read_only`.","Ids are not checked against your records: an address, contact, brand profile, user or shipping type that isn't yours (or isn't the order customer's) is saved as given. Read them from the order's customer and your settings first."],"side_effects":["Saves the fields; no totals change. Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open. No webhook or email is sent."]}}},"/v2/api/store/{team_slug}/v2/shipment/{unique_key}/item":{"get":{"description":"Returns every line of a shipment: shipped order lines and shipping cost lines. Not paged; sort by `position`.\n\n| `product.type` | What it is |\n| --- | --- |\n| `order_item` | Ships a quantity of a line of the same order (any kind of product line, or a fee). |\n| `shipment_cost` | A shipping cost line (Shipping Cost in the web app), with its own price, optionally tied to a package or an estimate. |","operationId":"v2_public_shipment_item_index","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's `id` (a hash id), as its answers show it. Its unique key (`shp_...`) also works, but API answers don't include it.","example":"MQyJUnd3oty75h","in":"path","name":"unique_key","required":true,"schema":{"example":"MQyJUnd3oty75h","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"u8mEG7LHUtS55s","is_external":false,"lock_version":1730000000000000,"position":100,"pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"total":{"dp":0,"value":0},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"shipment_id":"MQyJUnd3oty75h","type":"order_item","weight":{"type":"use_system"}}],"status":200,"success":true},"schema":{"properties":{"data":{"items":{"additionalProperties":true,"description":"A shipment line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only details of the line.","type":"object"},"auto_invoice_managed":{"type":"boolean"},"billable_fee_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping cost lines only: what is billed (after override, markup or margin); `pricing.product_cost.total` is the cost. 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."},"external_ids":{"description":"Links to external systems; usually empty.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The shipment line.","example":"u8mEG7LHUtS55s","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Returned but not checked on shipment lines.","type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"For `system`, `_meta.unit_price` is the order line's unit price and `_meta.subtotal` is that price × this shipment line's quantity (`_meta.total` is always 0); for `shipment_cost`, `product_cost` has `override` (always true for lines saved through the API), `total` (the cost), `pricing_mode` and `pricing_mode_total` (decimal pairs at 6 decimal places).","properties":{"type":{"enum":["system","shipment_cost"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details; for `order_item`, `parent` describes the order line.","type":"object"},"properties":{"additionalProperties":true,"description":"For `order_item`, `id` is the order line; for `shipment_cost`, `name`, `description`, `shipment_package_id`, `shipment_estimate_id`.","type":"object"},"type":{"enum":["order_item","shipment_cost"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"type":{"description":"Same as `product.type`.","type":"string"},"weight":{"additionalProperties":true,"description":"The order line's weight (`_meta.total`, `_meta.unit`).","type":"object"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"List the lines of a shipment","tags":["Shipment line items"],"x-yoprint-docs":{"errors":[{"fix":"Check the id.","status":404,"when":"The shipment isn't your team's."}],"group":"Shipping","permission":"Any member of the team.","related":["v2_public_shipment_item_create","v2_public_shipment_item_bulk"]}},"post":{"description":"Adds one line to a shipment and recalculates it. Returns the line in an action envelope (`action_performed` `CREATED`, `has_changes`, `lock_version`, `item`).\n\n| `product.type` | What it is |\n| --- | --- |\n| `order_item` | Ships a quantity of a line of the same order (any kind of product line, or a fee). |\n| `shipment_cost` | A shipping cost line (Shipping Cost in the web app), with its own price, optionally tied to a package or an estimate. |\n\nNumbers are `{ value, dp }` pairs: `value` is the number without its decimal point and `dp` the count of decimal places, so 12.50 is `{ \"value\": 1250, \"dp\": 2 }` (or `{ \"value\": 125, \"dp\": 1 }`). `value` is a JSON integer or a digit string, never a float: `12.5` is refused. Quantities take up to 8 decimal places; shipping costs and a pricing mode's rate take 6. More significant decimals than that are a 422, not rounded. Send very large numbers as strings. Answers send prices at the stored scale (6 decimal places), quantities without trailing zeros, and `_meta.subtotal` (price × quantity) at the combined scale, compacted when it would exceed a safe integer: always read `dp`.\n\nNothing caps the quantity at what was ordered: shipping more marks the order line over-allocated.","operationId":"v2_public_shipment_item_create","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's `id` (a hash id), as its answers show it. Its unique key (`shp_...`) also works, but API answers don't include it.","example":"MQyJUnd3oty75h","in":"path","name":"unique_key","required":true,"schema":{"example":"MQyJUnd3oty75h","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"order_item":{"summary":"Ship 24 of an order line","value":{"position":100,"product":{"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"}},"x-yoprint-variant":"Order line"},"shipment_cost":{"summary":"Add a 12.40 shipping cost for a package","value":{"position":900,"pricing":{"product_cost":{"pricing_mode":"none","total":{"dp":2,"value":1240}},"type":"shipment_cost"},"product":{"properties":{"name":"USPS Ground Advantage","shipment_package_id":"o6foWpSAayc79D"},"type":"shipment_cost"}},"x-yoprint-variant":"Shipping cost"}},"schema":{"oneOf":[{"description":"Ships a quantity of a line of the same order.","properties":{"position":{"description":"Where the line sits on the shipment; lower comes first.","type":"integer"},"pricing":{"description":"Optional; the price always comes from the order line.","properties":{"type":{"const":"system","type":"string"}},"type":"object"},"product":{"properties":{"properties":{"properties":{"id":{"description":"The order line's `id` (a hash id). It must be on the shipment's order, shippable, and not already on this shipment.","example":"V4keXwwxMQyXw7","type":"string"}},"required":["id"],"type":"object"},"type":{"const":"order_item","type":"string"}},"required":["type","properties"],"type":"object"},"quantity":{"description":"How many to ship. Not negative; may be more than ordered (the line then shows as over-allocated).","properties":{"total":{"description":"The quantity, up to 8 decimal places.","example":{"dp":0,"value":24},"properties":{"dp":{"description":"How many of its digits come after the decimal point, 0 to 30.","maximum":30,"minimum":0,"type":"integer"},"value":{"description":"The number without its decimal point, as a JSON integer or a string of digits (an optional leading `-`, no leading zeros, no decimal point).","type":["integer","string"]}},"required":["value","dp"],"type":"object"},"type":{"const":"unit","type":"string"}},"required":["type","total"],"type":"object"}},"required":["product","quantity","position"],"title":"Order line","type":"object"},{"description":"A shipping cost line with its own cost.","properties":{"position":{"type":"integer"},"pricing":{"properties":{"product_cost":{"properties":{"pricing_mode":{"description":"Send `none`: the price billed is the cost. See the notes for the other values.","enum":["none","override","markup","margin"],"type":"string"},"total":{"description":"The cost, up to 6 decimal places. Missing means 0.","example":{"dp":2,"value":1240},"properties":{"dp":{"description":"How many of its digits come after the decimal point, 0 to 30.","maximum":30,"minimum":0,"type":"integer"},"value":{"description":"The number without its decimal point, as a JSON integer or a string of digits (an optional leading `-`, no leading zeros, no decimal point).","type":["integer","string"]}},"required":["value","dp"],"type":"object"}},"required":["pricing_mode"],"type":"object"},"type":{"const":"shipment_cost","type":"string"}},"required":["type","product_cost"],"type":"object"},"product":{"properties":{"properties":{"properties":{"description":{"type":"string"},"name":{"type":"string"},"shipment_estimate_id":{"description":"A shipping estimate of this shipment the cost comes from.","type":["string","null"]},"shipment_package_id":{"description":"A package of this shipment the cost is for. One live cost line per package: a second create returns the existing line.","type":["string","null"]}},"required":["name"],"type":"object"},"type":{"const":"shipment_cost","type":"string"}},"required":["type","properties"],"type":"object"},"quantity":{"description":"Optional and not used in the totals.","type":"object"}},"required":["product","pricing","position"],"title":"Shipping cost","type":"object"}],"title":"What are you adding?"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"action_performed":"CREATED","has_changes":true,"item":{"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"u8mEG7LHUtS55s","is_external":false,"lock_version":1730000000000000,"position":100,"pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"total":{"dp":0,"value":0},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"shipment_id":"MQyJUnd3oty75h","type":"order_item","weight":{"type":"use_system"}},"lock_version":{"order":{"invoice_lock_version":1730000000000000,"job_lock_version":1730000000000000,"order_item_lock_version":1730000000000000,"order_lock_version":1730000000000000,"payment_lock_version":1730000000000000,"shipment_lock_version":1730000000000000},"shipment":{"shipment_item_lock_version":1730000000000000,"shipment_lock_version":1730000000000000}},"object_type":"shipment_item"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"What happened, and the line.","properties":{"action_performed":{"description":"`NONE` when nothing changed.","enum":["CREATED","UPDATED","DELETED","NONE"],"type":"string"},"has_changes":{"type":"boolean"},"item":{"additionalProperties":true,"description":"A shipment line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only details of the line.","type":"object"},"auto_invoice_managed":{"type":"boolean"},"billable_fee_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping cost lines only: what is billed (after override, markup or margin); `pricing.product_cost.total` is the cost. 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."},"external_ids":{"description":"Links to external systems; usually empty.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The shipment line.","example":"u8mEG7LHUtS55s","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Returned but not checked on shipment lines.","type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"For `system`, `_meta.unit_price` is the order line's unit price and `_meta.subtotal` is that price × this shipment line's quantity (`_meta.total` is always 0); for `shipment_cost`, `product_cost` has `override` (always true for lines saved through the API), `total` (the cost), `pricing_mode` and `pricing_mode_total` (decimal pairs at 6 decimal places).","properties":{"type":{"enum":["system","shipment_cost"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details; for `order_item`, `parent` describes the order line.","type":"object"},"properties":{"additionalProperties":true,"description":"For `order_item`, `id` is the order line; for `shipment_cost`, `name`, `description`, `shipment_package_id`, `shipment_estimate_id`.","type":"object"},"type":{"enum":["order_item","shipment_cost"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"type":{"description":"Same as `product.type`.","type":"string"},"weight":{"additionalProperties":true,"description":"The order line's weight (`_meta.total`, `_meta.unit`).","type":"object"}},"type":"object"},"lock_version":{"additionalProperties":true,"description":"Lock versions after the change.","properties":{"order":{"additionalProperties":true,"description":"The order's lock versions: `job_lock_version`, `invoice_lock_version`, `order_item_lock_version`, `shipment_lock_version`, `payment_lock_version`, `order_lock_version`.","type":"object"},"shipment":{"additionalProperties":true,"description":"The shipment's lock versions: `shipment_item_lock_version`, `shipment_lock_version`.","type":"object"}},"type":"object"},"object_type":{"const":"shipment_item","example":"shipment_item","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add a line to a shipment","tags":["Shipment line items"],"x-yoprint-docs":{"errors":[{"fix":"Read the message and fix the line.","status":422,"when":"Validation (`validation_failed`) or a business rule (`cart_item_validation_error`, or a bare `message`)."},{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order."},{"fix":"Check the id.","status":404,"when":"The shipment isn't your team's."}],"group":"Shipping","notes":["A shipping cost line's `pricing_mode` `override`, `markup` and `margin` are accepted, but the API can't pass their rate: `override` bills 0 and the others bill the cost. Use `none` and set the cost you want to bill."],"permission":"Needs permission to edit the shipment's order: the team owner, a role whose Manage Sales Orders permission is \"update all\", or \"update assigned\" when you created the order or are assigned to it, or, on a draft order, its creator when their role can create sales orders. Otherwise 403 `user_is_not_authorized`. Reading needs only team membership.","related":["v2_public_shipment_item_index","v2_public_shipment_item_bulk","v2_public_shipment_package_index"],"rules":["`product.type` is `order_item` or `shipment_cost` only; the order line kinds (`db_catalog` and so on) are refused with \"The selected product.type is invalid.\"","An order line can be on a shipment once: 422 `cart_item_validation_error` \"Shipment already has the same Order Item\".","The order line must be on the shipment's order and shippable; otherwise 422 with a bare `{ \"message\": \"order_item: ...\" }`.","A shipping cost line's package or estimate must belong to this shipment. A second cost line for the same package returns the first with `action_performed` `NONE`.","A Shopify shipment that is locked (managed by Shopify or already fulfilled there) or has a broken Shopify link takes no new lines: 422 `validation_error` \"Cannot create Shopify-synced shipment item from API.\" An externally synced shipment on a draft order: \"Publish this order before creating an externally synced shipment item.\"","Fields that aren't listed are dropped, and a `null` counts as not sent (except `shipment_package_id` and `shipment_estimate_id`)."],"side_effects":["Recalculates the shipment's cost and billable fee totals and the order's shipping totals.","Updates each order line's shipped status (not allocated, partly, fully or over-allocated).","On an Auto Invoice order, shipping cost lines are mirrored as shipping fees on the managed invoice.","Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open. No webhook or email is sent."]}}},"/v2/api/store/{team_slug}/v2/shipment/{unique_key}/item/bulk":{"post":{"description":"Applies several line changes to one shipment in one transaction: all of them are saved, or none.\n\nThe body is a JSON array of actions, each with your own label `bid`, an `action`, a `payload` for `create` and `update` (the same body as the single calls) and `cart_item_id` for `update` and `delete`. YoPrint runs the deletes first, then the creates, then the updates, and recalculates once. Returns every line of the shipment afterwards, with a top-level `has_changes`. Numbers are `{ value, dp }` pairs: `value` is the number without its decimal point and `dp` the count of decimal places, so 12.50 is `{ \"value\": 1250, \"dp\": 2 }` (or `{ \"value\": 125, \"dp\": 1 }`). `value` is a JSON integer or a digit string, never a float: `12.5` is refused. Quantities take up to 8 decimal places; shipping costs and a pricing mode's rate take 6. More significant decimals than that are a 422, not rounded. Send very large numbers as strings. Answers send prices at the stored scale (6 decimal places), quantities without trailing zeros, and `_meta.subtotal` (price × quantity) at the combined scale, compacted when it would exceed a safe integer: always read `dp`.","operationId":"v2_public_shipment_item_bulk","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's `id` (a hash id), as its answers show it. Its unique key (`shp_...`) also works, but API answers don't include it.","example":"MQyJUnd3oty75h","in":"path","name":"unique_key","required":true,"schema":{"example":"MQyJUnd3oty75h","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"action":"create","bid":"row-1","payload":{"position":100,"product":{"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"}}},{"action":"delete","bid":"row-2","cart_item_id":"goJhP2gixO3PhU"}],"schema":{"items":{"properties":{"action":{"enum":["create","update","delete"],"type":"string"},"bid":{"description":"Your label for this action, echoed in errors.","type":"string"},"cart_item_id":{"description":"The shipment line. Required for `update` and `delete`.","example":"V4keXwwxMQyXw7","type":"string"},"payload":{"additionalProperties":true,"description":"Required for `create` and `update`.","type":"object"}},"required":["bid","action"],"type":"object"},"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"action_performed":"CREATED","has_changes":true,"item":{"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"u8mEG7LHUtS55s","is_external":false,"lock_version":1730000000000000,"position":100,"pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"total":{"dp":0,"value":0},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"shipment_id":"MQyJUnd3oty75h","type":"order_item","weight":{"type":"use_system"}},"lock_version":{"order":{"invoice_lock_version":1730000000000000,"job_lock_version":1730000000000000,"order_item_lock_version":1730000000000000,"order_lock_version":1730000000000000,"payment_lock_version":1730000000000000,"shipment_lock_version":1730000000000000},"shipment":{"shipment_item_lock_version":1730000000000000,"shipment_lock_version":1730000000000000}},"object_type":"shipment_item"}],"has_changes":true,"status":200,"success":true},"schema":{"properties":{"data":{"description":"Every line of the shipment after the save, one envelope each (deleted lines are absent). `has_changes` is at the top level, next to `data`.","items":{"additionalProperties":true,"description":"What happened, and the line.","properties":{"action_performed":{"description":"`NONE` when nothing changed.","enum":["CREATED","UPDATED","DELETED","NONE"],"type":"string"},"has_changes":{"type":"boolean"},"item":{"additionalProperties":true,"description":"A shipment line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only details of the line.","type":"object"},"auto_invoice_managed":{"type":"boolean"},"billable_fee_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping cost lines only: what is billed (after override, markup or margin); `pricing.product_cost.total` is the cost. 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."},"external_ids":{"description":"Links to external systems; usually empty.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The shipment line.","example":"u8mEG7LHUtS55s","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Returned but not checked on shipment lines.","type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"For `system`, `_meta.unit_price` is the order line's unit price and `_meta.subtotal` is that price × this shipment line's quantity (`_meta.total` is always 0); for `shipment_cost`, `product_cost` has `override` (always true for lines saved through the API), `total` (the cost), `pricing_mode` and `pricing_mode_total` (decimal pairs at 6 decimal places).","properties":{"type":{"enum":["system","shipment_cost"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details; for `order_item`, `parent` describes the order line.","type":"object"},"properties":{"additionalProperties":true,"description":"For `order_item`, `id` is the order line; for `shipment_cost`, `name`, `description`, `shipment_package_id`, `shipment_estimate_id`.","type":"object"},"type":{"enum":["order_item","shipment_cost"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"type":{"description":"Same as `product.type`.","type":"string"},"weight":{"additionalProperties":true,"description":"The order line's weight (`_meta.total`, `_meta.unit`).","type":"object"}},"type":"object"},"lock_version":{"additionalProperties":true,"description":"Lock versions after the change.","properties":{"order":{"additionalProperties":true,"description":"The order's lock versions: `job_lock_version`, `invoice_lock_version`, `order_item_lock_version`, `shipment_lock_version`, `payment_lock_version`, `order_lock_version`.","type":"object"},"shipment":{"additionalProperties":true,"description":"The shipment's lock versions: `shipment_item_lock_version`, `shipment_lock_version`.","type":"object"}},"type":"object"},"object_type":{"const":"shipment_item","example":"shipment_item","type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/BulkValidationPayloadResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Add, change and remove shipment lines at once","tags":["Shipment line items"],"x-yoprint-docs":{"errors":[{"fix":"Fix the named action and resend the whole array.","status":422,"when":"A payload fails validation (`bulk_validation_payload_failed`, with `bid` and `fields`), or a rule refuses an action; nothing is saved."},{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order."},{"fix":"Check the id.","status":404,"when":"The shipment isn't your team's."}],"group":"Shipping","notes":["Lines you updated say `UPDATED`; lines you created and lines you didn't touch both say `CREATED`, and deleted lines are absent. Use the top-level `has_changes` (next to `data`) to know whether anything changed."],"permission":"Needs permission to edit the shipment's order: the team owner, a role whose Manage Sales Orders permission is \"update all\", or \"update assigned\" when you created the order or are assigned to it, or, on a draft order, its creator when their role can create sales orders. Otherwise 403 `user_is_not_authorized`. Reading needs only team membership.","related":["v2_public_shipment_item_create","v2_public_shipment_item_update","v2_public_shipment_item_destroy"],"rules":["One action per line: a second is 422 `cart_item_validation_error` with `error.context.reason` `duplicate_item_action` and the row's `error.bid`.","An `update` or `delete` of a line that isn't on the shipment is the same code with reason `item_not_available` (and `error.bid`). Deleting an already deleted line is skipped.","The validation and Shopify lock rules of the single calls apply to each action (the Shopify lock to every action, synced line or not). Two don't: a shipping cost line for a package that already has one is created again (the single call answers `NONE`), and the draft-order \"Publish this order before ...\" rule for externally synced shipments isn't checked."],"side_effects":["Recalculates the shipment's cost and billable fee totals and the order's shipping totals.","Updates each order line's shipped status (not allocated, partly, fully or over-allocated).","On an Auto Invoice order, shipping cost lines are mirrored as shipping fees on the managed invoice.","Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open. No webhook or email is sent."]}}},"/v2/api/store/{team_slug}/v2/shipment/{unique_key}/item/sort":{"post":{"description":"Makes room around a line whose position you just changed, so positions stay unique and spaced. It doesn't move the line to a new place: set `position` with Update a shipment line first, then call this with the line (`current`) and its new neighbours (`previous`, `next`).\n\n- Send all three as null (or a `current` that isn't on the shipment) to re-space every line, keeping their order.\n- If `previous` and `next` are both sent and are within 1000 of each other, every line is re-spaced.\n- Otherwise, if the line is within 1000 of a neighbour, only it moves: to the middle of `previous` and `next`, or 3000 past the only neighbour you sent.\n- Otherwise nothing changes.\n\nReturns `is_position_sorted` and, when positions changed, every line (`data`).","operationId":"v2_public_shipment_item_sort","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's `id` (a hash id), as its answers show it. Its unique key (`shp_...`) also works, but API answers don't include it.","example":"MQyJUnd3oty75h","in":"path","name":"unique_key","required":true,"schema":{"example":"MQyJUnd3oty75h","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"all":{"summary":"Re-space every line","value":{"current":null,"next":null,"previous":null}},"one":{"summary":"After moving one line","value":{"current":"u8mEG7LHUtS55s","next":"T62Dl1gvIvguYd","previous":"goJhP2gixO3PhU"}}},"schema":{"properties":{"current":{"description":"The line you moved (hash id).","type":["string","null"]},"next":{"description":"The line now after it (hash id), or null.","type":["string","null"]},"previous":{"description":"The line now before it (hash id), or null.","type":["string","null"]}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"data":[{"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"goJhP2gixO3PhU","is_external":false,"lock_version":1730000000000000,"position":100000,"pricing":{"_meta":{"subtotal":{"dp":0,"value":180},"total":{"dp":0,"value":0},"unit_price":{"dp":6,"value":30000000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 18500 Hoodie"}},"properties":{"id":"OM2IMHqOYFKlP4"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":6},"type":"unit"},"shipment_id":"MQyJUnd3oty75h","type":"order_item","weight":{"type":"use_system"}},{"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"u8mEG7LHUtS55s","is_external":false,"lock_version":1730000000000000,"position":200000,"pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"total":{"dp":0,"value":0},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 5000 T-shirt"}},"properties":{"id":"ZJTJ2uF5dMiArL"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"shipment_id":"MQyJUnd3oty75h","type":"order_item","weight":{"type":"use_system"}},{"auto_invoice_managed":false,"external_ids":[],"external_type":null,"from_legacy":false,"id":"T62Dl1gvIvguYd","is_external":false,"lock_version":1730000000000000,"position":300000,"pricing":{"_meta":{"subtotal":{"dp":0,"value":300},"total":{"dp":0,"value":0},"unit_price":{"dp":6,"value":12500000}},"type":"system"},"product":{"_meta":{"parent":{"product_name":"Gildan 2000 T-shirt"}},"properties":{"id":"XznWFuTIgJF9Do"},"type":"order_item"},"quantity":{"total":{"dp":0,"value":24},"type":"unit"},"shipment_id":"MQyJUnd3oty75h","type":"order_item","weight":{"type":"use_system"}}],"is_position_sorted":true},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"properties":{"data":{"description":"Every line, when positions changed; otherwise null.","oneOf":[{"items":{"additionalProperties":true,"description":"A shipment line.","properties":{"_meta":{"additionalProperties":true,"description":"Read-only details of the line.","type":"object"},"auto_invoice_managed":{"type":"boolean"},"billable_fee_total":{"$ref":"#/components/schemas/BigDecimalValue","description":"Shipping cost lines only: what is billed (after override, markup or margin); `pricing.product_cost.total` is the cost. 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."},"external_ids":{"description":"Links to external systems; usually empty.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"external_type":{"type":["string","null"]},"from_legacy":{"type":"boolean"},"id":{"description":"The shipment line.","example":"u8mEG7LHUtS55s","type":"string"},"is_external":{"type":"boolean"},"lock_version":{"description":"Returned but not checked on shipment lines.","type":"integer"},"position":{"example":100,"type":"integer"},"pricing":{"additionalProperties":true,"description":"For `system`, `_meta.unit_price` is the order line's unit price and `_meta.subtotal` is that price × this shipment line's quantity (`_meta.total` is always 0); for `shipment_cost`, `product_cost` has `override` (always true for lines saved through the API), `total` (the cost), `pricing_mode` and `pricing_mode_total` (decimal pairs at 6 decimal places).","properties":{"type":{"enum":["system","shipment_cost"],"type":"string"}},"type":"object"},"product":{"additionalProperties":true,"properties":{"_meta":{"additionalProperties":true,"description":"Read-only details; for `order_item`, `parent` describes the order line.","type":"object"},"properties":{"additionalProperties":true,"description":"For `order_item`, `id` is the order line; for `shipment_cost`, `name`, `description`, `shipment_package_id`, `shipment_estimate_id`.","type":"object"},"type":{"enum":["order_item","shipment_cost"],"example":"order_item","type":"string"}},"type":"object"},"quantity":{"additionalProperties":true,"properties":{"total":{"$ref":"#/components/schemas/BigDecimalValue","description":"The quantity. 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."},"type":{"const":"unit","example":"unit","type":"string"}},"type":"object"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"type":{"description":"Same as `product.type`.","type":"string"},"weight":{"additionalProperties":true,"description":"The order line's weight (`_meta.total`, `_meta.unit`).","type":"object"}},"type":"object"},"type":"array"},{"type":"null"}]},"is_position_sorted":{"description":"Whether any position changed.","type":"boolean"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Fix up shipment line positions","tags":["Shipment line items"],"x-yoprint-docs":{"errors":[{"fix":"Send line hash ids.","status":422,"when":"An id that isn't a hash id (`validation_failed`)."},{"fix":"Send the line's `id`.","status":500,"when":"A line unique key (`shpitm_...`) instead of a hash id."},{"fix":"Ask the team owner to adjust your role or assign you to the order.","status":403,"when":"Your role can't edit this order."},{"fix":"Check the id.","status":404,"when":"The shipment isn't your team's."}],"group":"Shipping","permission":"Needs permission to edit the shipment's order: the team owner, a role whose Manage Sales Orders permission is \"update all\", or \"update assigned\" when you created the order or are assigned to it, or, on a draft order, its creator when their role can create sales orders. Otherwise 403 `user_is_not_authorized`. Reading needs only team membership.","related":["v2_public_shipment_item_update","v2_public_shipment_item_index"],"rules":["Hash ids only in `previous`, `current` and `next`: a unique key passes validation but fails with 500."],"side_effects":["Open Admin Portal pages, and Customer Portal pages the order's customer has open, refresh when positions change."]}}},"/v2/api/store/{team_slug}/v2/shipment/{unique_key}/package/bulk":{"post":{"description":"Changes the status of, or deletes, several packages of one shipment in one transaction: all of them, or none. Deletes run first and void Shippo labels as Delete a package does. Returns only the packages you touched, each with its `bid` and `action_performed` (`UPDATED` or `DELETED`).","operationId":"v2_public_shipment_package_bulk","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipment's `id` (a hash id), as its answers show it. Its unique key (`shp_...`) also works, but API answers don't include it.","example":"MQyJUnd3oty75h","in":"path","name":"unique_key","required":true,"schema":{"example":"MQyJUnd3oty75h","type":"string"}}],"requestBody":{"content":{"application/json":{"example":[{"action":"update","bid":"p1","payload":{"status":"shipped"},"shipment_package_id":"o6foWpSAayc79D"},{"action":"delete","bid":"p2","shipment_package_id":"UDsG6yjZAVrRNv"}],"schema":{"items":{"properties":{"action":{"description":"There is no create: packages come from labels.","enum":["update","delete"],"type":"string"},"bid":{"description":"Your label for this action.","type":"string"},"payload":{"description":"Required for `update`.","properties":{"status":{"description":"Pending, Ready to Ship, Shipped or Delivered.","enum":["pending","ready-to-ship","shipped","delivered"],"type":"string"}},"required":["status"],"type":"object"},"shipment_package_id":{"description":"A package of this shipment.","example":"V4keXwwxMQyXw7","type":"string"}},"required":["bid","action","shipment_package_id"],"type":"object"},"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"action_performed":"UPDATED","bid":"p1","has_changes":true,"item":{"charges":12400,"created_at":"2026-11-03T15:00:00+00:00","goshippo":{"parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"provider":"USPS","rate_id":"rate_0001"},"height":"4","id":"o6foWpSAayc79D","is_master":true,"length":"12","length_unit":"IN","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","parent_id":null,"pdf":[{"description":"Postage label individually to be printed 4\" x 6\" label","label":"Postage Label (4 in x 6 in label)","url":"https://example.com/labels/o6foWpSAayc79D.pdf"}],"provider_name":"USPS","provider_saturday_delivery":false,"provider_service_code":null,"provider_service_name":"Ground Advantage","provider_shipment_id":"transaction_0001","provider_tracking_number":"9400100000000000000000","shipment_has_third_party_fulfilled_items":false,"shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","status":"shipped","type":"goshippo","weight":"2","weight_unit":"LB","width":"10"},"lock_version":{"shipment":{"shipment_item_lock_version":1730000000000000,"shipment_lock_version":1730000000000000}},"object_type":"shipment_package"},{"action_performed":"DELETED","bid":"p2","has_changes":true,"item":{"charges":12400,"created_at":"2026-11-03T15:00:00+00:00","goshippo":{"parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"provider":"USPS","rate_id":"rate_0001"},"height":"4","id":"UDsG6yjZAVrRNv","is_master":true,"length":"12","length_unit":"IN","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","parent_id":null,"pdf":[{"description":"Postage label individually to be printed 4\" x 6\" label","label":"Postage Label (4 in x 6 in label)","url":"https://example.com/labels/o6foWpSAayc79D.pdf"}],"provider_name":"USPS","provider_saturday_delivery":false,"provider_service_code":null,"provider_service_name":"Ground Advantage","provider_shipment_id":"transaction_0003","provider_tracking_number":"9400100000000000000001","shipment_has_third_party_fulfilled_items":false,"shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","status":"pending","type":"goshippo","weight":"2","weight_unit":"LB","width":"10"},"lock_version":{"shipment":{"shipment_item_lock_version":1730000000000000,"shipment_lock_version":1730000000000000}},"object_type":"shipment_package"}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"The packages you touched.","items":{"additionalProperties":true,"properties":{"action_performed":{"enum":["UPDATED","DELETED"],"type":"string"},"bid":{"description":"Your label from the request.","type":"string"},"has_changes":{"type":"boolean"},"item":{"additionalProperties":true,"description":"A package.","properties":{"charges":{"description":"The label cost. For a multi-parcel label every package repeats the rate's full amount: read the master's value and don't add packages up. Null for external labels. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12400,"type":["integer","number","string","null"]},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"from_address":{"description":"The address record behind `from_address_id`, or null when it is not set."},"from_address_id":{"description":"Older packages only: the ship-from address record; null otherwise.","example":null,"type":["string","null"]},"goshippo":{"additionalProperties":true,"description":"Shippo labels only: the Shippo details (shipment, rate, carrier, addresses, parcels).","properties":{"address_from":{"description":"The ship-from address sent to Shippo."},"address_return":{"description":"The return address sent to Shippo."},"address_to":{"description":"The ship-to address sent to Shippo."},"carrier_id":{"description":"The Shippo carrier account.","type":["string","null"]},"parcel_id":{"description":"The Shippo parcel.","type":["string","null"]},"parcels":{"description":"The parcels of the Shippo shipment."},"provider":{"type":["string","null"]},"provider_image_200":{"type":["string","null"]},"provider_image_75":{"type":["string","null"]},"provider_tracking_number":{"type":["string","null"]},"rate_id":{"description":"The Shippo rate bought.","type":["string","null"]},"shipment_data":{"description":"The Shippo shipment the rate came from."},"shipment_id":{"description":"The Shippo shipment.","type":["string","null"]}},"type":"object"},"height":{"description":"Parcel size and weight as stored, in `length_unit` and `weight_unit`. Null for external labels.","type":["number","string","null"]},"id":{"description":"The package.","example":"o6foWpSAayc79D","type":"string"},"is_master":{"description":"The first package of a label (the others have `parent_id`).","type":"boolean"},"length":{"type":["number","string","null"]},"length_unit":{"description":"Shippo labels only, upper case.","example":"IN","type":["string","null"]},"order_external_ids":{"description":"The order's links to external systems.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_external_type":{"description":"`shopify` when the order came from Shopify.","type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"example":"sales_order","type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"parent_id":{"description":"The master package, for the other parcels of a multi-parcel label.","example":null,"type":["string","null"]},"pdf":{"description":"Not on external labels: the label file. `label` and `description` are fixed texts that always say 4 x 6, whatever your label size setting.","items":{"additionalProperties":true,"properties":{"description":{"example":"Postage label individually to be printed 4\" x 6\" label","type":"string"},"label":{"example":"Postage Label (4 in x 6 in label)","type":"string"},"url":{"description":"For a Shippo label, Shippo's signed link to the label file: don't publish it.","type":"string"}},"type":"object"},"type":"array"},"provider_name":{"description":"The carrier.","example":"USPS","type":["string","null"]},"provider_saturday_delivery":{"description":"Shippo labels only (absent on external labels); always false today.","type":"boolean"},"provider_service_code":{"description":"For external labels, `ups`, `fedex` or `other`. For Shippo labels it may be null: read the service from `provider_service_name`.","type":["string","null"]},"provider_service_name":{"example":"Ground Advantage","type":["string","null"]},"provider_shipment_id":{"description":"The Shippo transaction id (Shippo labels).","type":["string","null"]},"provider_tracking_number":{"example":"9400100000000000000000","type":["string","null"]},"shipment_external_type":{"description":"`shopify` when the shipment is linked to Shopify.","type":["string","null"]},"shipment_has_third_party_fulfilled_items":{"type":"boolean"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":"string"},"shipment_shopify_sync":{"description":"Shopify sync state of the shipment."},"status":{"enum":["pending","ready-to-ship","shipped","delivered"],"example":"pending","type":"string"},"to_address":{"description":"The address record behind `to_address_id`, or null when it is not set."},"to_address_id":{"description":"Older packages only: the ship-to address record; null otherwise.","example":null,"type":["string","null"]},"type":{"description":"`goshippo` a label bought through Shippo; `external_label` a label recorded from elsewhere.","enum":["goshippo","external_label","single_label"],"example":"goshippo","type":"string"},"weight":{"type":["number","string","null"]},"weight_unit":{"description":"Shippo labels only, upper case.","example":"LB","type":["string","null"]},"width":{"type":["number","string","null"]}},"type":"object"},"lock_version":{"additionalProperties":true,"description":"Lock versions after the change (no `order` key here).","properties":{"shipment":{"additionalProperties":true,"description":"The shipment's lock versions: `shipment_item_lock_version`, `shipment_lock_version`.","type":"object"}},"type":"object"},"object_type":{"const":"shipment_package","example":"shipment_package","type":"string"}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/BulkValidationPayloadResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change and delete packages at once","tags":["Shipment packages"],"x-yoprint-docs":{"errors":[{"fix":"Fix the named action and resend the whole array.","status":422,"when":"A bad `status` (`bulk_validation_payload_failed`), a duplicate or foreign package, or a refused delete; nothing is saved."},{"fix":"Ask the team owner for permission to view this order, or to be assigned to it.","status":403,"when":"Your role can't view the shipment's order (`user_is_not_authorized`). Nothing is saved."},{"fix":"Check the id.","status":404,"when":"The shipment isn't your team's."}],"group":"Shipping","permission":"Needs permission to view the shipment's order: the team owner, a role whose Manage Sales Orders permission is \"view all\", or \"view assigned\" when you created the order or are assigned to it. Otherwise 403 `user_is_not_authorized`. Edit rights are not needed, so a role that can only view orders can do this too. This applies even when every action is an `update`; Change a package's status alone checks no role.","related":["v2_public_shipment_package_update","v2_public_shipment_package_destroy"],"rules":["One action per package: a second is 422 `cart_item_validation_error` with `error.context.reason` `duplicate_item_action` and `error.bid`. A package not on this shipment: the same code with reason `item_not_available`.","The draft rule and the Shopify lock rules of Delete a package apply to each delete; the third-party-fulfilment check does not."],"side_effects":["Requests Shippo refunds for deleted Shippo labels, in the background. Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open."]}}},"/v2/api/store/{team_slug}/v2/shipment_estimate/{hash_id}":{"delete":{"description":"Deletes a saved shipping estimate. Nothing is sent to Shippo, and shipment lines that bill for the estimate are left as they are.","operationId":"v2_public_shipment_estimate_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipping estimate's hash id. Hash ids only: a unique key or a document number gives 404.","example":"tVjoZLKlSwZFF5","in":"path","name":"hash_id","required":true,"schema":{"example":"tVjoZLKlSwZFF5","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a shipping estimate","tags":["Shipping rates and estimates"],"x-yoprint-docs":{"errors":[{"fix":"Treat a 404 on a repeat delete as done.","status":404,"when":"The estimate isn't your team's, or is already deleted."}],"group":"Shipping","permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_shipment_estimate_index"],"side_effects":["Open Admin Portal pages refresh."]}},"get":{"description":"Returns one saved shipping estimate: its shipment and order, the Shippo shipment and selected rate ids, and the stored addresses, parcels and rates. Doesn't call Shippo.","operationId":"v2_public_shipment_estimate_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The shipping estimate's hash id. Hash ids only: a unique key or a document number gives 404.","example":"tVjoZLKlSwZFF5","in":"path","name":"hash_id","required":true,"schema":{"example":"tVjoZLKlSwZFF5","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"created_at":"2026-11-03T15:00:00+00:00","frontend_data":[],"frontend_data_version":null,"goshippo_selected_rate_id":"rate_0001","goshippo_shipment_id":"shipment_0001","id":"tVjoZLKlSwZFF5","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","shippo_address_from":{"city":"Austin","company":"","country":"US","email":"","name":"Northwind Apparel","phone":"+1 201 555 0123","state":"TX","street1":"100 Example Street","street2":"","zip":"78701"},"shippo_address_to":{"city":"Denver","company":"","country":"US","email":"alex@example.com","name":"Alex Rivera","phone":"","state":"CO","street1":"100 Example Street","street2":"","zip":"80202"},"shippo_carrier_accounts":[],"shippo_extra":null,"shippo_object_id":"shipment_0001","shippo_parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"shippo_rates":[{"amount":"12.40","amount_local":"12.40","arrives_by":null,"attributes":["CHEAPEST"],"carrier_account":"carrier_0001","currency":"USD","currency_local":"USD","duration_terms":"Delivery in 2 to 5 days.","estimated_days":3,"included_insurance_price":null,"messages":[],"object_created":"2026-11-03T15:00:00Z","object_id":"rate_0001","object_updated":"2026-11-03T15:00:00Z","provider":"USPS","provider_image_200":"https://example.com/usps_200.png","provider_image_75":"https://example.com/usps_75.png","servicelevel":{"extended_token":"usps_ground_advantage","name":"Ground Advantage","terms":"","token":"usps_ground_advantage"},"shipment":"shipment_0001"}],"shippo_shipment_date":"2026-11-03T15:00:00Z","shippo_status":"SUCCESS","type":"integration_shippo"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A saved shipping estimate.","properties":{"created_at":{"format":"date-time","type":"string"},"frontend_data":{"description":"What you sent as `frontend_data`; an empty list `[]` when you sent none.","type":["object","array"]},"frontend_data_version":{"description":"What you sent, or null."},"goshippo_selected_rate_id":{"description":"The rate chosen when it was saved.","example":"rate_0001","type":["string","null"]},"goshippo_shipment_id":{"description":"The Shippo shipment.","example":"shipment_0001","type":["string","null"]},"id":{"description":"The estimate.","example":"tVjoZLKlSwZFF5","type":"string"},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":["string","null"]},"shippo_address_from":{"additionalProperties":true,"type":"object"},"shippo_address_to":{"additionalProperties":true,"type":"object"},"shippo_carrier_accounts":{"items":{"type":"string"},"type":"array"},"shippo_extra":{"description":"The label options, or null."},"shippo_object_id":{"type":["string","null"]},"shippo_parcels":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"shippo_rates":{"description":"Every rate of that Shippo shipment, as saved (`amount` is a decimal string).","items":{"additionalProperties":true,"description":"A rate, with exactly these keys. Keys Shippo leaves out come back as empty strings.","properties":{"amount":{"example":"12.40","type":"string"},"amount_local":{"example":"12.40","type":"string"},"arrives_by":{"example":null,"type":["string","null"]},"attributes":{"description":"Shippo's tags, for example `CHEAPEST`.","example":["CHEAPEST"],"items":{"type":"string"},"type":"array"},"carrier_account":{"example":"carrier_0001","type":"string"},"currency":{"example":"USD","type":"string"},"currency_local":{"example":"USD","type":"string"},"duration_terms":{"example":"Delivery in 2 to 5 days.","type":["string","null"]},"estimated_days":{"example":3,"type":["integer","null"]},"included_insurance_price":{"example":null,"type":["string","null"]},"messages":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"object_created":{"example":"2026-11-03T15:00:00Z","type":"string"},"object_id":{"description":"The rate id. Send it as `rate_id` to buy this label.","example":"rate_0001","type":"string"},"object_updated":{"example":"2026-11-03T15:00:00Z","type":"string"},"provider":{"example":"USPS","type":"string"},"provider_image_200":{"example":"https://example.com/usps_200.png","type":"string"},"provider_image_75":{"description":"A URL of the carrier logo.","example":"https://example.com/usps_75.png","type":"string"},"servicelevel":{"additionalProperties":false,"description":"Exactly these four keys; null when Shippo sends no service level.","properties":{"extended_token":{"example":"usps_ground_advantage","type":"string"},"name":{"example":"Ground Advantage","type":"string"},"terms":{"example":"","type":"string"},"token":{"example":"usps_ground_advantage","type":"string"}},"type":"object"},"shipment":{"description":"The Shippo shipment this rate belongs to.","example":"shipment_0001","type":"string"}},"type":"object"},"type":"array"},"shippo_shipment_date":{"type":["string","null"]},"shippo_status":{"example":"SUCCESS","type":["string","null"]},"type":{"example":"integration_shippo","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a shipping estimate","tags":["Shipping rates and estimates"],"x-yoprint-docs":{"errors":[{"fix":"Check the id.","status":404,"when":"The estimate isn't your team's, or was deleted."}],"group":"Shipping","permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_shipment_estimate_index","v2_public_shipment_estimate_destroy"]}}},"/v2/api/store/{team_slug}/v2/shipment_package/labels/compile":{"post":{"description":"Merges the label files of up to 40 Shippo packages into one PDF (`compiled-labels.pdf`, shown inline), ready to print. Nothing is bought. Packages without a Shippo label (external, deleted or unknown ids) are skipped.","operationId":"v2_public_shipment_label_compile_goshippo","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"shipment_package_ids":["o6foWpSAayc79D","UDsG6yjZAVrRNv"]},"schema":{"properties":{"shipment_package_ids":{"description":"Package hash ids (`id` from List the packages of a shipment). Packages have no unique keys. A string of digits is read as an internal numeric id, not a hash id; anything else is skipped.","items":{"type":"string"},"maxItems":40,"minItems":1,"type":"array"}},"required":["shipment_package_ids"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"The merged labels as a PDF, shown inline (`Content-Disposition: inline`)."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Download labels as one PDF","tags":["Shipping labels"],"x-yoprint-docs":{"errors":[{"fix":"Send ids of packages bought with Buy a shipping label.","status":422,"when":"None of the ids is a live Shippo package (`no_goshippo_labels`)."},{"fix":"Leave out the listed packages and try again.","status":422,"when":"A package has no label file (`label_fetch_failed`, with `{ id, reason }` rows in `error.failed_packages`)."},{"fix":"Try again in a moment. If it keeps failing, open each label from its package's `pdf` link.","status":422,"when":"The merge failed (`pdf_merge_failed`). This includes a label link that fails YoPrint's link check before the merge (it must be an http or https link whose host resolves only to public addresses): the message is \"One or more labels couldn't be fetched from the carrier. Try again in a moment, or open each label from its package.\", `error.refused_label_hosts` lists the hosts, and no PDF is made rather than one with fewer labels."},{"fix":"Split the list into calls of 40.","status":422,"when":"More than 40 ids, or none (`validation_failed`)."}],"group":"Shipping","permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_shipment_label_create_goshippo","v2_public_shipment_package_index"],"rules":["1 to 40 ids per call.","The pages follow the stored package order, not the order you sent."]}}},"/v2/api/store/{team_slug}/v2/shipment_package/{hash_id}":{"delete":{"description":"Deletes a package. For a Shippo label this is how you void it: YoPrint asks Shippo for a refund in the background, and a refused refund is not reported back. Shippo and the carrier decide whether you get the money back.\n\nIn a multi-parcel label, deleting the master makes the next parcel the master; deleting one parcel voids only that parcel. A shipping cost line tied to the package is not removed: when you delete a master that has other parcels, the cost line moves to the new master and keeps billing; otherwise it stays linked to the deleted package. Remove it yourself if you no longer bill it.","operationId":"v2_public_shipment_package_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The package's hash id. Hash ids only: a unique key or a document number gives 404.","example":"o6foWpSAayc79D","in":"path","name":"hash_id","required":true,"schema":{"example":"o6foWpSAayc79D","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a package (voids its label)","tags":["Shipment packages"],"x-yoprint-docs":{"errors":[{"fix":"Publish the order, or void the fulfillment in Shopify first.","status":422,"when":"A draft order, or a Shopify rule (see rules)."},{"fix":"Ask the team owner for permission to view this order, or to be assigned to it.","status":403,"when":"Your role can't view the order of the package's shipment (`user_is_not_authorized`). Nothing is deleted or refunded."},{"fix":"Check the id.","status":404,"when":"The package isn't your team's."}],"group":"Shipping","permission":"Needs permission to view the shipment's order: the team owner, a role whose Manage Sales Orders permission is \"view all\", or \"view assigned\" when you created the order or are assigned to it. Otherwise 403 `user_is_not_authorized`. Edit rights are not needed, so a role that can only view orders can do this too.","related":["v2_public_shipment_package_index","v2_public_shipment_label_create_goshippo"],"rules":["On a draft order, a package with a label can't be deleted: \"Publish this order before deleting a shipment package with a shipping label.\"","On a shipment linked to Shopify: 422 `shopify_managed_shipment_locked` (\"Cannot modify Shopify-managed shipment packages from API.\"), `shopify_fulfilled_shipment_package_locked` (\"This shipment has already been fulfilled to Shopify. Void fulfillment first to edit packages or create labels.\") or `shopify_broken_link_shipment_locked`; and 422 \"Shipment package cannot be deleted because shipment contains items fulfilled by a third-party.\" (`error.code` `validation_error`). There is no carrier check here."],"side_effects":["Requests a refund from Shippo for a Shippo label, in the background.","Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open."]}},"get":{"description":"Returns one package: carrier, service, tracking number, size, weight, `charges` (in thousandths), `status`, whether it is the master of a multi-parcel label, and for Shippo labels the Shippo details and label file.","operationId":"v2_public_shipment_package_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The package's hash id. Hash ids only: a unique key or a document number gives 404.","example":"o6foWpSAayc79D","in":"path","name":"hash_id","required":true,"schema":{"example":"o6foWpSAayc79D","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"charges":12400,"created_at":"2026-11-03T15:00:00+00:00","goshippo":{"parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"provider":"USPS","rate_id":"rate_0001"},"height":"4","id":"o6foWpSAayc79D","is_master":true,"length":"12","length_unit":"IN","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","parent_id":null,"pdf":[{"description":"Postage label individually to be printed 4\" x 6\" label","label":"Postage Label (4 in x 6 in label)","url":"https://example.com/labels/o6foWpSAayc79D.pdf"}],"provider_name":"USPS","provider_saturday_delivery":false,"provider_service_code":null,"provider_service_name":"Ground Advantage","provider_shipment_id":"transaction_0001","provider_tracking_number":"9400100000000000000000","shipment_has_third_party_fulfilled_items":false,"shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","status":"pending","type":"goshippo","weight":"2","weight_unit":"LB","width":"10"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A package.","properties":{"charges":{"description":"The label cost. For a multi-parcel label every package repeats the rate's full amount: read the master's value and don't add packages up. Null for external labels. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12400,"type":["integer","number","string","null"]},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"from_address":{"description":"The address record behind `from_address_id`, or null when it is not set."},"from_address_id":{"description":"Older packages only: the ship-from address record; null otherwise.","example":null,"type":["string","null"]},"goshippo":{"additionalProperties":true,"description":"Shippo labels only: the Shippo details (shipment, rate, carrier, addresses, parcels).","properties":{"address_from":{"description":"The ship-from address sent to Shippo."},"address_return":{"description":"The return address sent to Shippo."},"address_to":{"description":"The ship-to address sent to Shippo."},"carrier_id":{"description":"The Shippo carrier account.","type":["string","null"]},"parcel_id":{"description":"The Shippo parcel.","type":["string","null"]},"parcels":{"description":"The parcels of the Shippo shipment."},"provider":{"type":["string","null"]},"provider_image_200":{"type":["string","null"]},"provider_image_75":{"type":["string","null"]},"provider_tracking_number":{"type":["string","null"]},"rate_id":{"description":"The Shippo rate bought.","type":["string","null"]},"shipment_data":{"description":"The Shippo shipment the rate came from."},"shipment_id":{"description":"The Shippo shipment.","type":["string","null"]}},"type":"object"},"height":{"description":"Parcel size and weight as stored, in `length_unit` and `weight_unit`. Null for external labels.","type":["number","string","null"]},"id":{"description":"The package.","example":"o6foWpSAayc79D","type":"string"},"is_master":{"description":"The first package of a label (the others have `parent_id`).","type":"boolean"},"length":{"type":["number","string","null"]},"length_unit":{"description":"Shippo labels only, upper case.","example":"IN","type":["string","null"]},"order_external_ids":{"description":"The order's links to external systems.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_external_type":{"description":"`shopify` when the order came from Shopify.","type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"example":"sales_order","type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"parent_id":{"description":"The master package, for the other parcels of a multi-parcel label.","example":null,"type":["string","null"]},"pdf":{"description":"Not on external labels: the label file. `label` and `description` are fixed texts that always say 4 x 6, whatever your label size setting.","items":{"additionalProperties":true,"properties":{"description":{"example":"Postage label individually to be printed 4\" x 6\" label","type":"string"},"label":{"example":"Postage Label (4 in x 6 in label)","type":"string"},"url":{"description":"For a Shippo label, Shippo's signed link to the label file: don't publish it.","type":"string"}},"type":"object"},"type":"array"},"provider_name":{"description":"The carrier.","example":"USPS","type":["string","null"]},"provider_saturday_delivery":{"description":"Shippo labels only (absent on external labels); always false today.","type":"boolean"},"provider_service_code":{"description":"For external labels, `ups`, `fedex` or `other`. For Shippo labels it may be null: read the service from `provider_service_name`.","type":["string","null"]},"provider_service_name":{"example":"Ground Advantage","type":["string","null"]},"provider_shipment_id":{"description":"The Shippo transaction id (Shippo labels).","type":["string","null"]},"provider_tracking_number":{"example":"9400100000000000000000","type":["string","null"]},"shipment_external_type":{"description":"`shopify` when the shipment is linked to Shopify.","type":["string","null"]},"shipment_has_third_party_fulfilled_items":{"type":"boolean"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":"string"},"shipment_shopify_sync":{"description":"Shopify sync state of the shipment."},"status":{"enum":["pending","ready-to-ship","shipped","delivered"],"example":"pending","type":"string"},"to_address":{"description":"The address record behind `to_address_id`, or null when it is not set."},"to_address_id":{"description":"Older packages only: the ship-to address record; null otherwise.","example":null,"type":["string","null"]},"type":{"description":"`goshippo` a label bought through Shippo; `external_label` a label recorded from elsewhere.","enum":["goshippo","external_label","single_label"],"example":"goshippo","type":"string"},"weight":{"type":["number","string","null"]},"weight_unit":{"description":"Shippo labels only, upper case.","example":"LB","type":["string","null"]},"width":{"type":["number","string","null"]}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a package","tags":["Shipment packages"],"x-yoprint-docs":{"errors":[{"fix":"Check the id.","status":404,"when":"The package isn't your team's."}],"group":"Shipping","permission":"Any member of the team.","related":["v2_public_shipment_package_update","v1_public_shipment_package_track"]}},"put":{"description":"Sets a package's status. That is the only field you can change. Returns the package.\n\nThe shipment's own status doesn't follow: change it with Change the status of a shipment. Nothing is sent to the customer and no webhook fires.","operationId":"v2_public_shipment_package_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The package's hash id. Hash ids only: a unique key or a document number gives 404.","example":"o6foWpSAayc79D","in":"path","name":"hash_id","required":true,"schema":{"example":"o6foWpSAayc79D","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"status":"shipped"},"schema":{"properties":{"status":{"description":"Pending, Ready to Ship, Shipped or Delivered.","enum":["pending","ready-to-ship","shipped","delivered"],"type":"string"}},"required":["status"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"charges":12400,"created_at":"2026-11-03T15:00:00+00:00","goshippo":{"parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"provider":"USPS","rate_id":"rate_0001"},"height":"4","id":"o6foWpSAayc79D","is_master":true,"length":"12","length_unit":"IN","order_id":"sFbALVSYD55eXe","order_object_type":"sales_order","order_quote":false,"order_scoped_id":"SO1001","parent_id":null,"pdf":[{"description":"Postage label individually to be printed 4\" x 6\" label","label":"Postage Label (4 in x 6 in label)","url":"https://example.com/labels/o6foWpSAayc79D.pdf"}],"provider_name":"USPS","provider_saturday_delivery":false,"provider_service_code":null,"provider_service_name":"Ground Advantage","provider_shipment_id":"transaction_0001","provider_tracking_number":"9400100000000000000000","shipment_has_third_party_fulfilled_items":false,"shipment_id":"MQyJUnd3oty75h","shipment_scoped_id":"SHIP-12","status":"shipped","type":"goshippo","weight":"2","weight_unit":"LB","width":"10"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A package.","properties":{"charges":{"description":"The label cost. For a multi-parcel label every package repeats the rate's full amount: read the master's value and don't add packages up. Null for external labels. Thousandths, an older encoding: `12500` is 12.50. Usually a whole number; an amount finer than a thousandth comes back as a number with a fraction (`1234.5` is 1.2345), or as a string (`\"1234.5\"`) when you send `X-Yoprint-Decimal-Format: exact-v1`. See [Money and quantities](/concepts/money-and-quantities/).","example":12400,"type":["integer","number","string","null"]},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"from_address":{"description":"The address record behind `from_address_id`, or null when it is not set."},"from_address_id":{"description":"Older packages only: the ship-from address record; null otherwise.","example":null,"type":["string","null"]},"goshippo":{"additionalProperties":true,"description":"Shippo labels only: the Shippo details (shipment, rate, carrier, addresses, parcels).","properties":{"address_from":{"description":"The ship-from address sent to Shippo."},"address_return":{"description":"The return address sent to Shippo."},"address_to":{"description":"The ship-to address sent to Shippo."},"carrier_id":{"description":"The Shippo carrier account.","type":["string","null"]},"parcel_id":{"description":"The Shippo parcel.","type":["string","null"]},"parcels":{"description":"The parcels of the Shippo shipment."},"provider":{"type":["string","null"]},"provider_image_200":{"type":["string","null"]},"provider_image_75":{"type":["string","null"]},"provider_tracking_number":{"type":["string","null"]},"rate_id":{"description":"The Shippo rate bought.","type":["string","null"]},"shipment_data":{"description":"The Shippo shipment the rate came from."},"shipment_id":{"description":"The Shippo shipment.","type":["string","null"]}},"type":"object"},"height":{"description":"Parcel size and weight as stored, in `length_unit` and `weight_unit`. Null for external labels.","type":["number","string","null"]},"id":{"description":"The package.","example":"o6foWpSAayc79D","type":"string"},"is_master":{"description":"The first package of a label (the others have `parent_id`).","type":"boolean"},"length":{"type":["number","string","null"]},"length_unit":{"description":"Shippo labels only, upper case.","example":"IN","type":["string","null"]},"order_external_ids":{"description":"The order's links to external systems.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"order_external_type":{"description":"`shopify` when the order came from Shopify.","type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_object_type":{"example":"sales_order","type":["string","null"]},"order_quote":{"type":"boolean"},"order_scoped_id":{"example":"SO1001","type":["string","null"]},"parent_id":{"description":"The master package, for the other parcels of a multi-parcel label.","example":null,"type":["string","null"]},"pdf":{"description":"Not on external labels: the label file. `label` and `description` are fixed texts that always say 4 x 6, whatever your label size setting.","items":{"additionalProperties":true,"properties":{"description":{"example":"Postage label individually to be printed 4\" x 6\" label","type":"string"},"label":{"example":"Postage Label (4 in x 6 in label)","type":"string"},"url":{"description":"For a Shippo label, Shippo's signed link to the label file: don't publish it.","type":"string"}},"type":"object"},"type":"array"},"provider_name":{"description":"The carrier.","example":"USPS","type":["string","null"]},"provider_saturday_delivery":{"description":"Shippo labels only (absent on external labels); always false today.","type":"boolean"},"provider_service_code":{"description":"For external labels, `ups`, `fedex` or `other`. For Shippo labels it may be null: read the service from `provider_service_name`.","type":["string","null"]},"provider_service_name":{"example":"Ground Advantage","type":["string","null"]},"provider_shipment_id":{"description":"The Shippo transaction id (Shippo labels).","type":["string","null"]},"provider_tracking_number":{"example":"9400100000000000000000","type":["string","null"]},"shipment_external_type":{"description":"`shopify` when the shipment is linked to Shopify.","type":["string","null"]},"shipment_has_third_party_fulfilled_items":{"type":"boolean"},"shipment_id":{"description":"The shipment.","example":"MQyJUnd3oty75h","type":"string"},"shipment_scoped_id":{"example":"SHIP-12","type":"string"},"shipment_shopify_sync":{"description":"Shopify sync state of the shipment."},"status":{"enum":["pending","ready-to-ship","shipped","delivered"],"example":"pending","type":"string"},"to_address":{"description":"The address record behind `to_address_id`, or null when it is not set."},"to_address_id":{"description":"Older packages only: the ship-to address record; null otherwise.","example":null,"type":["string","null"]},"type":{"description":"`goshippo` a label bought through Shippo; `external_label` a label recorded from elsewhere.","enum":["goshippo","external_label","single_label"],"example":"goshippo","type":"string"},"weight":{"type":["number","string","null"]},"weight_unit":{"description":"Shippo labels only, upper case.","example":"LB","type":["string","null"]},"width":{"type":["number","string","null"]}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change a package's status","tags":["Shipment packages"],"x-yoprint-docs":{"errors":[{"fix":"Send one of `pending`, `ready-to-ship`, `shipped`, `delivered`.","status":422,"when":"`status` is missing or not one of the four values, or a Shopify rule refuses the change."},{"fix":"Check the id.","status":404,"when":"The package isn't your team's."}],"group":"Shipping","permission":"Any member of the team.","related":["v2_public_shipment_package_show","v2_public_shipment_package_bulk","v2_public_sales_order_shipment_change_status"],"rules":["On a shipment linked to Shopify: 422 `shopify_managed_shipment_locked` (\"Cannot modify Shopify-managed shipment packages from API.\"), `shopify_fulfilled_shipment_package_locked` (\"This shipment has already been fulfilled to Shopify. Void fulfillment first to edit packages or create labels.\") or `shopify_broken_link_shipment_locked`; and 422 \"Shipment package cannot be updated because shipment contains items fulfilled by a third-party.\" (`error.code` `validation_error`). There is no carrier check here."],"side_effects":["Open Admin Portal pages refresh, and so do Customer Portal pages the order's customer has open."]}}},"/v2/api/store/{team_slug}/v2/shipment_rate/goshippo":{"post":{"description":"Asks Shippo for the rates to ship parcels between two addresses. Nothing is bought, and nothing is saved in YoPrint. Shippo keeps the request as a Shippo shipment in your Shippo account.\n\nThe reply is a trimmed copy of Shippo's shipment, without the usual `success`/`data` envelope, with HTTP 201. It has only these keys: `object_id`, `status`, `rates`, `messages`, `address_from`, `address_to`, `parcels`, `extra` (only `reference_1`, `billing`, `insurance`, `signature_confirmation`, `saturday_delivery`), `shipment_date` and `carrier_accounts`. The top-level `object_id` is the Shippo shipment, and each `rates[].object_id` is a rate you can buy with Buy a shipping label.\n\nOptions you want on the label (insurance, signature, Saturday delivery, third-party billing, references) go in `extra` here: the purchase can't change them.\n\nWhere the addresses come from. Rates are not tied to the YoPrint shipment: you send both addresses and the parcels yourself, YoPrint doesn't compare them with the shipment, and the label is bought for the rate's addresses and parcels. Build them the way the web app does. A shipment returns only ids (`customer_id`, `shipping_address_id`, `receiver_contact_id`, `customer_profile_id`), so read the records behind them:\n\n- **Ship To** (`address_to`): Get a customer address, `GET /v1/api/store/{team_slug}/customer/{customer_id}/address/{shipping_address_id}`; and, when the shipment has one, the receiver contact with Get a contact by id, `GET /v1/api/store/{team_slug}/contact/{receiver_contact_id}`.\n- **Ship From** (`address_from`): when `customer_profile_id` is set, the brand profile with Get a brand profile, `GET /v1/api/store/{team_slug}/customer/{customer_id}/profile/{customer_profile_id}` (its `address` is the Ship From address); otherwise one of your company locations (List company locations), with your team's `email` and `phone` from Get your company details.\n\n| Shippo field | `address_to` | `address_from` |\n| --- | --- | --- |\n| `name` | receiver contact `first_name` + `last_name`; else the address `label`; else the customer's name | brand profile `company_name`; else the location `label` |\n| `company` | the customer's name when it differs from `name`; empty when the shipment has a brand profile | empty |\n| `street1` | address `address1` | address `address1` |\n| `street2` | address `address2` | address `address2` |\n| `city` | address `city` | address `city` |\n| `state` | address `state_code` (or `state` when there is no code) | the same |\n| `zip` | address `postcode` | address `postcode` |\n| `country` | address `country_code` (or `country`) | the same |\n| `email` | receiver contact `email` | brand profile `email`; else the team's `email` |\n| `phone` | receiver contact `phone` | brand profile `phone`; else the team's `phone` |\n\nShippo needs `name`, `street1`, `city`, `state`, `zip` and `country` on both; company locations have no name or phone of their own.\n\nMoney here: a rate's `amount` is a decimal string in `currency` (`\"12.40\"`); parse it as a decimal. After purchase, each package's `charges` is that amount cut to 3 decimal places, in thousandths, an older encoding (`12400` is 12.40; usually a whole number of thousandths; a finer value comes back as a fractional number, or as an exact decimal string with `X-Yoprint-Decimal-Format: exact-v1`). On a multi-parcel label, every package repeats the rate's full amount: read the master package's value and don't add the packages up. See [Money and quantities](/concepts/money-and-quantities/).\n\nThe order of calls:\n\n1. Optional: List Shippo carrier accounts, to limit rates to some of your accounts.\n2. Get shipping rates with the addresses and parcels. Note the top-level `object_id` (the Shippo shipment) and the chosen rate's `object_id` (`rates[].object_id`).\n3. Optional: Save a shipping estimate on the YoPrint shipment, to keep the quote.\n4. Buy a shipping label with the rate's `object_id` as `rate_id`. This is the only step that costs money.\n5. Print: Download labels as one PDF. Track: Get live tracking for a package.","operationId":"v2_public_shipment_rate_goshippo","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"address_from":{"city":"Austin","country":"US","name":"Northwind Apparel","phone":"+1 201 555 0123","state":"TX","street1":"100 Example Street","zip":"78701"},"address_to":{"city":"Denver","country":"US","email":"alex@example.com","name":"Alex Rivera","state":"CO","street1":"100 Example Street","zip":"80202"},"extra":{"reference_1":"SO1001"},"parcels":[{"distance_unit":"in","height":4,"length":12,"mass_unit":"lb","weight":2,"width":10}]},"schema":{"properties":{"address_from":{"description":"Where the parcels ship from.","properties":{"city":{"maxLength":255,"type":"string"},"company":{"maxLength":255,"type":"string"},"country":{"description":"ISO country code, for example `US`. Upper-cased for you.","maxLength":50,"type":"string"},"email":{"format":"email","maxLength":255,"type":"string"},"name":{"maxLength":255,"type":"string"},"phone":{"maxLength":20,"type":"string"},"state":{"description":"State or province code. Upper-cased for you.","maxLength":50,"type":"string"},"street1":{"maxLength":255,"type":"string"},"street2":{"maxLength":255,"type":"string"},"validate":{"description":"Passed to Shippo: ask it to validate the address.","type":"boolean"},"zip":{"maxLength":20,"type":"string"}},"required":["name","street1","city","state","zip","country"],"type":"object"},"address_to":{"description":"Where they go.","properties":{"city":{"maxLength":255,"type":"string"},"company":{"maxLength":255,"type":"string"},"country":{"description":"ISO country code, for example `US`. Upper-cased for you.","maxLength":50,"type":"string"},"email":{"format":"email","maxLength":255,"type":"string"},"name":{"maxLength":255,"type":"string"},"phone":{"maxLength":20,"type":"string"},"state":{"description":"State or province code. Upper-cased for you.","maxLength":50,"type":"string"},"street1":{"maxLength":255,"type":"string"},"street2":{"maxLength":255,"type":"string"},"validate":{"description":"Passed to Shippo: ask it to validate the address.","type":"boolean"},"zip":{"maxLength":20,"type":"string"}},"required":["name","street1","city","state","zip","country"],"type":"object"},"async":{"default":false,"description":"Leave false. With `true` Shippo answers before it has rates; the only later read is Save a shipping estimate with the reply's `object_id`, which reads the shipment back with its rates.","type":"boolean"},"carrier_accounts":{"description":"Carrier account `object_id`s to rate. Omit to rate every active account.","items":{"maxLength":255,"type":"string"},"type":"array"},"extra":{"description":"Label options, passed on to Shippo. Other Shippo `extra` keys are passed on unchecked.","properties":{"billing":{"description":"Bill the shipment to another carrier account (third party or recipient). `account`, `country` and `type` are required when you send it.","properties":{"account":{"maxLength":255,"type":"string"},"country":{"maxLength":2,"minLength":2,"type":"string"},"participation_code":{"maxLength":255,"type":"string"},"type":{"example":"THIRD_PARTY","maxLength":50,"type":"string"},"zip":{"maxLength":20,"type":"string"}},"type":"object"},"insurance":{"description":"Insurance. `amount` and `currency` are required when you send it.","properties":{"amount":{"description":"The insured value as a plain decimal in `currency` (`200` or `\"200.00\"` is 200.00), passed to Shippo unchanged: not thousandths and not a decimal pair.","minimum":0,"type":["number","string"]},"content":{"maxLength":255,"type":"string"},"currency":{"maxLength":3,"minLength":3,"type":"string"},"provider":{"enum":["FEDEX","UPS","ONTRAC"],"type":"string"}},"type":"object"},"reference_1":{"maxLength":255,"type":"string"},"reference_2":{"maxLength":255,"type":"string"},"saturday_delivery":{"type":"boolean"},"signature_confirmation":{"enum":["STANDARD","ADULT","CERTIFIED","INDIRECT","CARRIER_CONFIRMATION"],"type":"string"}},"type":["object","null"]},"parcels":{"description":"One entry per box. More than one makes a multi-parcel shipment, bought as one rate.","items":{"properties":{"distance_unit":{"enum":["cm","in","ft","m","mm","yd"],"type":"string"},"extra":{"properties":{"insurance":{"description":"Insurance. `amount` and `currency` are required when you send it.","properties":{"amount":{"description":"The insured value as a plain decimal in `currency` (`200` or `\"200.00\"` is 200.00), passed to Shippo unchanged: not thousandths and not a decimal pair.","minimum":0,"type":["number","string"]},"content":{"maxLength":255,"type":"string"},"currency":{"maxLength":3,"minLength":3,"type":"string"},"provider":{"enum":["FEDEX","UPS","ONTRAC"],"type":"string"}},"type":"object"}},"type":"object"},"height":{"minimum":0.01,"type":["number","string"]},"length":{"description":"A plain number, or a numeric string (the web app sends `\"12\"`). At least 0.01.","minimum":0.01,"type":["number","string"]},"mass_unit":{"enum":["g","kg","lb","oz"],"type":"string"},"template":{"description":"A Shippo carrier parcel template token. The dimensions and weight are still required.","maxLength":255,"type":"string"},"weight":{"description":"A plain number or numeric string, in `mass_unit`.","minimum":0.01,"type":["number","string"]},"width":{"minimum":0.01,"type":["number","string"]}},"required":["length","width","height","distance_unit","weight","mass_unit"],"type":"object"},"minItems":1,"type":"array"},"shipment_date":{"description":"When you plan to hand the parcels over. Defaults to now.","format":"date-time","type":["string","null"]}},"required":["address_from","address_to","parcels"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"address_from":{"city":"Austin","company":"","country":"US","email":"","name":"Northwind Apparel","phone":"+1 201 555 0123","state":"TX","street1":"100 Example Street","street2":"","zip":"78701"},"address_to":{"city":"Denver","company":"","country":"US","email":"alex@example.com","name":"Alex Rivera","phone":"","state":"CO","street1":"100 Example Street","street2":"","zip":"80202"},"carrier_accounts":[],"extra":{"reference_1":"SO1001"},"messages":[],"object_id":"shipment_0001","parcels":[{"distance_unit":"in","height":"4","length":"12","mass_unit":"lb","weight":"2","width":"10"}],"rates":[{"amount":"12.40","amount_local":"12.40","arrives_by":null,"attributes":["CHEAPEST"],"carrier_account":"carrier_0001","currency":"USD","currency_local":"USD","duration_terms":"Delivery in 2 to 5 days.","estimated_days":3,"included_insurance_price":null,"messages":[],"object_created":"2026-11-03T15:00:00Z","object_id":"rate_0001","object_updated":"2026-11-03T15:00:00Z","provider":"USPS","provider_image_200":"https://example.com/usps_200.png","provider_image_75":"https://example.com/usps_75.png","servicelevel":{"extended_token":"usps_ground_advantage","name":"Ground Advantage","terms":"","token":"usps_ground_advantage"},"shipment":"shipment_0001"}],"shipment_date":"2026-11-03T15:00:00Z","status":"SUCCESS"},"schema":{"additionalProperties":true,"properties":{"address_from":{"additionalProperties":true,"description":"Exactly `name`, `company`, `city`, `country`, `email`, `phone`, `state`, `street1`, `street2`, `zip`; empty strings for what Shippo leaves out.","type":"object"},"address_to":{"additionalProperties":true,"description":"The same ten keys as `address_from`.","type":"object"},"carrier_accounts":{"items":{"type":"string"},"type":"array"},"extra":{"additionalProperties":true,"type":["object","null"]},"messages":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"object_id":{"description":"The Shippo shipment. Send it as `goshippo_shipment_id` to save an estimate.","type":"string"},"parcels":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"rates":{"items":{"additionalProperties":true,"description":"A rate, with exactly these keys. Keys Shippo leaves out come back as empty strings.","properties":{"amount":{"example":"12.40","type":"string"},"amount_local":{"example":"12.40","type":"string"},"arrives_by":{"example":null,"type":["string","null"]},"attributes":{"description":"Shippo's tags, for example `CHEAPEST`.","example":["CHEAPEST"],"items":{"type":"string"},"type":"array"},"carrier_account":{"example":"carrier_0001","type":"string"},"currency":{"example":"USD","type":"string"},"currency_local":{"example":"USD","type":"string"},"duration_terms":{"example":"Delivery in 2 to 5 days.","type":["string","null"]},"estimated_days":{"example":3,"type":["integer","null"]},"included_insurance_price":{"example":null,"type":["string","null"]},"messages":{"example":[],"items":{"additionalProperties":true,"type":"object"},"type":"array"},"object_created":{"example":"2026-11-03T15:00:00Z","type":"string"},"object_id":{"description":"The rate id. Send it as `rate_id` to buy this label.","example":"rate_0001","type":"string"},"object_updated":{"example":"2026-11-03T15:00:00Z","type":"string"},"provider":{"example":"USPS","type":"string"},"provider_image_200":{"example":"https://example.com/usps_200.png","type":"string"},"provider_image_75":{"description":"A URL of the carrier logo.","example":"https://example.com/usps_75.png","type":"string"},"servicelevel":{"additionalProperties":false,"description":"Exactly these four keys; null when Shippo sends no service level.","properties":{"extended_token":{"example":"usps_ground_advantage","type":"string"},"name":{"example":"Ground Advantage","type":"string"},"terms":{"example":"","type":"string"},"token":{"example":"usps_ground_advantage","type":"string"}},"type":"object"},"shipment":{"description":"The Shippo shipment this rate belongs to.","example":"shipment_0001","type":"string"}},"type":"object"},"type":"array"},"shipment_date":{"type":["string","null"]},"status":{"description":"Shippo's status. With `ERROR`, or no rates, read `messages`.","enum":["SUCCESS","QUEUED","ERROR"],"type":"string"}},"required":["object_id","rates"],"type":"object"}}},"description":"A trimmed copy of the Shippo shipment with its rates, without the YoPrint envelope."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"},"500":{"$ref":"#/components/responses/ServerErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get shipping rates","tags":["Shipping rates and estimates"],"x-yoprint-docs":{"errors":[{"fix":"Fix the fields listed in `error.fields`.","status":422,"when":"A required address or parcel field is missing, a unit isn't in the list, or an `extra` option is out of range (`validation_failed`)."},{"fix":"Connect Shippo in the web app first.","status":422,"when":"Shippo isn't connected or is disabled (`goshippo_not_enabled`)."},{"fix":"Check the addresses, parcels and ids, then retry once. Do not loop.","status":500,"when":"Shippo refused the request or could not be reached. Shippo errors are not translated into 4xx replies."}],"group":"Shipping","notes":["A 201 can still carry no rates: check `status`, `messages` and each rate's `messages`.","Rates are quotes from Shippo. YoPrint doesn't record how long Shippo keeps a rate buyable: buy soon after rating, and if the purchase is refused, rate again."],"permission":"Any member of the team. No sales order permission is checked. Needs a connected, enabled Shippo integration (Settings > Integrations > Shippo Shipping). Without one the reply is 422 `goshippo_not_enabled` with no message.","related":["v2_public_shipment_carrier_goshippo","v2_public_shipment_estimate_create_goshippo","v2_public_shipment_label_create_goshippo","v2_public_shipment_show","v1_public_customer_address_show","v1_public_contact_show","v1_public_customer_profile_show","v1_public_location_index","v1_public_setting_detail_show"],"rules":["Both addresses need `name`, `street1`, `city`, `state`, `zip` and `country`.","Each parcel needs its dimensions and weight (at least 0.01) and their units.","Use `carrier_accounts` (plural). A singular `carrier_account` is read only when the plural is missing and is not checked."],"side_effects":["Calls Shippo, which stores a Shippo shipment in your Shippo account. Nothing is bought or saved in YoPrint."]}}},"/v2/api/store/{team_slug}/v2/work_pipeline/{hash_id}":{"delete":{"description":"Deletes a task. The job keeps its dates: they are re-derived from the remaining tasks only the next time a task's dates change.","operationId":"v2_public_job_work_pipeline_destroy","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The task's hash id. Hash ids only: a unique key or a document number gives 404.","example":"hpioY1gDBQZdbI","in":"path","name":"hash_id","required":true,"schema":{"example":"hpioY1gDBQZdbI","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":null,"status":200,"success":true},"schema":{"properties":{"data":{"example":null,"type":"null"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Delete a task","tags":["Tasks"],"x-yoprint-docs":{"errors":[{"fix":"Check the task id.","status":404,"when":"The task isn't your team's."}],"group":"Production","permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_job_work_pipeline_index_for_job"],"side_effects":["Open Admin Portal pages refresh."]}},"get":{"description":"Returns one task: its job and order, preset, status, dates, position and assignees.","operationId":"v2_public_job_work_pipeline_show","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The task's hash id. Hash ids only: a unique key or a document number gives 404.","example":"hpioY1gDBQZdbI","in":"path","name":"hash_id","required":true,"schema":{"example":"hpioY1gDBQZdbI","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-05T17:00:00+00:00","id":"hpioY1gDBQZdbI","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"hTFITko5Q0R83y","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T15:05:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A task.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Get a task","tags":["Tasks"],"x-yoprint-docs":{"errors":[{"fix":"Check the task id.","status":404,"when":"The task isn't your team's."}],"group":"Production","permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_job_work_pipeline_update","v2_public_job_work_pipeline_change_status"]}},"put":{"description":"Changes a task's name, note, preset, status, position, dates or assignees, and returns it. Send only what you change.\n\nSend `start_date` and `due_date` together (both may be null). A start after the due date is a 422 (\"Invalid date range. Due Date should be greater than Start Date.\"). Changing a task's dates resets the job's dates to span its dated tasks: the earliest task start and the latest task due date (none when no task has dates).\n\nAssignees: `unassign_all` runs first, then `assigned_users` are added, then `unassigned_users` are removed. To change only the status, Change a task's status does the same and also returns the previous status.","operationId":"v2_public_job_work_pipeline_update","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The task's hash id. Hash ids only: a unique key or a document number gives 404.","example":"hpioY1gDBQZdbI","in":"path","name":"hash_id","required":true,"schema":{"example":"hpioY1gDBQZdbI","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"reassign":{"summary":"Hand a task to someone else","value":{"assigned_users":["4mdDkMg3dgQOa3"],"unassign_all":true}},"reschedule":{"summary":"Move a task","value":{"due_date":"2026-11-06T17:00:00Z","start_date":"2026-11-06T09:00:00Z"}}},"schema":{"properties":{"assigned_users":{"description":"User hash ids to add.","items":{"type":"string"},"type":"array"},"color":{"description":"A hex color. Validated but not saved.","type":"string"},"due_date":{"description":"ISO 8601, or null to clear. Send with `start_date`.","format":"date-time","type":["string","null"]},"name":{"type":"string"},"note":{"type":"string"},"pipeline_id":{"description":"Move the task to another task preset. Send a `status_id` of that preset with it.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"maximum":2147483647,"minimum":-2147483648,"type":"integer"},"start_date":{"description":"ISO 8601, or null to clear. Send with `due_date`; dates change only when both are sent.","format":"date-time","type":["string","null"]},"status_id":{"description":"A status of the task's preset.","example":"hTFITko5Q0R83y","type":"string"},"unassign_all":{"description":"Remove every assignee first.","type":["boolean","null"]},"unassigned_users":{"description":"User hash ids to remove.","items":{"type":"string"},"type":"array"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-06T17:00:00+00:00","id":"hpioY1gDBQZdbI","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-06T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"hTFITko5Q0R83y","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T16:00:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"A task.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Update a task","tags":["Tasks"],"x-yoprint-docs":{"errors":[{"fix":"Send both dates in order and a status of the task's preset.","status":422,"when":"Dates out of order or sent alone, an unknown preset, or a status from another preset."},{"fix":"Check the ids.","status":404,"when":"The task or a user isn't your team's."}],"group":"Production","permission":"Any member of the team. No sales order permission is checked.","related":["v2_public_job_work_pipeline_show","v2_public_job_work_pipeline_change_status","v2_public_job_work_pipeline_assign"],"rules":["A task's status must be a status of its task preset. An unknown preset is a 422 \"Pipeline not found!\"; a status from another preset a 422 \"Pipeline Status not found!\".","`assigned_users` must be members of your team (404 otherwise). `unassigned_users` isn't checked: ids that aren't assigned are ignored."],"side_effects":["Changing the dates may change the job's dates.","Changing `status_id` sends the `work_pipeline.status_changed` webhook and records the status history.","Open Admin Portal pages refresh."]}}},"/v2/api/store/{team_slug}/v2/work_pipeline/{hash_id}/assign":{"put":{"description":"Adds one team member to a task, or removes one. Returns the task's assignees after the change (people who have left the team are left out).","operationId":"v2_public_job_work_pipeline_assign","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The task's hash id. Hash ids only: a unique key or a document number gives 404.","example":"hpioY1gDBQZdbI","in":"path","name":"hash_id","required":true,"schema":{"example":"hpioY1gDBQZdbI","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"action":"assign","user_id":"4mdDkMg3dgQOa3"},"schema":{"properties":{"action":{"enum":["assign","unassign"],"type":"string"},"user_id":{"description":"A member of your team (from List users).","example":"4mdDkMg3dgQOa3","type":"string"}},"required":["action","user_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":[{"avatar_url":null,"email":"alex@example.com","id":"4mdDkMg3dgQOa3","name":"Alex Rivera","timezone":"America/Chicago"}],"status":200,"success":true},"schema":{"properties":{"data":{"description":"The task's assignees after the change.","items":{"additionalProperties":true,"description":"A team member.","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"email":{"example":"alex@example.com","type":"string"},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"},"timezone":{"example":"America/Chicago","type":["string","null"]}},"type":"object"},"type":"array"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Assign or unassign a person on a task","tags":["Tasks"],"x-yoprint-docs":{"errors":[{"fix":"Send both fields.","status":422,"when":"`action` isn't `assign` or `unassign`, or `user_id` is missing."},{"fix":"Use ids from List users and the task list.","status":404,"when":"The user isn't on your team, or the task isn't your team's."}],"group":"Production","permission":"Any member of the team may assign or unassign anyone on the team.","related":["v1_public_user_index","v2_public_job_work_pipeline_update"],"rules":["Assigning someone already assigned, or unassigning someone who isn't, changes nothing and succeeds."],"side_effects":["No email or notification is sent."]}}},"/v2/api/store/{team_slug}/v2/work_pipeline/{hash_id}/status":{"put":{"description":"Moves a task to another status of its task preset. Returns the task with `previous_status_id` and `previous_status`.\n\nCompleting every task doesn't change the job's status: change it with Change a job's status.","operationId":"v2_public_job_work_pipeline_change_status","parameters":[{"description":"Your team slug, shown as Team ID next to your API key in Profile.","example":"your-team","in":"path","name":"team_slug","required":true,"schema":{"example":"your-team","type":"string"}},{"description":"The task's hash id. Hash ids only: a unique key or a document number gives 404.","example":"hpioY1gDBQZdbI","in":"path","name":"hash_id","required":true,"schema":{"example":"hpioY1gDBQZdbI","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"status_id":"hTFITko5Q0R83y"},"schema":{"properties":{"notify_customer":{"description":"Accepted and ignored.","type":["boolean","null"]},"status_id":{"description":"A status of the task's preset (from List task statuses).","example":"hTFITko5Q0R83y","type":"string"}},"required":["status_id"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"assigned_users":[{"avatar_url":null,"id":"4mdDkMg3dgQOa3","name":"Alex Rivera"}],"created_at":"2026-11-03T15:00:00+00:00","due_date":"2026-11-05T17:00:00+00:00","id":"hpioY1gDBQZdbI","job_id":"WaGvtaWsx7Kcn4","job_is_rush":1,"job_item_count":48,"job_name":"Front print","job_scoped_id":"JOB-2419","job_status_id":"scaWHQnPLtqMPT","name":"Burn screens","note":null,"order_id":"sFbALVSYD55eXe","order_name":"Team shirts","order_scoped_id":"SO1001","pipeline_id":"SE3SfXjt6dPfnH","position":1,"previous_status":{"color":"#9e9e9e","customer_label":"Pending","id":"P32Ic61q2HqUCD","label":"To do","pipeline_id":"SE3SfXjt6dPfnH","position":1,"role":"pipeline","trashed":false,"type":"start"},"previous_status_id":"P32Ic61q2HqUCD","sales_order":{"customer_id":"ifAHmADekGZ6id","customer_name":"Northwind Apparel","is_quote":false,"object_type":"sales_order","status_id":"wgbOT87gGZvhgy"},"start_date":"2026-11-04T09:00:00+00:00","status":{"color":"#2196f3","customer_label":"In Progress","id":"hTFITko5Q0R83y","label":"Burning","pipeline_id":"SE3SfXjt6dPfnH","position":2,"role":"pipeline","trashed":false,"type":"in_progress"},"status_completion_date":null,"status_id":"hTFITko5Q0R83y","status_last_change_date":"2026-11-03T15:05:00+00:00","updated_at":"2026-11-03T15:05:00+00:00"},"status":200,"success":true},"schema":{"properties":{"data":{"additionalProperties":true,"description":"The task after the change, with the status it had before.","properties":{"assigned_users":{"description":"Who is assigned.","items":{"additionalProperties":true,"description":"An assigned team member: id, name and avatar only (no email).","properties":{"avatar_url":{"example":"https://example.com/avatar.png","type":["string","null"]},"id":{"description":"The user.","example":"4mdDkMg3dgQOa3","type":"string"},"name":{"example":"Alex Rivera","type":"string"}},"type":"object"},"type":"array"},"created_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"},"due_date":{"description":"Task due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"id":{"description":"The task.","example":"hpioY1gDBQZdbI","type":"string"},"job_id":{"description":"The job.","example":"WaGvtaWsx7Kcn4","type":"string"},"job_is_rush":{"type":["boolean","integer","null"]},"job_item_count":{"type":["number","null"]},"job_name":{"example":"Front print","type":["string","null"]},"job_scoped_id":{"description":"The job number with its prefix.","example":"JOB-2419","type":"string"},"job_status_id":{"description":"The job's current status.","example":"scaWHQnPLtqMPT","type":["string","null"]},"name":{"example":"Burn screens","type":"string"},"note":{"type":["string","null"]},"order_id":{"description":"The order.","example":"sFbALVSYD55eXe","type":"string"},"order_name":{"type":["string","null"]},"order_scoped_id":{"description":"The order number.","example":"SO1001","type":["string","null"]},"pipeline_id":{"description":"The task preset it comes from.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Order among tasks; lower comes first. 0 when unset.","example":1,"type":"integer"},"previous_status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"previous_status_id":{"description":"The status before this call.","example":"P32Ic61q2HqUCD","type":["string","null"]},"sales_order":{"additionalProperties":true,"description":"A summary of the job's order.","properties":{"created_by":{"description":"Who created the order.","example":"4mdDkMg3dgQOa3","type":["string","null"]},"cust_due_date":{"description":"Order customer due (in-hand) date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"customer_id":{"description":"The customer.","example":"ifAHmADekGZ6id","type":["string","null"]},"customer_name":{"example":"Northwind Apparel","type":["string","null"]},"due_date":{"description":"Order production due date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"external_type":{"description":"`shopify` when the order came from Shopify, else null.","type":["string","null"]},"is_quote":{"type":"boolean"},"issue_date":{"description":"Order issue date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"object_type":{"description":"`sales_order` or `quote`.","example":"sales_order","type":["string","null"]},"ship_due_date":{"description":"Order ship-by date. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"shopify_deleted_externally":{"type":"boolean"},"shopify_deleted_externally_at":{"description":"When it was deleted in Shopify. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"start_date":{"description":"Order production start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The order status.","example":"wgbOT87gGZvhgy","type":["string","null"]}},"type":"object"},"start_date":{"description":"Task start. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status":{"additionalProperties":true,"description":"A status: label, kind and place in the list.","properties":{"color":{"description":"Hex color.","example":"#2196f3","type":["string","null"]},"customer_label":{"example":"In Progress","type":"string"},"id":{"description":"The status.","example":"scaWHQnPLtqMPT","type":"string"},"label":{"example":"Printing","type":"string"},"pipeline_id":{"description":"Only on the statuses of a task preset (`role` `pipeline`): the task preset. Absent on other statuses.","example":"SE3SfXjt6dPfnH","type":"string"},"position":{"description":"Its place in the team's list: sort by it to find the next status.","example":3,"type":"integer"},"role":{"description":"Which list it belongs to: `job` for job statuses, `pipeline` for the statuses of a task preset.","enum":["order","quote","job","purchase_order","shipment","customer_message","pipeline"],"example":"job","type":"string"},"trashed":{"description":"The status was deleted.","type":"boolean"},"type":{"description":"The kind of status: `start` (Pending), `pre_production` and `in_progress` (In Progress), `end` (Completed).","enum":["start","pre_production","in_progress","end"],"example":"in_progress","type":"string"}},"type":"object"},"status_completion_date":{"description":"When it reached a Completed status. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"status_id":{"description":"The task's status (a status of its task preset).","example":"hTFITko5Q0R83y","type":"string"},"status_last_change_date":{"description":"When the status last changed. ISO 8601 with offset, or null.","example":"2026-11-04T09:00:00+00:00","format":"date-time","type":["string","null"]},"updated_at":{"example":"2026-11-03T15:00:00+00:00","format":"date-time","type":"string"}},"type":"object"},"status":{"example":200,"type":"integer"},"success":{"example":true,"type":"boolean"}},"required":["success","status","data"],"type":"object"}}},"description":"Successful response."},"401":{"$ref":"#/components/responses/UnauthenticatedResponse"},"403":{"$ref":"#/components/responses/PublicForbiddenResponse"},"404":{"$ref":"#/components/responses/NotFoundResponse"},"422":{"$ref":"#/components/responses/ValidationErrorResponse"}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"summary":"Change a task's status","tags":["Tasks"],"x-yoprint-docs":{"errors":[{"fix":"Use a status of the task's preset.","status":422,"when":"The status is from another preset (`invalid_status_selection`), or `status_id` is missing."},{"fix":"Check the ids.","status":404,"when":"The task or the status isn't your team's."}],"group":"Production","permission":"Any member of the team.","related":["v1_public_status_list_pipeline","v2_public_job_change_status"],"rules":["The status must belong to the task's preset: otherwise 422 `invalid_status_selection` (\"Selected status is not part of task preset\")."],"side_effects":["Sends the `work_pipeline.status_changed` webhook when the status really changed, and records the status history and `status_last_change_date` (and `status_completion_date` for a Completed status)."]}}}},"security":[{"UserApiKeyBearer":[]},{"UserApiKeyHeader":[]},{"UserApiKeyQuery":[]}],"servers":[{"description":"YoPrint production. Every path starts with the API version and your team slug.","url":"https://secure.yoprint.com"}],"tags":[{"description":"Your personal API key. Check that it works here; create, copy and reset it on your Profile page in the YoPrint web app.","name":"API key"},{"description":"Every customer approval on your team, across all sales orders and quotes: artwork (job) approvals and whole-order approvals together, by approval id. List, filter, email and delete them here. To create an order approval or record the customer's answer on one order, use Sales order approvals.","name":"Approvals"},{"description":"Turn a barcode or QR code printed by YoPrint into the record it points to.","name":"Barcodes"},{"description":"CSV templates, the service pricing CSV upload, and your import jobs. Customer, vendor and product CSV imports run in the web app's Import Portal, not on the public API.","name":"CSV imports"},{"description":"Any internal comment by its id, whatever it is on: a sales order, a quote, a job or a purchase order. Read, edit, delete and restore it here. To list or add the comments of one order, use Sales order comments. Customers never see comments.","name":"Comments"},{"description":"The team's own addresses: the primary location, warehouses, the default warehouse and tax nexus.","name":"Company locations"},{"description":"Your company's profile, logo, customer portal look, custom domain, general preferences and list columns.","name":"Company settings"},{"description":"Files produced for privacy requests, such as a Shopify customer data request.","name":"Compliance requests"},{"description":"Card terminals paired with your team.","name":"Connected devices"},{"description":"Any contact by its id, whether it belongs to a customer or a vendor.","name":"Contacts"},{"description":"The team's currencies. Only the default currency is used: its symbol on documents, its code for integrations.","name":"Currencies"},{"description":"A customer's billing and shipping addresses. The first of each role is primary. An address already used on a document is copied, not changed, when you edit it.","name":"Customer addresses"},{"description":"Brand Profiles: the company name, logo, contact details and Ship From address printed on a customer's documents and used on its shipments.","name":"Customer brand profiles"},{"description":"The people at a customer. One contact can be primary; documents and emails use the contacts you pick.","name":"Customer contacts"},{"description":"Customer credit: money held for a customer, added or taken out by hand and used to pay their sales orders.","name":"Customer credit"},{"description":"Files kept on a customer: tax exemption certificates, internal files and files the customer can see.","name":"Customer files"},{"description":"The people and companies you sell to. A customer holds contacts, billing and shipping addresses, brand profiles, files, tags and a customer credit balance; sales orders, quotes and invoices name a customer.","name":"Customers"},{"description":"Whole-team CSV exports from the Download Center: customers, products, sales orders, invoices, payments, tax and purchase orders. They run in the background; poll, then download.","name":"Data exports"},{"description":"Preview the next sales order, quote, purchase order or stock adjustment number.","name":"Document numbers"},{"description":"Optional features a team turns on or off.","name":"Feature add-ons"},{"description":"Saved fee names and prices to copy into fee line items.","name":"Fee presets"},{"description":"Recent QuickBooks Online and Shopify sync errors for one sales order, purchase order or shipment.","name":"Integration logs"},{"description":"Connections to suppliers, Twilio, GoShippo, QuickBooks Online, Square and Shopify.","name":"Integrations"},{"description":"The lines of an invoice: billed sales order lines, shipping fees, discounts and one tax line.","name":"Invoice line items"},{"description":"Invoices bill some or all of a sales order or quote. One order can have many; with Auto Invoice on, YoPrint automatically keeps one invoice updated to match the order's lines and shipping fees. Payments recorded on the order are allocated to its invoices.","name":"Invoices"},{"description":"Ready-made jobs, with their services, tasks, people and files, that you add to a sales order or quote in one step.","name":"Job presets"},{"description":"A job groups line items on a sales order or quote that are produced together, with their services (decorations), mockups, production files, tasks, dates and a status. The status is the job's production stage: read it from `status_id` on the job, and move it with Change a job's status.","name":"Jobs"},{"description":"One person on an order's or purchase order's message thread, by participant id: who receives its customer emails and texts. To list or add an order's participants, use Sales order messages.","name":"Message participants"},{"description":"The files a message template attaches when it is sent: document PDFs, job sheets, invoices or an uploaded file.","name":"Message template attachments"},{"description":"Reusable email and text messages for sales orders, quotes and purchase orders, with placeholders and attachments.","name":"Message templates"},{"description":"Your team's whole message inbox: emails and texts exchanged with customers and vendors on all sales orders, quotes and purchase orders, with their delivery status. Read them, retry failed deliveries and set a message status here. To send a message on one order, use Sales order messages.","name":"Messages"},{"description":"Your own notification feed: the YoPrint activity that concerns you, such as new comments, customer replies, payments and approvals. Read it and mark items seen or archived.","name":"Notifications"},{"description":"Card payment gateway credentials: Stripe, PayPal, Square, Charge It Pro and Authorize.Net. Charges and refunds themselves go through the sales order payment operations.","name":"Payment gateways"},{"description":"A payment link records how payments received on a sales order are split across its invoices (the web app calls this a payment allocation). It is not a URL or payment page a customer opens to pay, and it moves no money.","name":"Payment links"},{"description":"Labels for payments you record yourself, such as Cash or Check.","name":"Payment methods"},{"description":"Deposit and due-date rules that new sales orders and quotes copy from the customer or the team default.","name":"Payment terms"},{"description":"Payments, refunds and customer credit on a sales order: payments you record yourself, card payments through a connected gateway, and Square Terminal checkouts.","name":"Payments"},{"description":"What members can do. Each member is in one group; the owner can do everything.","name":"Permission groups"},{"description":"Your own stock levels for products, read-only.","name":"Product stock"},{"description":"The size and color combinations of a variant product. Each has its own id, price, stock and sale state (on sale or phased out).","name":"Product variants"},{"description":"The Production Control calendar: orders with their jobs and tasks over a date range.","name":"Production control"},{"description":"Your own products. A simple product is one item with one price; a variant product has sizes, colors or both, and each combination is a variant with its own price and stock. Supplier catalog products are not stored here: see Supplier catalog.","name":"Products"},{"description":"Read one purchase order and change its status (two operations kept for the Zapier app), its history, the CSV export and the QuickBooks sync switch. Creating, editing and receiving purchase orders is not part of the public API.","name":"Purchase orders"},{"description":"Lists and exports for quotes only. Create, read and change a quote with the Sales orders operations.","name":"Quotes"},{"description":"Period reports of orders, purchase orders, payments and paid invoices, for your own reporting.","name":"Reports"},{"description":"The next sales order, purchase order and invoice numbers.","name":"Running numbers"},{"description":"Ask the customer to approve a whole sales order or quote, and record their answer.","name":"Sales order approvals"},{"description":"The team members in an order's Assigned To list. Assigned people whose role sees only their own orders can see the order.","name":"Sales order assignees"},{"description":"Internal comments on a published sales order or quote. The customer never sees them.","name":"Sales order comments"},{"description":"Files attached to a sales order or quote: the Files section in the web app.","name":"Sales order files"},{"description":"The lines of a sales order or quote: catalog products, your own products and their sizes and colors, custom lines and fees. Each line can belong to one of the order's jobs, which adds its decoration price.","name":"Sales order line items"},{"description":"The conversation with the customer on an order: its participants and the emails and text messages sent to them.","name":"Sales order messages"},{"description":"Purchase orders linked to a sales order, by the stock workflow or by hand.","name":"Sales order purchase orders"},{"description":"Add and remove the team's tags on a sales order or quote.","name":"Sales order tags"},{"description":"Sales orders and quotes: create a draft, add jobs and lines, publish it, then run actions on it. A quote is a sales order with `object_type` quote, and most operations here serve both.","name":"Sales orders"},{"description":"Look up the automatic US sales tax rate for a shipping address.","name":"Sales tax"},{"description":"Quick lookups that return the first matches, for search boxes and pickers.","name":"Search"},{"description":"Where on an item a decoration goes, such as \"Shirt - Front\". Set up in Settings and used by your services and their prices.","name":"Service locations"},{"description":"The lines of a shipment: quantities of order lines, and shipping cost lines.","name":"Shipment line items"},{"description":"The packages of a shipment: one per parcel of a label (a multi-parcel label makes several), with carrier, tracking number, size, weight, cost and status.","name":"Shipment packages"},{"description":"Shipments send some or all of an order's lines to one address by one shipping type, with packages, labels and documents.","name":"Shipments"},{"description":"Saved box sizes for GoShippo parcels. Sizes are ×1000.","name":"Shipping boxes"},{"description":"Buying Shippo labels (this spends real money), recording labels bought elsewhere, and printing labels.","name":"Shipping labels"},{"description":"How shipments go out: courier, own delivery, pick-up or a carrier integration service.","name":"Shipping methods"},{"description":"Shipping rates from your connected Shippo account, the carrier accounts behind them, and estimates (rate quotes saved on a shipment). Nothing here buys a label.","name":"Shipping rates and estimates"},{"description":"The status lists for sales orders, quotes, jobs, purchase orders, shipments, message threads and task presets. Each list has a starting and an ending status.","name":"Statuses"},{"description":"The reasons offered when stock is adjusted by hand.","name":"Stock adjustment reasons"},{"description":"Live prices, stock and images from your connected suppliers (S&S Activewear, SanMar, Momentec, AS Colour), for catalog products you sell on sales orders. Find a style's size and color ids, and their `provider`, with Load a product for a sales order line.","name":"Supplier catalog"},{"description":"Colored labels you put on customers and sales orders.","name":"Tags"},{"description":"Named sets of task statuses (pipelines in the API) that tasks on jobs follow.","name":"Task presets"},{"description":"Tasks are the production steps of a job (the work pipeline). Each comes from a task preset, which sets its statuses; a task has dates, a position and assignees.","name":"Tasks"},{"description":"The taxes you apply to invoices: one rate, or named parts that add up, plus YoPrint's Auto Tax. Rates are ×1000.","name":"Tax presets"},{"description":"Email invitations to join your team, with the permission group the person gets.","name":"Team invitations"},{"description":"The people on your team, their permission groups, and ownership.","name":"Team members"},{"description":"Upload a file first, then attach it to a job, an order, a purchase order or a customer by its id.","name":"Uploads"},{"description":"The people at a vendor. One contact can be primary.","name":"Vendor contacts"},{"description":"Files kept on a vendor, such as price lists.","name":"Vendor files"},{"description":"The suppliers you buy from. Purchase orders and your products name a vendor.","name":"Vendors"},{"description":"Subscribe a URL to YoPrint events, such as a published sales order or a received payment. YoPrint signs every delivery with the subscription's secret, retries failures and keeps a delivery log. The web app calls them Webhooks.","name":"Webhook subscriptions"},{"description":"Your shop's own YoPrint plan and billing: plans, checkout, card, invoices, cancellation and the billing operations that track each change.","name":"YoPrint subscription"},{"description":"Your saved web app preferences for one team, such as grid column layouts.","name":"Your preferences"}],"x-tagGroups":[{"name":"Sales","tags":["Approvals","Comments","Document numbers","Quotes","Sales order approvals","Sales order assignees","Sales order comments","Sales order files","Sales order line items","Sales order messages","Sales order purchase orders","Sales order tags","Sales orders","Sales tax","Search"]},{"name":"Customers","tags":["Contacts","Customer addresses","Customer brand profiles","Customer contacts","Customer credit","Customer files","Customers"]},{"name":"Products and catalog","tags":["Product stock","Product variants","Products","Supplier catalog","Tags"]},{"name":"Purchasing","tags":["Purchase orders","Vendor contacts","Vendor files","Vendors"]},{"name":"Production","tags":["Barcodes","Jobs","Production control","Tasks"]},{"name":"Shipping","tags":["Shipment line items","Shipment packages","Shipments","Shipping labels","Shipping rates and estimates"]},{"name":"Invoices and payments","tags":["Invoice line items","Invoices","Payment links","Payments"]},{"name":"Messages and activity","tags":["Message participants","Messages","Notifications","Sales order messages","Your preferences"]},{"name":"Imports and exports","tags":["CSV imports","Data exports","Uploads"]},{"name":"Reports","tags":["Reports"]},{"name":"Team settings","tags":["Company locations","Company settings","Compliance requests","Connected devices","Currencies","Feature add-ons","Fee presets","Integration logs","Integrations","Job presets","Message template attachments","Message templates","Payment gateways","Payment methods","Payment terms","Permission groups","Running numbers","Service locations","Shipping boxes","Shipping methods","Statuses","Stock adjustment reasons","Task presets","Tax presets","Team invitations","Team members","Webhook subscriptions","YoPrint subscription"]},{"name":"Account","tags":["API key"]}]}
