API: parts, carts, and prices
Customer API endpoints and data shapes for part uploads, carts, and prices, in the order of the purchase flow
This page follows the first half of the purchase flow: upload a part, put it in a cart, and get a price. For the procedure with examples, refer to Upload and price.
Parts
/part-revision/uploadUpload a part fileGuestGET/part-revision/upload/statusPoll the analysis statusGuestGET/part-revision/upload/{analysisId}/resultsRead the analysis result, one time onlyGuestPOST/part-revision/manufacturability/validateCheck parts against process limitsGuestUpload a part
/part-revision/uploadGuestUploads one part file and starts the analysis.
| Item | Value |
|---|---|
| Body | multipart/form-data, one field file that contains the gzip-compressed file |
Header X-Filename | Mandatory. The original file name, URL-encoded. |
Response 200 | A JSON string: the analysis ID |
| Limit | 1024 MB for each request. Also apply the store setting maximumFileSize. |
Poll the analysis status
/part-revision/upload/status?analysisIds={id},{id}GuestReturns an object: analysis ID → status. Refer to Wait for the analysis for the status values.
Read the analysis result
/part-revision/upload/{analysisId}/resultsGuestReturns the analysis result as MessagePack (application/msgpack, with Content-Encoding: gzip). Only the uploader can read it.
You can read the result one time only. Keep the data that you need.
type AnalysisResult = {
partRevisionId: string // the ID for all later calls
fileName: string
versionNumber: number
createdAt: string
originalCadFileType: string
availableAccessories: string[]
width: number
height: number
length: number
volume: number
area: number
convexHullVolume: number
minBoundingBoxVolume: number
shrinkWrapVolume: number
minimumWallThickness: number | null
watertight: boolean // false: the part cannot be purchased instantly
repaired: boolean // the mesh was repaired automatically
baseRotation: number[][]
thumbnail: Uint8Array | null // image bytes
stl: Uint8Array // gzip-compressed STL mesh, for a 3D viewer
wallThickness: Uint8Array | null
bending?: object | null // sheet metal data
machining?: object | null // machining data
}Dimensions are in the units of the file. You tell the API the units (units) when you add the part to a cart or an order.
Check manufacturability
/part-revision/manufacturability/validateGuestChecks if parts are in the limits of a process and a material.
Request: an array of
{ partRevisionId: string; units: MeasurementUnit; processPricesId: string; materialId: number }Response: an array of
type PartManufacturability = {
partRevisionId: string
limits: { withinBoundingBoxLimit: boolean; withinWallThicknessLimit: boolean }
warnings: { hasOptimalWallThickness: boolean }
values: { boundingBox: [number, number, number] | null; wallThicknessLimit: number | null; wallThicknessWarning: number | null }
}
type MeasurementUnit = 'MILLIMETERS' | 'CENTIMETERS' | 'METRES' | 'INCHES' | 'FEET'Part data and files for carts and orders
These calls need a customer token.
/carts/{cartId}/items/{itemId}/part-revisionPart data (JSON) for a cart itemCustomer/carts/{cartId}/items/{itemId}/part-revision/thumbnailPNG imageCustomer/carts/{cartId}/items/{itemId}/part-revision/download/{type}A part fileCustomer/requisition/{requisitionId}Part data (JSON) for an order lineCustomer/requisition/{requisitionId}/thumbnailPNG imageCustomer/requisition/{requisitionId}/download/{type}A part fileCustomer{type} is ORIGINAL_CAD_FILE, CORE_GEOMETRY, THUMBNAIL, PDF_DESIGN_FILE, or WALL_THICKNESS_ANALYSIS.
Carts
A cart keeps the parts and their configuration on the server. A cart does not contain prices. Prices come from POST /pre-order. The cart uses the prefix /cart, and its items use /carts/{cartId}/items.
/cartCreate an empty cart. No body.Guest/carts/{cartId}/itemsAdd an itemGuest/carts/{cartId}/items/{itemId}Replace the configuration of an itemGuest/carts/{cartId}/items/{itemId}Remove an item. 204.Guest/cart/{cartId}Change cart-level dataGuestPATCH/cart/{cartId}/claimMove a guest's parts and carts to the customer. 204.Customer/cartList the open cartsCustomer/cart/{cartId}Get one cart with its itemsCustomer/cart/{cartId}Delete an open cart. 204.Customer/carts/{cartId}/items/{itemId}/filesAttach a file (multipart/form-data, field file)Customer/carts/{cartId}/items/{itemId}/files/{fileId}Download an attached fileCustomer/carts/{cartId}/items/{itemId}/files/{fileId}Delete an attached fileCustomerA guest can create carts and change items, but cannot read a cart back. Keep the cart ID and the items in your storefront until the visitor signs in.
Cart data shapes
type Cart = {
cartId: string
status: 'OPEN' | 'DELETED' | 'CONVERTED'
items: CartItem[]
customerId: number | null // null: a guest cart that is not claimed
currency: string | null
notes: string | null
affiliate: string | null
discountId: number | null
billingAddressId: number | null
toAddressId: number | null
shippingMethodId: number | null
rateId: string | null
createdAt: string
lastUpdated: string
}
type CartItem = {
id: number // omit when you create an item
partRevisionId: string
name: string | null
quantity: number
units: MeasurementUnit | null
processPricesId: string | null
materialId: number | null
colorId: number | null
infillId: number | null
precisionPricesId: number | null // NOTE: "precisionId" in pre-order and order lines
leadTimeId: string | null
postProcessingIds: number[] | null
useOriginalOrientation: boolean | null
files: { id: number; fileName: string | null; contentType: string | null; size: number | null }[] | null
}Change cart-level data
/cart/{cartId}GuestAccepts currency, affiliate, notes, discountId, billingAddressId, shippingMethodId, toAddressId, and rateId.
- A field that you omit does not change.
- A field with
nullis cleared. - For a guest cart, the address and rate fields give
409CART_NOT_CLAIMED.
Claim a guest cart
/cart/{cartId}/claimCustomerTakes { "anonymousSessionToken": "<guest token>" }. For the procedure and the status codes, refer to Claim the guest cart.
Prices
/pre-orderCalculate prices for a set of linesGuestPOST/pre-order/bulk-quote?currency={currency}Prices at the bulk quantities of a processGuestPOST/discount/validateCheck a discount codeCustomerGet a price
/pre-orderGuestCalculates the price for a set of lines. Stores no data. For an example request and how to use the response, refer to Get a price.
Request
POST /order uses the same body. Refer to Orders.
type CreateOrder = {
currency: string // one of acceptedCurrencies
requisitions: Record<string, CreateRequisition> // key: a UUID that you select for each line
shipping: CreateShipping | null
shippingId: null
billingAddressId: number | null
discountId: number | null
operatorNote: string | null // a note to the manufacturer
affiliate: string | null
cartId: string | null // POST /order only
intent?: 'CHECKOUT' // POST /order only
}
type CreateRequisition = {
sequence: number // position of the line, from 0
partRevisionId: string
units: MeasurementUnit
quantity: number
processPricesId: string
materialId: number
infillId: number | null
precisionId: number | null
colorId: number | null
leadTimeId: string | null
postProcessingIds: number[]
comments: { conversationType: 'REQUISITION_TAGGED'; message: string }[]
constraints?: { constraintType: 'FIXED_ORIENTATION' }[]
name: string | null
}
type CreateShipping =
| { shippingMode: 'SELF_COLLECTION'; shippingMethodId: number; contactName?: string; contactPhoneNumber?: string }
| { shippingMode: 'FIXED_PRICE'; shippingMethodId: number; rateId: string; toAddressId: number }
| { shippingMode: 'CARRIER_ACCOUNT'; shippingMethodId: number; rateId: string; toAddressId: number }
| { shippingMode: 'CUSTOMER_ACCOUNT'; shippingMethodId: number; toAddressId: number; accountNumber: string }A guest cannot send shipping or billingAddressId (addresses need a customer).
Response
type PreOrder = {
quote: Quote
purchasability: Purchasability
constraints: Record<string, object[]>
}
type Quote = {
currency: string
price: number // total
subtotal: number
shipping: number
discount: number
topUp: number | null // amount added to reach the minimum order amount
tax: {
totalPrice: number
totalPercentage: number
components: { shortName: string; longName: string; percentage: number; amount: number }[]
isTaxAppliedToShipping: boolean
isTaxExempted: boolean
isTaxReverseCharged: boolean
}
lineItems: { name: string; price: number }[]
requisitions: Record<string, RequisitionQuote | null> // null: no instant price for this line
expectedDispatchDate: string | null
}
type RequisitionQuote = {
partRevisionId: string
quantity: number
price: number
unitPrice: number
manufacturingPrice: number
postProcessingPrice: number
postProcessingOptions: { id: number; price: number }[]
}
type Purchasability = {
canBePurchased: boolean // false: offer "request a quote", not payment
isPriceReviewRequired: boolean
withinMaximumOrderValue: boolean
withinBoundingBoxLimit: boolean
withinWallThicknessLimit: boolean
isMaterialPurchasable: boolean
isPostProcessingPurchasable: boolean
parts: Record<string, PartManufacturability>
}PartManufacturability is described in Check manufacturability.
400 with an empty body: the request has no lines.
Get bulk prices
/pre-order/bulk-quote?currency={currency}GuestReturns prices at the bulk quantities of the process, for one part configuration.
Request: a CreateRequisition without sequence, quantity, comments, and name.
type BulkQuote = { quantity: number; price: number; unitPrice: number; savingsPerUnit: number }Validate a discount code
/discount/validateCustomerRequest: { "discountCode": "SPRING" }. Response 200: the discount (discountId, code, percentage, …). Response 204: the code is not valid.
Last updated on