Custom Storefronts

API: customers and orders

Customer API endpoints and data shapes for customers, addresses, shipping, orders, payment, and order tracking, in the order of the purchase flow

This page follows the second half of the purchase flow: after sign-in, the customer selects an address and shipping, creates the order, pays, and follows the order. All calls on this page need a customer token. For the procedure with examples, refer to Checkout and payment.

Customer profile

GET/customerThe signed-in customerCustomer
PATCH/customerChange firstName, lastName, language, notificationPreferenceCustomer
GET/customer-organisationThe customer's organisation, with its customers and addressesCustomer
PATCH/customer-organisationChange name or languageCustomer
type Customer = {
  customerId: number
  email: string | null
  firstName: string | null
  lastName: string | null
  phoneNumber: string | null
  organisationName: string | null
  language: string
  notificationPreference: 'EMAIL' | 'SMS' | 'WHATSAPP'
  customerType: 'PRO_FORMA' | 'ACCOUNT' | 'INTERNAL'
  discountPercentage: number | null
}

Customer types

customerType controls the payment methods. Refer to Choose the payment methods.

TypeMeaning
PRO_FORMAPays before production (the default)
ACCOUNTCan always pay by invoice or by purchase order
INTERNALAn internal customer of the manufacturer. No online payment.

Addresses

GET/addressList the addresses of the organisationCustomer
GET/address/{addressId}Get one addressCustomer
POST/addressCreate an addressCustomer
DELETE/address/{addressId}Delete an address. 204.Customer

There is no call to change an address. Create a new one.

type Address = {
  addressId: number             // omit when you create an address
  name: string                  // name of the contact person
  company: string
  street1: string
  street2: string
  city: string
  state: string
  zip: string
  country: string               // the "country" value from GET /countries
  jurisdictionIsoCode: string   // the "iso" value from GET /countries/{country}/jurisdictions
  phone: string
  email: string
  residential: boolean
  taxId: string | null
  isBillingAddress: boolean
  isShippingAddress: boolean
  countryAlpha2Code: string     // response only
  countryAlpha3Code: string     // response only
}

Send all fields when you create an address. Use an empty string for text fields that the customer leaves empty.

For the country and jurisdiction lists, refer to Store settings.

Shipping

For the shipping methods of the store, refer to List shipping methods. For the shipping object of an order, refer to CreateShipping in Get a price.

Get shipping rates

POST/shipping/rateCustomer
// Request
{
  currency: string
  toAddressId: number
  parts: { partRevisionId: string; units: MeasurementUnit; quantity: number; processPricesId: string; materialId: number }[]
}

// Response
type ShippingRates = {
  shippingMethodId: number | null
  tooLargeForBoxes: boolean     // the parts do not fit the boxes of the manufacturer
  errorWithCarrier: boolean     // the carrier gave no rate
  rates: { id: string; rate: number; currency: string; serviceType: string; serviceName: string; shippingMethodId: number }[]
}[]

A rate id is the rateId of the shipping object. A rate belongs to the customer's organisation.

Orders

A quote and an order are one resource. state is QUOTE until the customer pays or accepts; then it is ORDER.

POST/orderCreate a quote / order. Body: CreateOrder.Customer
GET/orderAll quotes and orders of the organisation, newest firstCustomer
GET/order/{orderId}One orderCustomer
GET/order/{orderId}/quotePrice breakdown (Quote). The keys of requisitions are requisition IDs.Customer
GET/order/{orderId}/purchasabilityCan the order be paid now (Purchasability)Customer
GET/requisition?orderId={orderId}The lines of an orderCustomer
PATCH/order/{orderId}/shippingSet or replace the shipping. Body: CreateShipping.Customer
PATCH/order/{orderId}/discount/{discountId}/applyApply a discount. 204.Customer
PATCH/order/{orderId}/discount/removeRemove the discount. 204.Customer
PATCH/order/{orderId}/requisitions/removeRemove lines. Body: { "requisitionIds": [1, 2] }.Customer

Create an order

POST/orderCustomer

The body is CreateOrder, the same as POST /pre-order. For the rules, refer to Create the order.

Response:

{ order: Order; requisitionMapping: Record<string, Requisition> }   // key: your line key

Order data shapes

type Order = {
  id: number
  state: 'QUOTE' | 'ORDER'
  quoteNumber: string | null
  orderNumber: string | null    // set when the quote becomes an order
  price: number | null
  currency: string
  paymentStatus: 'UNPAID' | 'PROCESSING' | 'PAID' | 'REFUNDED' | 'EXTERNALLY_TRACKED'
  isReviewRequired: boolean
  isVoided: boolean
  isArchived: boolean
  operatorNote: string | null
  purchaseOrderNumber: string | null
  requisitionIds: number[]
  threadId: number              // for messages and files
  shipping: Shipping | null
  shipments: Shipment[]
  billingAddress: Address | null
  discount: { discountId: number; code: string | null; percentage: number } | null
  tax: object | null
  kanbanColumn: { id: string; name: string; color: string | null } | null   // production stage
  createdAt: string
  lastUpdated: string
}

type Requisition = {
  id: number
  orderId: number
  sequence: number
  name: string
  partRevisionId: string
  units: MeasurementUnit
  quantity: number
  processPricesId: string
  materialId: number
  colorId: number | null
  infillId: number | null
  precisionId: number | null
  leadTimeId: string | null
  postProcessingIds: number[]
  pricePaid: number | null
  watertight: boolean
}

type Shipment = {
  id: string
  type: 'COURIER' | 'COLLECTION'
  fulfilledAt: string
  destination: object
  parcels: object[]
  tracking?: { provider: string; providerService: string; trackingNumber: string; trackingUrl: string | null } | null
}

Shipping in a response is the CreateShipping object plus read-only fields such as rate, name, toAddress, and expectedDispatchDate.

Payment

For which methods to show and the procedure, refer to Checkout and payment.

Start an online payment

POST/order/{orderId}/paymentCustomer

No body.

type Payment = {
  id: string
  provider: string              // the paymentProvider of the store
  finalPrice: number
  tax: number
  currency: string
  clientSecret?: string | null
  paymentPrincipal?: string | null
  merchantAccount?: string | null
  flywireGatewayUrl?: string | null
  stripePaymentIntentStatus?: string | null
}
ProvideridclientSecretpaymentPrincipalmerchantAccount
STRIPEPayment intent IDPayment intent client secret-Connected account ID of the store
PAYPALPayPal order ID-PayPal order IDMerchant ID of the store
RAZORPAY_SINGLE_PARTYRazorpay order ID-Razorpay order IDRazorpay key ID
FLYWIRE---- (open flywireGatewayUrl)

Errors: 404 ORDER_NOT_FOUND; 400 INTERNAL_ORDER_NOT_PAYABLE; 400 ORDER_ERROR (also when the order cannot be paid).

After the customer completes the payment with the provider, poll GET /order/{orderId} until paymentStatus changes.

To complete a Stripe or PayPal payment in your storefront, you need the Phasio platform key for the provider SDK. Contact Phasio support to get it.

Pay by invoice

PATCH/order/{orderId}/payment/invoiceCustomer

No body. Returns the Order. 400 with an empty body if the method is not permitted.

Pay by purchase order

PATCH/order/{orderId}/payment/purchase-orderCustomer

multipart/form-data with optional fields purchaseOrderNumber, message, and file. Returns the Order. 400 with an empty body if the method is not permitted.

Documents

GET/document/order/{orderId}/estimateQuote PDFCustomer
GET/document/order/{orderId}/confirmationOrder confirmation PDFCustomer
GET/document/order/{orderId}/invoiceInvoice PDF. 403 if isInvoiceDownloadEnabled is false. 404 if there is no invoice.Customer

Messages and files

Each order has a thread (Order.threadId).

GET/activity/thread/{threadId}Messages and events of the thread, oldest firstCustomer
POST/activitySend a messageCustomer
GET/thread-file/thread/{threadId}List the files of the threadCustomer
PUT/thread-file/thread/{threadId}?name={name}Upload a file (multipart/form-data, field file)Customer
GET/thread-file/thread/{threadId}/{fileId}Download a fileCustomer

Send a message:

{ "activityType": "CONVERSATION", "conversationType": "GENERIC", "threadId": 880, "message": "When will you ship?" }

Projects

A project groups orders and files for a customer.

GET/project?page=0&size=20&sort=createdAt,desc&status=ACTIVEList projects (in pages)Customer
GET/project/{projectId}Get a projectCustomer
POST/projectCreate a project: { "name": "…", "description": "…", "status": "ACTIVE" }Customer
GET/order/project/{projectId}Orders of a projectCustomer

Page response:

type Page<T> = { content: T[]; totalElements: number; totalPages: number; pageNumber: number; pageSize: number; isEmpty: boolean; isFirst: boolean; isLast: boolean }

Catalog

A catalog contains parts with agreed prices for one customer organisation.

GET/catalogThe catalog of the organisation: { parts: CatalogItem[] }Customer
GET/catalog/{catalogItemId}/part-revisionPart dataCustomer
GET/catalog/{catalogItemId}/thumbnailPNG imageCustomer

Last updated on

On this page