Skip to main content

Create order

Entry. POST /v1/commerce/orders → OrderController → OrderService / OrderCommandService.

Marketplace creates use a different entry. See Marketplace order ingestion.

Sequence​

Synchronous behavior​

Inside the command transaction, when a status change is involved, state is checked with isValidOrderTransition.

OutboxWriterService.enqueue writes:

  • order.created
  • order.confirmed on confirm paths
  • order.location.changed on location changes
  • stock.sync.requested on some paths
  • order.address.resolution_triggered on some paths

OrderCommandService.create always inserts orderStatus: PENDING. The order.confirmed enqueue in that method runs only when the saved status is CONFIRMED, so this create method does not emit it.

If channelOrderNo or orderNo is present, create rejects a second live order with the same channelOrderNo, channelId, and tenantId (order.error.orderNoAlreadyExistsInChannel, deletedAt: null). A retry with a new channel order number is not covered by that check. A missing channel order number is stored as the allocated orderNo.

The client does not wait for fulfillment or the wallet.

Transaction boundary​

The order row and the outbox rows commit or roll back together, because enqueue receives the transaction client. An in-process eventEmitter.emit would not.

Asynchronous behavior​

EventConsumerEffect
order.createdfulfillment listenerFulfillment work
order.confirmedwallet listenerdeductToken
order.address.resolution_triggeredWhatsApp address listenerAddress resolution

Failure​

WhereResult
Validation pipe400, order not written
Throw before commitOrder and outbox rolled back
Listener throwOrder remains. Outbox retries up to 10, then DEAD

Idempotency​

A second live order with the same channelOrderNo, channelId, and tenantId is rejected. There is no Idempotency-Key header on this route. A retry that omits the channel order number, or sends a different one, can insert another order. IdempotencyRecord is not used by this method.

Side effects that do not happen here​

Inventory quantity on a channel is not updated inside this HTTP call. Stock sync is an outbox event that becomes an inventory publish job. See Publish path.