Live Price, Inventory and Delivery for AI Shopping Agents
Design live commerce state for AI shopping agents with authoritative reads, reservations, expiry, idempotent retries and checkout reconciliation.

AI shopping agents should use indexed data to find candidates and authoritative live APIs to promise price, inventory and delivery. Each live observation needs a source, market, customer context, timestamp and expiry. Scarce inventory needs a reservation with explicit lifecycle state. Retries need stable idempotency keys, and checkout must reconcile any changed state instead of trusting the earlier conversation.
This article is for commerce architects connecting retrieval to checkout. The outcome is a state model that prevents an agent from presenting an indexed product fact as a current commercial commitment.
Start with the ecommerce product discovery guide and the companion agent-readable product schema.
Stable facts and live facts belong on different paths
Index fields that change slowly: title, product family, variant options, dimensions, materials, compatibility references and evidence digests. Fetch fields whose value depends on time or transaction context:
| Field | Indexed candidate data | Authoritative live read |
|---|---|---|
| Product title | yes | optional refresh |
| Variant identity | yes | verify it remains sellable |
| List price | useful for discovery | required before a promise |
| Customer or contract price | no | required with buyer context |
| Inventory | coarse status at most | required by location |
| Promotion | searchable campaign metadata | validate eligibility and expiry |
| Delivery | estimate for discovery | compute for destination and cutoff |
| Tax and final total | no | checkout authority |
Google Merchant Center treats price and availability mismatches as data-quality failures and requires the submitted values to match landing and checkout surfaces. Google's product-data specification is not a transactional agent protocol, but it illustrates the operational cost of stale state.
Define a live observation contract
Do not return bare values such as price: 49.99 or in_stock: true.
type LiveOfferObservation = {
observationId: string;
offerId: string;
merchantId: string;
variantId: string;
market: string;
buyerContextId?: string;
price: { amount: string; currency: string; includesTax: boolean };
inventory: {
status: 'available' | 'limited' | 'unavailable' | 'unknown';
quantity?: number;
locationId?: string;
};
delivery: {
earliestDate?: string;
latestDate?: string;
serviceLevel?: string;
status: 'estimated' | 'confirmed' | 'unknown';
};
observedAt: string;
expiresAt: string;
sourceVersion?: string;
};
unknown is not the same as unavailable. If the inventory API times out, the agent should not tell the buyer that the product is sold out. It should say that availability could not be confirmed and either retry or offer alternatives.
Contextual pricing can depend on country, company, customer segment, quantity or contract. Shopify exposes contextual product pricing rather than assuming one universal value. Shopify's contextual pricing object supports the design rule: include the pricing context in the cache key and evidence.
Query live state after candidate retrieval
Do not call three merchant APIs for every item in a 100,000-product catalog. Retrieve and filter first, then enrich a bounded candidate set.
intent
-> structured and semantic retrieval
-> 50 candidate variants
-> compatibility and market filters
-> 10 eligible offers
-> parallel live-state reads
-> remove unknown or invalid candidates according to policy
-> 3 to 5 evidence-rich choices
Control concurrency and deadlines. If one merchant takes four seconds, the whole response should not hang indefinitely.
async function enrichCandidates(candidates: Candidate[], ctx: BuyerContext) {
return mapWithConcurrency(candidates, 8, async (candidate) => {
const result = await withTimeout(
merchant.getLiveOffer(candidate.offerId, ctx),
750,
);
return result.ok
? { candidate, state: validateObservation(result.value, ctx) }
: { candidate, state: { status: 'unknown', reason: result.code } };
});
}
The timeout and concurrency values are illustrative. Measure them against merchant service-level objectives and the value of waiting for another candidate.
Delivery is a calculation, not a catalog attribute
Delivery depends on stock location, destination, handling time, carrier service, order cutoff, weekends, holidays and sometimes the contents of the full basket. A static ships_in_2_days field cannot represent this.
Ask the authoritative fulfillment service with the actual variant, quantity and destination. Record whether the response is an estimate or a confirmed promise. A date range should carry its timezone and cutoff assumptions.
Google's 2026 Merchant Center update added product-level handling cutoff and minimum-order attributes, which shows how fulfillment context keeps expanding beyond a single shipping string. The 2026 product-data update supports discovery presentation, but checkout still needs the merchant's live calculation.
Reservations turn observations into temporary claims
An observation says inventory was available. A reservation asks the merchant to hold a quantity for a bounded time.
type Reservation = {
reservationId: string;
idempotencyKey: string;
offerId: string;
variantId: string;
quantity: number;
locationId: string;
status: 'pending' | 'held' | 'committed' | 'released' | 'expired' | 'unknown';
createdAt: string;
expiresAt: string;
merchantReference?: string;
};
Use reservations only when their operational cost is justified. Reserving every viewed product can lock inventory and become an abuse vector. Trigger a reservation after clear purchase intent, or when the item is scarce and the buyer has accepted the tradeoff.
The merchant owns the reservation state. The agent stores a reference, not an invented local hold.
Use a state machine for expiry and uncertainty
OBSERVED -> RESERVATION_PENDING -> HELD -> CHECKOUT_PENDING -> COMMITTED
| | |
v v v
UNKNOWN EXPIRED RELEASED
If a reservation request times out, do not create a second reservation with a new key. Mark the operation unknown and query the merchant by the original idempotency key.
async function recoverReservation(op: ReservationOperation) {
const remote = await merchant.findReservation({
idempotencyKey: op.idempotencyKey,
});
if (remote.found) return reconcileLocal(remote);
if (remote.authoritativelyAbsent) return retrySameRequest(op);
return keepUnknownAndEscalate(op);
}
"Not found" must be authoritative. A delayed read replica can report absence while the write exists elsewhere.
Price acceptance needs an offer version
An agent may show EUR 129.90, then reach checkout after the promotion expires. Bind the displayed terms to an offer digest and validity window:
{
"offer_id": "offer:merchant-7:TS8-BLU-43:DE",
"revision": 18,
"price": { "amount": "129.90", "currency": "EUR" },
"quantity": 1,
"delivery_latest": "2026-08-14",
"valid_until": "2026-08-11T10:15:00Z",
"digest": "sha256:a482..."
}
At checkout, either honor this signed or server-issued offer, or return a structured change. Do not quietly charge the new amount.
UCP's Checkout capability models a stateful checkout session and requires binding transaction data for eligibility and policy at completion. It also permits buyer review or escalation when the resource needs attention. UCP Checkout provides a useful protocol boundary between provisional context and final commerce state.
Retry and idempotency rules
Use separate stable keys for reservation, checkout completion and payment. A conversation turn ID is a poor idempotency key because the agent may create a new turn during recovery.
Store a request fingerprint with each key. If the same key arrives with a different quantity, offer or destination, return a conflict.
INSERT INTO commerce_operations
(tenant_id, operation_type, idempotency_key, request_digest, state)
VALUES
($1, 'reserve_inventory', $2, $3, 'pending')
ON CONFLICT (tenant_id, operation_type, idempotency_key) DO NOTHING;
The caller then reads the existing row and verifies the digest. Database deduplication alone does not tell you whether the merchant executed. Reconciliation closes that gap.
Failure and recovery matrix
| Failure | Safe response |
|---|---|
| Indexed price differs from live price | show live price and mark discovery value stale |
| Inventory read times out | return unknown, not unavailable |
| Reservation times out after dispatch | query by same idempotency key |
| Reservation expires before checkout | refresh and request consent to continue |
| Delivery service loses destination context | reject estimate as incomplete |
| Currency changes during localization | recompute and issue new offer revision |
| Two agents reserve final unit | only authoritative hold succeeds |
| Checkout total changes | require review under configured threshold |
| Merchant webhook arrives twice | deduplicate by event ID and version |
| Webhook arrives out of order | apply monotonic state/version rules |
| Cache serves another buyer's contract price | tenant and context isolation test fails |
| Payment succeeds but order response times out | reconcile payment and order separately |
Reproducible evaluation
Build a fake merchant service with a controllable clock and deterministic fault injection. Seed one offer at revision 18, two units of inventory and a reservation TTL of five minutes.
Run these scenarios:
- Retrieve the offer, advance time beyond
expiresAt, and verify checkout rejects it. - Dispatch a reservation, drop the response, retry with the same key, and verify one hold exists.
- Retry with the same key but quantity two, and verify an idempotency conflict.
- Return inventory events out of order, and verify the older version cannot restore stock.
- Vary buyer context and verify contract prices never cross cache keys.
- Expire a hold during checkout and verify no payment call occurs.
Record upstream-call count, final reservation state, reason codes and the displayed customer message. The evaluation passes only when the system avoids false availability and duplicate holds.
Current Intelliger boundary
Live merchant connectors, authoritative price and inventory calls, reservation orchestration, Commerce Graph and Merchant Agent Runtime are target-state components in the August 2026 Intelliger blueprint. They are not current production claims.
OATI Commerce currently provides developer-preview schemas and deterministic evaluation for signed price, currency, budget, usage and substitution constraints. Its local sandbox demonstrates a paid API transaction. The hosted Commerce profile proves profile discovery, not a live retail inventory or checkout integration.
The agentic-commerce infrastructure article explains why live state belongs below the assistant. The agentic commerce architecture shows the intended buyer-facing layer.
Implementation checklist
- Index stable product facts and fetch volatile state late.
- Include market, buyer context, source, observation and expiry.
- Distinguish unknown from unavailable in APIs and customer language.
- Compute delivery for the actual quantity and destination.
- Reserve inventory only after suitable purchase intent.
- Model held, expired, released and unknown states explicitly.
- Carry stable idempotency keys through retries.
- Store request digests and reject key reuse with changed intent.
- Reconcile merchant state after ambiguous responses.
- Refresh or bind accepted terms at checkout.
- Test tenant cache isolation, event order and clock expiry.
Review note: a commerce-platform expert should verify reservation semantics, inventory authority, tax and pricing assumptions, and each merchant connector's idempotency guarantees before production use.
Use the agent-readable schema fixture as the indexed input, then test the live transition with the evaluation scenarios above.