> ## Documentation Index
> Fetch the complete documentation index at: https://voyant.travel/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Commerce

> The commercial decision layer: markets, pricing, promotions, FX, and sellability resolved through one evaluator that answers can this buyer buy this item, for this date and party, and at what price.

The commerce module (`@voyant-travel/commerce`) owns the narrow commercial decision: given a [Catalog Item](/docs/concepts/glossary) or vertical item, a date, a party, a market, a channel, a buyer, and a currency, can it be bought, and at what price? It is the layer that turns catalog (what exists) into something buyable (what this customer can purchase right now). It owns the quote-time markets, pricing, promotions, and sellability runtime sources behind a single root call.

Commerce is deliberately thin and adapter-driven. It does not depend on Product or inventory schemas; operated inventory and every sourced vertical enter commerce the same way, through an item reference resolved by a registered price-availability adapter. The decision is the resolved answer to [Sellability](/docs/concepts/glossary): it combines availability, pricing, allotments, and policies into one verdict, and it does so without side effects.

## Key concepts

<ResponseField name="Commercial decision" type="root output">
  The result of `evaluateCommercialDecision`. It carries `status` and `buyable` (`buyable`, `unbuyable`, or `error`), a canonical `reason` code, full `pricing`, `fx`, `promotions`, `availability`, `sellability`, rule `traces`, adapter/source `handles`, and `validFrom` / `validUntil` bounds.
</ResponseField>

<ResponseField name="Cost" type="our outflow">
  The amount the operator pays a [Supplier](/docs/concepts/glossary): the input to margin. Distinct from Rate and Price even when the numbers are equal. See [Cost](/docs/concepts/glossary).
</ResponseField>

<ResponseField name="Rate" type="supplier tariff">
  A Supplier's per-unit tariff: `per_person`, `per_night`, `per_vehicle`, or `flat`. The pricing input, not the customer-facing number. See [Rate](/docs/concepts/glossary).
</ResponseField>

<ResponseField name="Price" type="customer sell amount">
  The customer-facing sell amount. Commerce returns it in minor units with components, tax and fee facts, and source price facts. See [Price](/docs/concepts/glossary).
</ResponseField>

<ResponseField name="Market" type="region anchor">
  A geographic and economic region (for example "EU" or "US East Coast") that anchors currency and pricing. The decision input carries the requested market and the requested sell currency separately; FX resolves one to the other. See [Market](/docs/concepts/glossary).
</ResponseField>

<ResponseField name="FX rate set" type="exchange snapshot">
  A timestamped snapshot of exchange rates used to resolve prices in a non-native currency. The decision's `fx` block records the requested currency, source currency, rate, rate set, and provider handle when a conversion was applied. See [FX Rate Set](/docs/concepts/glossary).
</ResponseField>

<ResponseField name="Promotion" type="discount rule">
  A discount applied at decision time. The `promotions` block reports applied and rejected promotions, the requested codes, the total discount, and the stacking facts that explain why each promotion did or did not apply.
</ResponseField>

<ResponseField name="Price-availability adapter" type="pluggable source">
  The unit of extensibility. An adapter declares `id`, `kind`, `supports(input)`, and `evaluate(input, context)`. Inventory is just one adapter kind; cruise, accommodation, and sourced verticals each register their own. The evaluator selects the adapter that supports the item and delegates pricing and availability to it.
</ResponseField>

## What it owns

* **The commercial decision Interface**: `createCommercialDecisionEvaluator`, `evaluateCommercialDecision`, and the decision, trace, pricing, promotion, FX, and snapshot types, all exposed from the package root.
* **Markets and FX**: the market definitions and rate sets that anchor currency and resolve cross-currency pricing.
* **Pricing**: the rule engine that assembles components, taxes, fees, and surcharges into a sell price from the selected adapter's source facts.
* **Promotions**: the promotion catalog and the stacking and eligibility logic, with a dedicated admin surface.
* **Sellability**: the runtime that folds availability and policy facts from the adapter into the buyable verdict.
* **The adapter registry**: `createCommerceAdapterRegistry` and the boot-time registration of price-availability adapters.
* **Snapshot recording**: `recordCommercialSnapshot`, the explicit persistence command for decision evidence.

Commerce does **not** own catalog content, inventory truth, bookings, or finance documents. Crucially, `evaluateCommercialDecision` is side-effect-free from commerce's perspective: it may call adapters that read operational or source state, but it must never create offers, orders, reservations, holds, snapshots, ledgers, or audit records. Persisting evidence is a separate, explicit step.

## Working with it

You build an evaluator at boot, register the adapters your deployment uses, and call the root decision for each priced surface.

```ts theme={null}
import { createCommercialDecisionEvaluator } from "@voyant-travel/commerce";

const evaluator = createCommercialDecisionEvaluator();

// Inventory is just another adapter kind; commerce never imports its schema.
evaluator.registerPriceAvailabilityAdapter(operatedInventoryAdapter);
evaluator.registerPriceAvailabilityAdapter(cruiseSourceAdapter);
```

A decision answers the buyable question for one item, date, and party. Pass an `idempotencyKey` to replay the same decision deterministically.

```ts theme={null}
const decision = await evaluator.evaluateCommercialDecision({
  item: { module: "products", id: "prod_aswan_felucca" },
  date: "2026-09-14",
  party: { adults: 2, children: 1 },
  market: "EU",
  currency: "RON",
  channel: "direct",
  buyer: { personId: "pers_henderson" },
  promotionCodes: ["EARLYBIRD"],
  idempotencyKey: "quote:abc123",
});

if (decision.buyable === "buyable") {
  // decision.pricing carries minor-unit totals, components, tax/fee facts.
  // decision.fx records the RON conversion and the rate set used.
  // decision.traces explains every applied, skipped, and blocked rule.
}
```

Because evaluation never writes, persisting the decision as evidence is a separate command that the snapshot repository owns, including its own idempotency enforcement.

```ts theme={null}
import { recordCommercialSnapshot } from "@voyant-travel/commerce";

await recordCommercialSnapshot(decision, { kind: "quote", id: "quot_123" }, snapshotRepository);
```

Templates declare one commerce runtime entry and expand it; the route prefixes stay stable.

Standard modules are not registered by hand. `@voyant-travel/commerce` is part of the standard product graph, so its routes, services, subscribers, and jobs are resolved into the application at build time. See [Configuration](/docs/platform/fundamentals/configuration).

<Note>
  The decision distinguishes error modes precisely. An item with no registered adapter returns an `unbuyable` decision with `unsupported_item`; duplicate adapter ids throw at registration; an adapter that fails at evaluation returns an `error` decision with `adapter_failed` and an error trace; a buyable decision that lacks pricing facts is rejected as `adapter_invalid_result`. A buyable decision must always carry real pricing.
</Note>

## Links to other modules

* **[catalog](/docs/platform/modules/catalog)** supplies the item reference. Commerce reads the catalog plane to know what is being priced; for sourced items, the catalog source adapter's `liveResolve` feeds the price-availability adapter.
* **[inventory](/docs/platform/modules/inventory)** registers the operated price-availability adapter, reporting Product pricing and Slot availability into the decision.
* **[distribution](/docs/platform/modules/distribution)** supplies channel and commission context. A decision is scoped to a Channel, and what the channel earns (its commission rule) is reconciled and settled in distribution.
* **bookings** is where a decision becomes a commitment. The booking captures the commercial snapshot evidence alongside its own per-line transactional state.
* **finance** consumes the priced components, taxes, and fees when it issues invoices.

## React package

The `@voyant-travel/commerce-react` family owns the reusable commercial UI under owner-path subpaths: `@voyant-travel/commerce-react/markets`, `@voyant-travel/commerce-react/pricing`, `@voyant-travel/commerce-react/promotions` (with an `/admin` surface), and `@voyant-travel/commerce-react/sellability`. Prefer these for any commerce-owned admin or storefront wiring.

## Next steps

<CardGroup cols={2}>
  <Card title="Catalog" icon="layer-group" href="/docs/platform/modules/catalog">
    The sellable plane commerce prices, owned and sourced alike.
  </Card>

  <Card title="Inventory" icon="calendar-days" href="/docs/platform/modules/inventory">
    The operated availability and pricing the commercial decision reads.
  </Card>

  <Card title="Distribution" icon="share-nodes" href="/docs/platform/modules/distribution">
    Channels and commission rules that scope the commercial decision.
  </Card>

  <Card title="Glossary" icon="book-open" href="/docs/concepts/glossary">
    Cost, Rate, Price, Market, and Sellability defined precisely.
  </Card>
</CardGroup>
