AI agents are starting to change the assumptions behind commerce software.
For a long time, e-commerce platforms were designed around human interpretation. A product page could combine structured data, marketing copy, policy fragments, trust signals, pricing, availability indicators, and checkout calls to action. A human buyer could read those elements together and decide what they meant.
That model does not transfer cleanly to agentic commerce.
When an AI agent interacts with a commerce system, ambiguity becomes a system-design problem. The agent should not need to infer whether a product can be recommended, whether inventory is fresh, whether a policy applies, whether checkout is allowed, or whether payment authority exists. Those decisions need to be represented explicitly by the platform.
This article is the first in a technical series about designing an agent-ready commerce platform. The focus is not on adding a chatbot to an e-commerce UI. The focus is on the lower-level architecture required when external agents, tools, and protocols need to interact with commerce workflows safely.
The platform boundary is changing
Traditional e-commerce platforms expose experiences primarily through pages and user-driven flows:
Product page → Cart → Checkout → Payment → Order
That flow assumes a human is driving the process. The platform presents information, the user interprets it, and the user decides what to do next.
Agentic commerce introduces a different interaction model. A system may need to answer questions such as:
- Which products are discoverable by agents?
- Which product facts are fresh enough to use?
- Which policies apply to a specific product, region, or checkout context?
- Which actions are allowed for a product?
- Is checkout preparation allowed?
- Is delegated payment allowed?
- Does the action require human confirmation?
- What evidence supports the decision?
- What should happen if an agent retries the same command?
These are not only API design questions. They are domain modeling questions.
A more useful mental model for agent-ready commerce is:
Facts → Eligibility → Authority → State transition → Evidence → Audit
This model is less familiar than the page-based e-commerce flow, but it captures the main architectural shift. A commerce platform that interacts with agents must expose more than products and endpoints. It must expose the conditions under which commercial actions are valid.
Product data is not the same as commercial truth
A common first step is to expose a structured product feed. That is necessary, but incomplete.
A basic product record might look like this:
type Product = {
id: string;
name: string;
price: number;
currency: string;
inStock: boolean;
};
This structure is useful for rendering a storefront or indexing a catalog. It is not enough for an agent deciding whether a product can be recommended, compared, added to cart, or used in a checkout flow.
The missing layer is commercial truth: the platform’s current, source-backed understanding of the product as a commercial object.
For example:
type ProductTruthSummary = {
productId: string;
priceFreshness: "fresh" | "stale" | "unknown";
inventoryFreshness: "fresh" | "stale" | "unknown";
policyCoverage: "complete" | "partial" | "missing";
sourceStatus: "verified" | "changed" | "unverified";
agentVisible: boolean;
};
This structure separates raw product data from the confidence and completeness required to use that data in agent-facing decisions.
A product may exist in the catalog but still be unsuitable for agent discovery. A product may be discoverable but not checkout-ready. A product may be checkout-ready but not eligible for delegated payment. A product may have a fresh price but stale inventory. A product may have valid inventory but missing return-policy coverage.
A human can often work around those inconsistencies. An agent should not have to.
This is the first major design principle in agent-ready commerce:
Do not ask agents to infer commercial truth from presentation surfaces.
Expose commercial truth directly.
Availability is too broad
Many e-commerce systems use product availability as a broad gate. The product is active, in stock, and therefore available.
That approach breaks down once agent actions become more specific.
Consider a simple implementation:
function canCheckout(product: Product) {
return product.active && product.inStock;
}
This function answers a narrow question, but the platform usually needs to answer several different questions:
- Can the product appear in an agent-visible catalog?
- Can the product be compared against alternatives?
- Can the agent quote policies for it?
- Can the agent add it to a cart?
- Can the agent prepare checkout?
- Can the agent delegate payment?
- Does the product require human confirmation?
These actions do not have the same risk profile. Treating them as one availability decision makes the model too coarse.
A more explicit action model is easier to reason about:
type AgentCommerceDecisionAction =
| "discover"
| "compare"
| "quote_policy"
| "add_to_cart"
| "prepare_checkout"
| "delegate_payment"
| "complete_checkout"
| "show_generated_claim"
| "explain";
Each action can then produce its own decision:
type ActionEligibilityDecision = {
productId: string;
requestedAction: AgentCommerceDecisionAction;
allowed: boolean;
blockers: Array<{
code: string;
severity: "info" | "warning" | "blocker";
message: string;
nextAction: string;
}>;
};
The important part is not the exact TypeScript shape. The important part is the separation of concerns.
A product can be safe to discover but unsafe to purchase. It can be safe to compare but unsafe to quote because policy facts are incomplete. It can be safe to prepare checkout but unsafe for delegated payment because payment authority has not been established.
This creates a more reliable interface for agents and a more useful operational model for merchants.
Instead of returning a generic rejection, the platform can return a reason:
Product is discoverable but checkout is blocked because inventory freshness is stale.
That kind of response is useful to both the agent and the operator. The agent knows not to proceed. The operator knows what to fix.
Policies need to become structured facts
Policy text is another area where human-first assumptions leak into the system.
A human can read a returns page and interpret whether a product is likely covered. An agent should not rely on free-text interpretation when quoting commercial terms.
Policy data needs to be connected to products, categories, markets, and actions.
A simplified policy fact might look like this:
type PolicyFact = {
policyType: "returns" | "shipping" | "warranty" | "cancellation";
appliesTo: {
productIds?: string[];
categoryIds?: string[];
region?: string;
};
status: "known" | "missing" | "stale" | "conflicting";
summary: string;
sourceRef: string;
lastVerifiedAt: string;
};
This gives the platform a way to distinguish between several conditions that would otherwise collapse into vague policy text:
- The policy is known and applies to the product.
- The policy exists but is stale.
- The policy exists but does not apply in the buyer’s region.
- Two policy sources conflict.
- The product is missing required policy coverage.
- The policy can be shown to a human but should not be quoted by an agent.
The distinction matters because an incorrect policy claim is not just a technical bug. It can become a customer-support issue, a trust issue, or a compliance issue.
Agent-ready systems therefore need to treat policy facts as part of the commerce domain, not as static content attached to the storefront.
Protocol adapters should stay thin
Agent-commerce platforms are likely to interact with multiple external protocol surfaces. Some protocols focus on product discovery. Some focus on tool use. Some focus on checkout or payment authority. Some may be specific to a marketplace, assistant, payment provider, or agent runtime.
A common architecture mistake is to let each protocol adapter make its own business decisions.
For example:
ACP interaction decides checkout eligibility
UCP adapter decides cart or checkout capability
MCP tool decides product visibility
AP2-related payment adapter decides mandate validity
Admin UI calculates its own issue status
Feed publisher calculates another version of availability
That structure may work temporarily, but it tends to create contradictions. One surface says the product is available. Another says it is blocked. The admin UI shows a third status. The feed publisher uses a fourth rule.
A safer architecture keeps adapters thin:
External protocol
↓
Protocol adapter
↓
Internal domain command/query
↓
Canonical decision path
↓
Protocol-specific response
The adapter translates between external protocol shape and internal domain shape. It should not own the core decision.
This separation is especially important while agent-commerce protocols are still evolving. If the domain model is independent from the protocol adapter, new protocol versions can be supported without rewriting the business rules.
The platform can then maintain one internal answer to questions such as:
- Is the product discoverable?
- Is checkout allowed?
- Is delegated payment allowed?
- Which blockers apply?
- Which evidence supports the result?
ACP- and UCP-style commerce surfaces, MCP tools, AP2-related payment flows, feeds, storefronts, admin tools, and support views can expose that answer in different formats, but the decision remains owned by the domain.
Using one shared decision envelope for every surface
A decision-centered architecture only works if each surface can ask the platform for the same commercial answer.
If the adapter shortcut is one line:
product.active && inventory.status == "in_stock" && price.amount < 150
and the domain path requires three calls across unrelated modules, the system is inviting local decision logic to reappear. Under pressure, a feed, checkout flow, or tool adapter will eventually choose the path that is easiest to reach.
That is why agent-ready commerce needs more than the right boxes on a diagram. It needs an ergonomic decision path.
The platform should make this the boring path:
Build or reuse the commerce decision.
Return one shared decision envelope.
Project that envelope to the surface.
A decision envelope is a structured record of the platform's answer for one requested action. It keeps the related decisions together without collapsing them into one boolean:
eligibility
actor authority
checkout state
payment authority
generated-claim projection state
freshness and hash-pinned evidence references
next safe actions
At the contract boundary, the envelope can also carry decisionId, contractVersion, envelopeSchemaVersion, content-addressed rule-set identity, inputDependencyHash, resultHash, decisionHash, and an explicit authenticator.
The three hashes answer different questions:
-
inputDependencyHash: Which action, subject, actor, rules, evidence, and freshness inputs were evaluated? -
resultHash: Which eligibility, authority, checkout, payment, claim, and next-action results were produced? -
decisionHash: Which contract and schema bind those inputs and results together?
The protected input boundary should include the decision identity, requested surface and action, actor, subject, inputs, evidence, freshness dependencies, and rule-set identity. A surface may omit internal detail, but an externally verifiable projection should preserve the rule-set identity, hashes, authenticator, and freshness information needed to validate the result.
At an external projection boundary, the platform should capture any externally supplied or persisted envelope once into a detached, deeply frozen, JSON-compatible snapshot. Hash recomputation, authenticator verification, request binding, freshness evaluation, and projection should all consume that same captured value rather than re-read caller-controlled state. The platform should then confirm the target surface, reject stale allowed output on action-bearing external surfaces, and compare the protected requested action, subject, and actor with the live request.
Administrative and support projections may expose stale context for diagnosis, but they do not authorize execution. Before changing state, the platform should compare the decision's protected dependency hashes with current authoritative checkout, mandate, product, policy, price, inventory, payment, authority, claim, or evidence snapshots as applicable. A missing, changed, or expired dependency requires a fresh decision even when the envelope is still signed and within its original freshness window.
A feed can project one part of the envelope. A tool adapter can project another. Checkout can use the same envelope before mutation. Admin and support can show the same blocker codes and remediation path.
The important point is not that every surface shows the same fields. It is that every surface starts from the same commercial meaning, and that meaning stays tied to the use and evidence that produced it.
Checkout is a lifecycle, not a single action
Checkout is often presented as a button in the UI, but backend systems already know that checkout is a lifecycle. Agentic commerce makes that lifecycle more explicit.
A checkout session may need to pass through several states:
type AgentCommerceCheckoutLifecycleState =
| "created"
| "empty"
| "requires_address"
| "requires_shipping_option"
| "requires_payment"
| "requires_revalidation"
| "blocked"
| "payment_authorized"
| "order_submitted"
| "completed"
| "declined"
| "cancelled"
| "expired"
| "failed";
Each transition has conditions. A draft session should not become validated unless prices, inventory, and policy constraints have been checked. A session should not move into payment authorization unless the required authority exists. A completed session should usually be terminal. A repeated command should be handled safely.
The checkout should keep one current state and append a meaningful event when an accepted or blocked command changes the lifecycle or must remain reconstructable:
type EvidenceRef = {
type: string;
id: string;
hash: string;
hashAlgorithm: "sha256";
};
type CheckoutEvent = {
checkoutId: string;
operation: "create" | "read" | "update" | "confirm" | "complete" | "cancel" | "expire";
previousState: AgentCommerceCheckoutLifecycleState;
nextState: AgentCommerceCheckoutLifecycleState;
accepted: boolean;
actorType: "buyer" | "agent" | "operator" | "system";
reasonCodes: string[];
evidenceRefs: EvidenceRef[];
occurredAt: string;
};
This does not require a separate database row for every internal validation. The current checkout record answers, “Where is checkout now?” The event history answers, “Which meaningful command changed or failed to change it, and why?”
The key design point is that agents should not be allowed to move commerce state arbitrarily. They should submit commands, and the platform should decide whether the requested transition is valid.
That decision depends on facts, eligibility, authority, and current state.
This makes checkout a good example of the broader architecture pattern:
Agent request → Command validation → Authority check → Current-state decision → Meaningful checkout event
Payment authority is a separate domain
Payment authority is one of the areas where vague models become dangerous.
In a human-driven checkout flow, the user typically sees the final cart and authorizes payment directly. In an agent-driven or agent-assisted flow, the platform must be more precise about what authority the agent has.
A boolean such as paymentAllowed is not expressive enough.
A delegated payment flow needs boundaries:
type AgentCommerceMandateRecord = {
mandateId: string;
buyerId: string;
actorId: string;
merchantId: string;
checkoutId: string;
cartSnapshotHash: string;
maxAmount: number;
currency: string;
allowedActions: Array<"delegate_payment" | "complete_checkout">;
allowedProductIds: string[];
expiresAt: string;
confirmationStatus: "not_required" | "required" | "confirmed";
consumedAt?: string;
revokedAt?: string;
};
A payment attempt can then be evaluated against the mandate:
type AgentCommercePaymentAuthorityVerdict = {
allowed: boolean;
amountWithinLimit: boolean;
currencyMatches: boolean;
merchantMatches: boolean;
productScopeMatches: boolean;
cartSnapshotMatches: boolean;
mandateNotExpired: boolean;
mandateNotRevoked: boolean;
humanConfirmationSatisfied: boolean;
};
This separates payment execution from payment authority.
Payment execution asks, “Can the provider process this request?”
Payment authority asks, “Is this exact request still inside the authority the buyer granted?”
A provider can accept a technically valid payment request even when the commerce platform should not have sent it. That is why the authority decision must come first.
Idempotency becomes part of the safety model
Agent-driven systems must assume retries.
A request can time out after the backend has already completed the operation. An agent may retry a command because it did not receive the previous response. A payment command may be submitted twice. A checkout mutation may be replayed.
Idempotency means that retrying the same command does not perform the commercial action twice. It is therefore not just an implementation detail. It is part of the safety model.
A command needs identity:
type AgentCommand = {
commandId: string;
idempotencyKey: string;
actorId: string;
actorType: "human" | "agent" | "system";
action: string;
payloadHash: string;
requestedAt: string;
};
The platform should be able to answer:
- Has this command been seen before?
- Was the payload identical?
- Did the previous execution complete?
- Is it safe to return the previous result?
- Is this a replay attempt?
- Is the same idempotency key being reused with a different payload?
This is especially important for payment and checkout operations, where duplicate execution can create real financial or operational damage.
The operator view should not mirror the internal architecture
As the backend becomes more explicit, the internal state can become large: product facts, policy facts, feed health, checkout and mandate events, payment authority, protocol responses, transaction correlation, attribution records, privacy rules, and audit timelines.
Exposing all of that directly to operators usually creates a poor admin experience.
Operators need decisions and tasks, not a raw map of internal subsystems.
A task-oriented view is usually more useful:
type MerchantTask = {
owner: "catalog" | "policy" | "checkout" | "payment" | "operations";
status: "healthy" | "needs_attention" | "blocked";
issue: string;
nextAction: string;
fixImpact: string;
sampleRefs: string[];
};
The task model translates system state into operational work:
Inventory freshness is stale for 12 agent-visible products.
Checkout is blocked until the catalog source is revalidated.
That is more useful than exposing five different internal panels and expecting the operator to infer the business impact.
The admin UI should not leak the architecture unless the user needs to debug at that level. The default view should help the operator answer three questions:
What is wrong?
Why does it matter?
What should be fixed next?
AI-generated commerce content needs authority boundaries
AI-assisted store creation introduces a related problem.
Generating storefront content is not difficult. Generating commercially safe storefront content is harder.
A model can produce product descriptions, category pages, policy summaries, promotional text, and landing-page copy very quickly. But generated content should not automatically become commercial truth.
The platform needs to distinguish between generated content and approved claims.
In this series, projection means a surface-specific view of commercial truth. It is not a new source of truth. For generated text, projection is stricter: the platform returns whether a claim may be used for a specific surface and use, with its source and freshness state still attached.
For example:
type AxisStatus = "passed" | "failed" | "not_evaluated";
type GeneratedClaimStatus =
| "allowed"
| "requires_review"
| "refused_here"
| "inherited_refusal"
| "stale"
| "out_of_scope"
| "absent";
type GeneratedCommerceClaimSummary = {
claimId: string;
claimType: "product" | "policy" | "shipping" | "warranty" | "promotion";
status: GeneratedClaimStatus;
sourceRefs: string[];
axes: Record<
"source" | "freshness" | "scope" | "surface" | "use" | "payload" | "taint",
AxisStatus
>;
inheritedRefusalCount: number;
approvedValueHash?: string | null;
claimTextHash?: string | null;
publishBlocked: boolean;
};
This prevents a generated storefront from publishing unsupported statements such as:
- inaccurate warranty claims
- unapproved discounts
- unsupported shipping promises
- unavailable product references
- policy claims not backed by a source
- external links that have not been reviewed
The same principle appears again: AI output should not become business authority automatically. It should be projected through explicit rules that keep source, freshness, scope, surface, and use attached to the text.
Maintainability is not separate from agent readiness
Agent-ready commerce adds concepts to the platform. Without clear ownership, those concepts can easily become scattered across routes, clients, UI components, protocol adapters, and helper files.
That creates a maintainability problem with commercial consequences.
If product eligibility is calculated in one API route, policy coverage in a frontend component, checkout validation in a payment adapter, and agent visibility in a feed publisher, the system will eventually contradict itself.
The architecture needs clear ownership:
Commercial truth owns selected source-backed facts.
Policy owns applicability and quotability.
Eligibility owns action-specific validity.
One checkout application owner coordinates human and agent checkout behavior.
One delegated-authority owner coordinates mandate scope, confirmation, consumption, and revocation.
Payment owns execution and provider interaction.
Order owns order state.
A transaction coordinator correlates checkout, mandate, payment, and order events without copying their state.
Protocol adapters translate decisions.
UI surfaces render decisions.
The deployment and folder structure can vary. The important rule is that reusable commercial meaning has one owner and every external surface projects from that meaning.
That keeps the core small. The durable business rails are these:
Product facts
Policy facts
Checkout state
Payment limits
Evidence, audit, attribution, protocol projection, and operator views should attach to those rails instead of becoming separate rule systems that every surface has to reimplement.
With a shared decision envelope, an adapter developer should not need to know every product, policy, checkout, and payment rule before building a feed or tool response. The developer asks the platform for the decision, then projects that decision to the required surface.
This is especially important in an AI-assisted development environment. Code is becoming easier to generate, which means duplication and architectural drift can happen faster. The limiting factor is not only implementation speed. It is the ability to keep the system coherent as it grows.
What this series will cover
This first article defines the main architectural problem: agent-ready commerce requires platforms to expose facts, eligibility, authority, state transitions, evidence, and operational tasks explicitly.
The rest of the series will go deeper into each area:
- Agent-Ready Commerce, Part 1: Building a Platform for the AI Era
- Agent-Ready Commerce, Part 2: From Product Pages to Commercial Truth
- Agent-Ready Commerce, Part 3: Why “Available” Is Not Enough for AI Agents
- Agent-Ready Commerce, Part 4: Making Policies Machine-Readable
- Agent-Ready Commerce, Part 5: Keeping ACP, UCP, MCP, and AP2 Adapters Thin
- Agent-Ready Commerce, Part 6: Checkout Is a State Machine, Not a Form
- Agent-Ready Commerce, Part 7: Delegated Payment Needs More Than a Token
- Agent-Ready Commerce, Part 8: Generated Claims Need Review, Evidence, and Expiry
- Agent-Ready Commerce, Part 9: Evidence and Audit Are Part of the Product
- Agent-Ready Commerce, Part 10: The Reference Architecture
The series is not intended to define a universal standard. Protocols, payment models, and agent runtimes are still evolving. The goal is to document the system boundaries that become important once AI agents are treated as real commerce actors rather than as chat interfaces attached to existing flows.
The core idea
Agent-ready commerce is not primarily a UI problem. It is not solved by adding an assistant to a storefront, and it is not solved by exposing a product feed alone.
The deeper challenge is architectural.
Commerce platforms need to make hidden assumptions explicit: product truth, policy coverage, action eligibility, checkout state, payment authority, mutation safety, generated-claim projection, provenance state, and operator remediation.
Human users can tolerate ambiguity in ways that agents should not be expected to. If agents are going to discover products, compare options, prepare checkout, or act within delegated authority, the platform needs to expose the rules of commerce in a form that software can evaluate.
That is the core idea behind agent-ready commerce:
Pages are for human interpretation.
Decision envelopes are for machine-safe action.
The rest of this series will examine how those decision envelopes and supporting layers work in practice.
About the author
Written by Dimitrios S. Sfyris, Founder & Software Architect at AspectSoft.
AspectSoft designs and develops custom software platforms, e-commerce systems, SaaS infrastructure, integrations, analytics tools, and practical digital products.
You can also follow the AspectSoft LinkedIn page for updates on software platforms, commerce systems, AI tooling, and developer-focused products.
Top comments (0)