Understanding the order lifecycle
In Propeller, orders, quotes and quote requests are all the same object: an Order. What distinguishes them is the combination of type and status on the order. This unified model means you query, display and manage all three using the same API. Understanding how the order lifecycle works helps you build checkout flows, quote request forms, order history pages and status displays correctly.
The unified order model
Every order in Propeller has two fields that define what it represents:
type(OrderType) categorizes the order by its business purpose.status(a string matching a configured OrderStatus code) determines where the order sits in its lifecycle.
OrderType
The type field is an enum with four values:
| Type | Purpose |
|---|---|
dropshipment | A standard order fulfilled by shipping to the customer |
quotation | A quote |
purchase | A purchase order (procurement) |
stock | A stock order (internal inventory) |
For most frontend applications, you work with dropshipment (orders and quote requests) and quotation (quotes).
OrderStatus
Each order status is a configured object with its own fields:
| Field | Description |
|---|---|
code | The status identifier (e.g. NEW, QUOTATION, CONFIRMED) |
name | Human-readable label |
orderType | Categorizes the status as ORDER, QUOTATION or REQUEST |
type | Whether the status is SYSTEM (built-in) or CUSTOM (user-defined) |
isPublic | Whether the status is visible to customers |
isDefault | Whether this is the default status for its order type |
nextStatuses | Which statuses this status can transition to |
previousStatuses | Which statuses can transition to this status |
statusSet | The parent group this status belongs to |
The orderType field on a status is what ultimately tells you whether an order is a quote request (REQUEST), a quote (QUOTATION) or an order (ORDER).
How type and status combine
| What it represents | OrderType | OrderStatus orderType | Status examples |
|---|---|---|---|
| Quote request | dropshipment | REQUEST | REQUEST |
| Draft quote | quotation | QUOTATION | DRAFT_QUOTATION |
| Published quote | quotation | QUOTATION | QUOTATION |
| Order | dropshipment | ORDER | DRAFT_ORDER, NEW, VALIDATED, CONFIRMED |
Because quotes and orders share the same data model, you query them using the same orders query and filter by type or status to display the right records in the right context.
How orders are created
There are three paths to creating an order. Each produces the same Order object but serves a different use case.
Cart (storefront checkout)
The most common path for customer-facing applications. A customer builds a cart, sets addresses, selects shipping and payment, then converts the cart into an order using cartProcess.
cartStart → add items → set addresses → choose shipping → choose payment → cartProcess
The cartProcess mutation takes an orderStatus (typically UNFINISHED for orders requiring online payment, NEW for orders on account or REQUEST for a quote request) and returns the created order with its cartOrderId.
This is the path covered in Cart management and Checkout flow.
Tender (sales portal)
A tender is an extended cart used by sales representatives. It allows adjusting item prices, applying discounts, viewing margins and managing customer-specific pricing. Tenders are typically used in a sales portal, not in a frontend customer portal.
tenderStart → add items → adjust pricing and discounts → tenderProcess
Key differences from a cart:
| Aspect | Cart | Tender |
|---|---|---|
| User | Customer | Sales representative |
| Pricing | Fixed (based on price sheets and rules) | Adjustable per item |
| Discounts | Applied via action codes | Manually set with margin visibility |
| Owner | The customer placing the order | The sales rep (ownerId), separate from the customer |
| Output | cartProcess → order | tenderProcess → order |
When a tender is processed, it creates the same Order object as a cart would. The source field on the resulting order indicates where it originated (e.g. "Sales Portal").
Direct creation (API and admin)
For integrations and backend systems, orders can be created directly using the orderCreate mutation. This creates a complete order in a single call without going through the cart or tender flow.
All paths converge
Regardless of how an order is created, the result is the same Order object. The cartId field on an order indicates whether it originated from a cart. The source field records where the order came from.
Cart (storefront) ──→
Tender (sales portal) ──→ Order
orderCreate (API) ──→
Order statuses and transitions
Order statuses in Propeller are not just labels. They form a directed graph of allowed transitions. Each status defines which other statuses it can move to (nextStatuses) and which statuses can move to it (previousStatuses).
Status sets
Statuses are organized into sets (OrderStatusSet). A set is a named group of related statuses. This is useful for workflow organization, for example grouping all quote-related statuses into one set and all fulfillment statuses into another.
The default status set
Statuses are configured per tenant, so the codes below are the set a new environment starts with, not a fixed list. Query them (next section) rather than hard-coding them.
| Status code | Order type | Meaning |
|---|---|---|
REQUEST | REQUEST | Quote request submitted by the customer. System default for requests |
REJECTED | REQUEST | Quote request declined. Not visible to the customer |
DRAFT_QUOTATION | QUOTATION | Quote being drafted by a sales rep. Not visible to the customer. System default for quotes |
QUOTATION | QUOTATION | Published quote, visible to the customer |
DRAFT_ORDER | ORDER | Order being prepared, not yet placed. Not visible to the customer. System default for orders |
UNFINISHED | ORDER | Order placed, awaiting online payment |
NEW | ORDER | Order placed and ready for processing |
VALIDATED | ORDER | Order checked and approved |
CONFIRMED | ORDER | Order confirmed for fulfillment |
ARCHIVED | ORDER | Order closed |
OFFLINE_ORDERS | ORDER | Order created outside the storefront |
Allowed transitions in the default set:
| From | To |
|---|---|
REQUEST | REJECTED, DRAFT_QUOTATION |
DRAFT_QUOTATION | QUOTATION, DRAFT_ORDER |
QUOTATION | DRAFT_QUOTATION, DRAFT_ORDER, NEW |
DRAFT_ORDER | NEW |
UNFINISHED | NEW |
NEW | VALIDATED, CONFIRMED, ARCHIVED |
VALIDATED | CONFIRMED, ARCHIVED |
CONFIRMED | ARCHIVED |
cartProcess creates the order directly in the status you pass, so a storefront normally uses NEW (no online payment), UNFINISHED (an online payment follows) or REQUEST (quote request). A quote the customer accepts moves from QUOTATION to NEW, not to CONFIRMED.
Discover the statuses in your environment
Use orderStatuses to read the codes, their order type, whether customers may see them and where each can move next:
query OrderStatuses {
orderStatuses(input: { offset: 50 }) {
items {
code
name
orderType
type
isDefault
isPublic
nextStatuses {
items {
code
}
}
}
}
}
Response (trimmed):
{
"data": {
"orderStatuses": {
"items": [
{
"code": "QUOTATION",
"name": "Quote",
"orderType": "QUOTATION",
"type": "CUSTOM",
"isDefault": false,
"isPublic": true,
"nextStatuses": { "items": [{ "code": "DRAFT_QUOTATION" }, { "code": "DRAFT_ORDER" }, { "code": "NEW" }] }
},
{
"code": "NEW",
"name": "Order",
"orderType": "ORDER",
"type": "CUSTOM",
"isDefault": false,
"isPublic": true,
"nextStatuses": { "items": [{ "code": "VALIDATED" }, { "code": "CONFIRMED" }, { "code": "ARCHIVED" }] }
}
]
}
}
}
Read nextStatuses before offering a status change in your UI, and filter on isPublic when showing statuses to customers.
Enforced transitions
The orderSetStatus mutation enforces valid transitions. If you attempt a transition that is not allowed by the status configuration, the API returns an ORDER_STATUS_TRANSITION_NOT_ALLOWED error.
The orderSetStatus input accepts:
| Field | Description |
|---|---|
orderId | The order to update |
status | The new status code |
payStatus | Optional payment status update |
triggerOrderSendConfirmEvent | Whether to fire the ORDER_SEND_CONFIRMATION event, which an event action turns into the confirmation email |
deleteCart | Whether to delete the originating cart |
Public vs. internal statuses
The isPublic flag on a status controls whether it is visible to customers. Internal statuses (where isPublic is false) are only visible to admin users and sales representatives. Use this flag to decide which statuses to display in a customer-facing order history page.
Example lifecycle: quote to order
This example walks through a complete lifecycle from quote request to fulfilled order, showing how the same Order object moves through different statuses.
1. Customer submits a quote request
A customer builds a cart and processes it with a quote request status. The resulting order has type dropshipment and status REQUEST.
2. Sales rep creates a draft quote
A sales representative opens the order in the sales portal and adjusts pricing and discounts. The status moves to DRAFT_QUOTATION. This status is not public, so the customer cannot see the draft.
3. Sales rep publishes the quote
When the quote is ready, the sales rep transitions the status to QUOTATION. This status is public, so the customer can now view the quote and its pricing. The quote may have a validUntil date after which it expires.
4. Sales rep revises the quote
If changes are needed, the sales rep transitions back to DRAFT_QUOTATION, makes adjustments and publishes again. Each change is tracked in the version history (see below).
5. Customer accepts the quote
The customer accepts the quote, which transitions the status from QUOTATION to an order status like NEW. At this point the order type remains quotation but the status order type changes from QUOTATION to ORDER.
6. Order moves through fulfillment
The order progresses through the order statuses of your status set, in the default set VALIDATED → CONFIRMED → ARCHIVED. Shipments are created and tracked along the way, each with its own shipment status.
REQUEST → DRAFT_QUOTATION → QUOTATION → DRAFT_QUOTATION → QUOTATION → NEW → VALIDATED → CONFIRMED → ARCHIVED
(1) (2) (3) (4) (4) (5) (6) (6) (6)
Version history
Orders track every change as a revision. Each revision stores a sequential number, a timestamp, who made the change and a snapshot of the order state at that point.
Revision fields
| Field | Description |
|---|---|
revisionNumber | Sequential number, starting at 1 |
createdAt | When the revision was created |
createdByAdminUser | The admin user who made the change (if applicable) |
createdByContact | The contact who made the change (if applicable) |
createdByCustomer | The customer who made the change (if applicable) |
createdFromRevisionNumber | The revision this one was branched from |
Snapshots
Each revision contains a snapshot of the order state, including the status, type and visibility flags. Two fields are particularly relevant for frontends:
public: whether this revision is visible to customers.publicVersionNumber: the version number that customers see.
Public revisions get an incrementing publicVersionNumber. Private revisions (like draft edits) do not increment this number and are not visible to customers.
Example revision trail
For the quote-to-order lifecycle described above, the revision history might look like this:
| Revision | Status | Public | Customer sees |
|---|---|---|---|
| 1 | DRAFT_QUOTATION | No | Nothing |
| 2 | QUOTATION | Yes | Version 1 |
| 3 | DRAFT_QUOTATION | No | Still version 1 |
| 4 | QUOTATION | Yes | Version 2 |
| 5 | NEW | Yes | Version 3 (order confirmed) |
Revision mutations
Two mutations manage revisions:
orderRevisionRestorerestores an order to a previous revision state. TakesorderIdandrevisionNumber.orderRevisionsInvalidatemarks specific revisions as invalid.
Shipment tracking
After an order is confirmed, shipments track the physical fulfillment. Each shipment has a status that progresses through delivery stages:
| Status | Description |
|---|---|
CREATED | Shipment record created |
PROCESSING | Being prepared |
IN_TRANSIT | Picked up by carrier |
OUT_FOR_DELIVERY | Out for final delivery |
DELIVERED | Successfully delivered |
PARTIALLY_DELIVERED | Some items delivered |
FAILED_DELIVERY | Delivery attempt failed |
CANCELED | Shipment canceled |
EXCEPTION | An exception occurred |
An order can have multiple shipments for partial deliveries. Each shipment can carry track-and-trace codes for carrier tracking.
Key fields on the Order object
These are the fields most relevant to understanding the order lifecycle. For complete field documentation, see the GraphQL API reference.
| Field | Description |
|---|---|
id | Auto-increment order ID |
uuid | UUID identifier |
status | Current status code |
type | Order type (dropshipment, quotation, purchase, stock) |
source | Where the order was created (e.g. webshop name, "Sales Portal") |
cartId | The originating cart ID, if created via cartProcess |
originalOrderId | Reference to the original order (for copies) |
validUntil | Expiry date (used for quotes) |
createdAt | Creation timestamp |
lastModifiedAt | Last modification timestamp |
statusDate | When the status was last changed |
companyId | The company this order belongs to |
invoiceUserId | The user responsible for payment |
items | The order line items |
total | Order totals (subtotal, tax, shipping, grand total) |
orderAddresses | Billing and shipping addresses |
shipments | Associated shipments |
What this means for your frontend
Understanding the order lifecycle helps you build the right features for each stage:
- Cart management creates and manages the mutable cart before checkout. See Cart management.
- Checkout flow sets addresses, shipping and payment on the cart and converts it to an order with
cartProcess. See Checkout flow. - Quote requests use
cartProcesswith a quote request status to submit the cart as a request for quotation. - Order history queries orders and filters by type or status to display the right records. Use
isPublicon statuses to decide which statuses to show customers. See Order history. - Payment integration handles the payment flow after
cartProcesscreates an order with statusUNFINISHED. See Payment integration. - Shipment tracking displays shipment statuses and track-and-trace codes for fulfilled orders.