echo&aura developer docs
Reference

REFERENCE

Order states

Find the status contract, inventory ownership, and the boundary between issuance and delivery.

An order status describes its business state. Email delivery is tracked separately through jobs and audit events; there is no email_delivered order status.

StatusMeaningInventory
pending_paymentRegistered, awaiting the buyer's transaction IDReserved until the unpaid hold lapses
pending_verificationPayment details submitted, awaiting a person's decisionReserved; automatic expiry does not release it
paidPayment approved, inside the approval transactionConverted to sold during that transaction
issuedTicket rows created and approval committedSold, subject to ticket cancellation
rejectedAdmin rejected the payment claimHold released
expiredUnpaid hold expired through the expiry serviceHold released
cancelledAll tickets on the issued order have been cancelledSold inventory released as tickets are cancelled

This table is extracted from the application's transition validator:

order-status.ts · actual transition table
export const ORDER_TRANSITIONS: Readonly<Record<OrderStatus, readonly OrderStatus[]>> = {
  pending_payment: ['pending_verification', 'expired'],
  pending_verification: ['paid', 'rejected', 'expired'],
  paid: ['issued'],
  issued: ['cancelled'],
  rejected: [],
  expired: [],
  cancelled: [],
};

The table defines allowed transitions; a service must also check the operation's preconditions. Its pending_verification → expired entry does not permit the automatic expiry job to take that transition. expireLapsedHolds selects only pending_payment orders. Normal admin verification approves or rejects.

Approval records pending_verification → paid → issued in one transaction. Other requests do not observe an intermediate committed paid order from that operation. A repeat approval is refused because the row is no longer pending verification.

Hold cutoff

The displayed hold is 20 minutes. The server allows a two-minute submission grace, then refuses a late transaction ID under the order lock. A stored pending_payment row can already be lapsed before the expiry job processes it.

hold.ts · actual unpaid-hold predicate
export function holdLapsed(
  order: { status: string; holdExpiresAt: Date | null },
  at: Date,
): boolean {
  return (
    order.status === 'pending_payment' &&
    order.holdExpiresAt !== null &&
    at.getTime() >= holdCutoff(order.holdExpiresAt).getTime()
  );
}

Failure behavior

TriggerOutcome
Stock condition fails during registrationSold-out error; no new order or hold commits
Transaction ID already belongs to another orderUnique constraint refuses submission; its audit/update transaction rolls back
Buyer edits the ID before approval locks the orderChanged-ID error; admin must verify the current details
A database write fails during approvalApproval transaction rolls back, including sold counters and ticket rows
Email hook fails after approval commitsOrder remains issued; service logs the failure
An accepted email job fails to sendWorker rejects the job for the configured retry policy

Source and tests

For the explanation behind these contracts, follow Buy a ticket.

Source revision: 94a6d5c

On this page