cresvadevelopers
v2.0Current

Agent Commerce Protocol Specification

The formal specification for ACP v2.0. This document defines the complete protocol for AI agent-to-brand commerce.

1. Introduction

The Agent Commerce Protocol (ACP) is an open standard that defines how AI shopping agents interact with brand storefronts. It provides a structured, machine-readable interface for product discovery, search, negotiation, and transactions.

Purpose

ACP enables any AI agent — whether it's ChatGPT, Claude, Gemini, or a custom shopping assistant — to query products, negotiate prices, and complete purchases from any ACP-compatible storefront using a single, consistent protocol.

Design Goals

  • Simplicity: RESTful JSON APIs that any developer can implement in hours
  • Machine-readability: Every response is structured for AI consumption, not human browsing
  • Extensibility: Custom attributes and metadata without breaking the protocol
  • Backward compatibility: New features never break existing integrations within a major version

Versioning

ACP uses semantic versioning. The current version is 2.0. Minor versions (2.1, 2.2) add features without breaking changes. Major versions (3.0) may introduce breaking changes with a 6-month deprecation window.

2. Protocol Overview

Architecture

ACP follows a three-tier architecture:

AI Agent (Client)
↕ HTTPS + JSON
Cresva Storefront API (ACP Server)
↕ Internal
Brand Backend (Catalog, Pricing, Inventory)

Request/Response Lifecycle

  1. Agent sends an authenticated request to the storefront API endpoint
  2. The storefront validates the API key, rate limits, and request schema
  3. The request is processed against the brand's catalog and policies
  4. A structured JSON response is returned with product data, negotiation state, or transaction status
  5. The agent parses the response and presents results to the user

Base URL

URL
https://cresva.ai/api/storefront/{brandId}

All endpoints are relative to this base URL. Replace {brandId}with the brand's unique identifier.

Content Type

All requests and responses use application/json. Requests must include the Content-Type: application/json header for POST/PUT/PATCH methods.

3. Discovery

Discovery allows AI agents to find ACP-compatible storefronts. Brands publish a discovery file at a well-known URL, similar to robots.txt but designed for AI agents.

Discovery File

Every ACP-compatible storefront MUST serve a JSON file at:

HTTP
GET https://{domain}/.well-known/acp.json

The discovery file format:

JSON
{
  "acp_version": "2.0",
  "storefront_url": "https://cresva.ai/api/storefront/brand_abc123",
  "brand_id": "brand_abc123",
  "brand_name": "Acme Co",
  "capabilities": [
    "search",
    "recommend",
    "compare",
    "negotiate",
    "transact"
  ],
  "supported_currencies": ["USD", "EUR"],
  "supported_languages": ["en", "es", "fr"],
  "rate_limits": {
    "public": "100/minute",
    "authenticated": "1000/minute"
  },
  "documentation": "https://developers.cresva.ai/protocol/spec"
}

Discovery File Fields

acp_versionstringrequired

Protocol version. Currently "2.0".

storefront_urlstringrequired

The base URL for all API requests to this storefront.

brand_idstringrequired

Unique identifier for the brand.

brand_namestringrequired

Human-readable brand name.

capabilitiesstring[]required

List of supported ACP features: search, recommend, compare, negotiate, transact.

supported_currenciesstring[]

ISO 4217 currency codes accepted by this storefront.

supported_languagesstring[]

ISO 639-1 language codes supported.

rate_limitsobject

Rate limit information by key type.

documentationstring

URL to the storefront's API documentation.

4. Query Protocol

The query protocol is the primary interface for agents to search and retrieve products. All queries go through a unified endpoint that supports multiple intent types.

Endpoint

HTTP
POST /query

AgentQueryRequest

The request body for a query:

intentstringrequired

One of: "search", "recommend", "compare", "detail", "review", "availability".

querystring

Natural language query string. Required for search intent.

product_idsstring[]

Product IDs for detail, compare, review, or availability intents.

filtersQueryFilters

Structured filters to narrow results.

contextQueryContext

Additional context about the user's shopping session.

sortstring

Sort order: "relevance", "price_asc", "price_desc", "rating", "newest".

offsetnumber

Pagination offset. Default: 0.

limitnumber

Results per page. Default: 10, max: 50.

QueryFilters

categorystring

Product category path, e.g. "electronics/audio/headphones".

pricePriceRange

Price range with min, max, and currency.

attributesRecord<string, any>

Key-value pairs for product attributes.

in_stockboolean

Filter to only in-stock products.

brandstring

Filter by sub-brand or product line.

rating_minnumber

Minimum average rating (1-5).

QueryContext

budgetstring

User's budget level: "budget", "moderate", "premium", "luxury".

preferencesstring[]

User preferences that should influence ranking.

session_idstring

Session ID for tracking multi-turn conversations.

platformstring

The AI platform making the request (e.g. "chatgpt", "claude").

AgentQueryResponse

productsAgentProductCard[]required

Array of product cards matching the query.

totalnumberrequired

Total number of matching products.

query_idstringrequired

Unique ID for this query (for analytics and follow-ups).

filters_appliedobject

Echo of which filters were actually applied.

suggestionsstring[]

Alternative query suggestions if results are limited.

categoriesCategoryFacet[]

Available category facets for refinement.

Example

HTTP
POST /query
Authorization: Bearer pk_live_your_key_here
Content-Type: application/json

{
  "intent": "search",
  "query": "running shoes for marathon training",
  "filters": {
    "category": "sports/footwear/running",
    "price": { "max": 180, "currency": "USD" },
    "in_stock": true
  },
  "context": {
    "budget": "moderate",
    "preferences": ["cushioning", "durability"]
  },
  "limit": 5
}

5. Product Card Format

The AgentProductCard is the standard format for representing a product to an AI agent. It is optimized for machine consumption — structured, typed, and rich with metadata.

AgentProductCard Fields

idstringrequired

Unique product identifier.

titlestringrequired

Product title, optimized for AI readability.

pricenumberrequired

Current price.

currencystringrequired

ISO 4217 currency code.

urlstringrequired

Direct URL to the product page.

descriptionstring

Product description, typically 1-3 sentences.

imagesImageObject[]

Array of product images with URL, alt text, and dimensions.

attributesRecord<string, any>

Structured product attributes (color, size, material, etc.).

reviews_summaryReviewsSummary

Aggregated review data: average rating, count, and highlights.

availabilitystring

Stock status: "in_stock", "low_stock", "out_of_stock", "preorder".

trust_scoreTrustScore

Brand trust score with overall rating and tier.

comparison_highlightsstring[]

Key differentiators vs. similar products.

brand_voice_summarystring

How the brand describes this product in their own voice.

original_pricenumber

Original price before any discounts.

categoriesstring[]

Category paths this product belongs to.

Example

JSON
{
  "id": "prod_h7k2m",
  "title": "ProSound ANC-300 Wireless Headphones",
  "price": 179.99,
  "currency": "USD",
  "url": "https://acme.com/products/prosound-anc-300",
  "description": "Premium over-ear wireless headphones with adaptive noise cancellation, 40-hour battery life, and memory foam cushions for all-day comfort.",
  "images": [
    {
      "url": "https://cdn.acme.com/images/anc-300-black.jpg",
      "alt": "ProSound ANC-300 in matte black",
      "width": 1200,
      "height": 1200
    }
  ],
  "attributes": {
    "wireless": true,
    "noiseCancelling": true,
    "batteryLife": "40 hours",
    "weight": "250g",
    "color": "Matte Black",
    "connectivity": "Bluetooth 5.3"
  },
  "reviews_summary": {
    "average": 4.6,
    "count": 2847,
    "highlights": ["Excellent ANC", "All-day comfort", "Great battery"]
  },
  "availability": "in_stock",
  "trust_score": {
    "overall": 92,
    "tier": "Gold"
  },
  "comparison_highlights": [
    "40hr battery vs 30hr industry average",
    "250g — lightest in class",
    "Adaptive ANC with transparency mode"
  ],
  "brand_voice_summary": "Engineered for audiophiles who refuse to compromise on comfort or sound quality.",
  "original_price": 229.99,
  "categories": ["electronics/audio/headphones", "electronics/audio/wireless"]
}

6. Negotiation Protocol

The negotiation protocol enables AI agents to negotiate pricing with brand storefronts. This supports direct offers, counter-offers, and alternative deal structures.

Actions

initiateaction

Agent sends an initial offer for a product.

counteraction

Brand responds with a counter-offer.

acceptaction

Either party accepts the current offer.

rejectaction

Either party rejects and ends negotiation.

withdrawaction

Agent withdraws their offer before a response.

inquireaction

Agent asks what deals are possible without committing.

Endpoint

HTTP
POST /negotiate

Negotiation Request

actionstringrequired

One of: "initiate", "counter", "accept", "reject", "withdraw", "inquire".

negotiation_idstring

Required for all actions except "initiate" and "inquire".

product_idstringrequired

The product being negotiated.

offered_pricenumber

The price being offered (for initiate and counter).

currencystring

Currency of the offer. Default: storefront's primary currency.

quantitynumber

Number of units. Default: 1.

messagestring

Optional natural language message with the offer.

State Machine

INITIATED
  ├── COUNTERING (brand sends counter-offer)
  │     ├── COUNTERING (agent counters back)
  │     ├── ACCEPTED (either party accepts)
  │     └── REJECTED (either party rejects)
  ├── ACCEPTED (brand accepts initial offer)
  ├── REJECTED (brand rejects)
  ├── EXPIRED (no response within timeout)
  └── WITHDRAWN (agent withdraws offer)

Alternative Deal Types

  • Volume discount: Better price for buying multiple units
  • Bundle: Discount when purchasing with related products
  • Subscription: Lower per-unit price for recurring purchases
  • Time-limited: Special price valid for a limited window

Timeout Rules

Negotiations expire after 24 hours of inactivity by default. Brands can configure shorter timeouts. The expires_at field in the response indicates when the current offer expires.

Example: Initiating a Negotiation

JSON
// Request
POST /negotiate
{
  "action": "initiate",
  "product_id": "prod_h7k2m",
  "offered_price": 149.99,
  "currency": "USD",
  "quantity": 1,
  "message": "User is comparing with a competitor at $145"
}

// Response
{
  "negotiation_id": "neg_a1b2c3",
  "status": "COUNTERING",
  "original_price": 179.99,
  "offered_price": 149.99,
  "counter_price": 164.99,
  "currency": "USD",
  "message": "We can offer 8% off. Bundle with our carrying case for an additional 5% off.",
  "alternatives": [
    {
      "type": "bundle",
      "products": ["prod_h7k2m", "prod_case01"],
      "bundle_price": 189.99,
      "savings": "15%"
    }
  ],
  "expires_at": "2026-03-28T12:00:00Z"
}

7. Transaction Protocol

The transaction protocol manages the full lifecycle of a purchase, from cart creation through payment, fulfillment, and completion.

Transaction Lifecycle

CREATED → CONFIRMED → PAID → FULFILLING → COMPLETED
                                    ↘ CANCELLED
                         ↘ DISPUTED → RESOLVED

Endpoints

POST/transactionsCreate a new transaction
GET/transactions/{id}Get transaction status
POST/transactions/{id}/confirmConfirm a transaction
POST/transactions/{id}/cancelCancel a transaction

Escrow

ACP supports escrow for conditional purchases. Funds are held until conditions are met (e.g., product inspection, delivery confirmation). Escrow is managed through:

POST/transactions/{id}/escrow/releaseRelease escrowed funds to the seller
POST/transactions/{id}/escrow/disputeDispute and hold escrowed funds

Example: Creating a Transaction

JSON
// Request
POST /transactions
{
  "items": [
    {
      "product_id": "prod_h7k2m",
      "quantity": 1,
      "price": 164.99,
      "negotiation_id": "neg_a1b2c3"
    }
  ],
  "currency": "USD",
  "shipping_address": {
    "line1": "123 Main St",
    "city": "San Francisco",
    "state": "CA",
    "postal_code": "94102",
    "country": "US"
  }
}

// Response
{
  "transaction_id": "txn_x9y8z7",
  "status": "CREATED",
  "items": [...],
  "subtotal": 164.99,
  "shipping": 0,
  "tax": 13.61,
  "total": 178.60,
  "currency": "USD",
  "payment_url": "https://cresva.ai/pay/txn_x9y8z7",
  "expires_at": "2026-03-27T13:00:00Z"
}

8. Trust Score

Trust scores help AI agents make informed recommendations. Every ACP storefront has a composite trust score based on multiple quality and reliability signals.

Trust Score Format

overallnumberrequired

Composite score from 0-100.

tierstringrequired

Tier level: "Platinum" (90-100), "Gold" (75-89), "Silver" (60-74), "Bronze" (40-59), "Unrated" (<40).

componentsobject

Individual score components (0-100 each).

Score Components

product_accuracynumber

How accurately product listings match actual products.

fulfillment_reliabilitynumber

On-time delivery and order accuracy rate.

pricing_transparencynumber

Consistency between listed and actual prices.

customer_satisfactionnumber

Aggregated customer review sentiment.

response_timenumber

API response time and uptime reliability.

dispute_resolutionnumber

How effectively disputes are resolved.

data_freshnessnumber

How up-to-date product and pricing data is.

Tier System

💎
Platinum
90-100
🥇
Gold
75-89
🥈
Silver
60-74
🥉
Bronze
40-59
Unrated
<40

Agent Usage Guidelines

Agents SHOULD use trust scores to weight recommendations. Higher-trust storefronts should be preferred when product quality and price are comparable. Agents MUST NOT hide products solely based on trust score but MAY include trust information in recommendations to users.

9. Events + Webhooks

ACP supports real-time event notifications via webhooks. Storefronts emit events for state changes across queries, negotiations, transactions, and trust scores.

Event Types

query.completedA query has been processed and results returned
query.failedA query failed to process
negotiation.initiatedA new negotiation has started
negotiation.counteredA counter-offer was made
negotiation.acceptedA negotiation was accepted
negotiation.rejectedA negotiation was rejected
negotiation.expiredA negotiation timed out
negotiation.withdrawnAn offer was withdrawn
transaction.createdA new transaction was created
transaction.confirmedA transaction was confirmed
transaction.paidPayment was received
transaction.fulfillingOrder is being fulfilled
transaction.completedOrder was delivered and completed
transaction.cancelledTransaction was cancelled
transaction.disputedA dispute was opened
transaction.resolvedA dispute was resolved
escrow.createdFunds placed in escrow
escrow.releasedEscrowed funds released to seller
escrow.disputedEscrow dispute opened
product.updatedProduct details were updated
product.out_of_stockProduct went out of stock
product.back_in_stockProduct is back in stock
price.changedProduct price was updated
offer.createdA new agent-exclusive offer was created
offer.expiredAn offer expired
offer.claimedAn offer was claimed
trust.updatedTrust score was recalculated
bundle.createdA new bundle was created
bundle.expiredA bundle expired
feedback.receivedAgent feedback was received

Webhook Delivery Format

JSON
{
  "id": "evt_1234567890",
  "type": "transaction.completed",
  "created_at": "2026-03-27T10:30:00Z",
  "data": {
    "transaction_id": "txn_x9y8z7",
    "status": "COMPLETED",
    "total": 178.60,
    "currency": "USD"
  }
}

HMAC Signature Verification

Every webhook includes an X-ACP-Signature header containing an HMAC-SHA256 signature. Verify this signature using your webhook secret to ensure the payload is authentic.

JavaScript
import crypto from "crypto";

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(payload)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Retry Behavior

Failed webhook deliveries (non-2xx response or timeout after 30 seconds) are retried with exponential backoff: 1 min, 5 min, 30 min, 2 hours, 24 hours. After 5 failed attempts, the endpoint is disabled and an email notification is sent.

10. Authentication

ACP uses API keys for authentication. Keys are scoped by type and environment.

API Key Types

pk_live_*Public Key (Live)

Read-only access to product data. Safe to use in client-side code. Rate limit: 1,000 requests/minute.

sk_live_*Secret Key (Live)

Full access including transactions and negotiations. Must be kept server-side. Rate limit: 5,000 requests/minute.

pk_test_*Public Key (Test)

Read-only access to sandbox data. Rate limit: 100 requests/minute.

sk_test_*Secret Key (Test)

Full sandbox access. Rate limit: 500 requests/minute.

Authorization Header

HTTP
Authorization: Bearer pk_live_your_key_here

Include the API key in the Authorization header of every request using the Bearer scheme.

Rate Limits

Rate limits are applied per API key. When exceeded, the API returns 429 Too Many Requests with a Retry-After header indicating when the limit resets.

11. Errors

ACP uses standard HTTP status codes and returns structured error responses.

Error Response Format

JSON
{
  "error": {
    "code": "invalid_query",
    "message": "The 'intent' field is required for all query requests.",
    "details": {
      "field": "intent",
      "expected": "one of: search, recommend, compare, detail, review, availability"
    }
  }
}

HTTP Status Codes

400Bad RequestInvalid request body or parameters
401UnauthorizedMissing or invalid API key
403ForbiddenAPI key lacks required permissions
404Not FoundResource does not exist
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected server error
503Service UnavailableStorefront is temporarily unavailable

Degradation Headers

When a storefront is serving partial or stale data, it includes degradation headers:

X-ACP-Data-Freshnessheader

ISO 8601 timestamp of when the data was last updated.

X-ACP-Degradedheader

Set to "true" when serving from cache or with reduced functionality.

X-ACP-Degraded-Reasonheader

Human-readable reason for degradation.

12. Versioning + Compatibility

Protocol Version Header

Every request and response includes an X-ACP-Version header. Clients SHOULD send their supported version; servers MUST include the version used to process the request.

HTTP
// Request
X-ACP-Version: 2.0

// Response
X-ACP-Version: 2.0

Backward Compatibility Rules

  • New optional fields MAY be added to responses without a version bump
  • New optional request fields MAY be added without a version bump
  • Existing fields MUST NOT be removed or have their type changed within a major version
  • New required fields MUST trigger a major version increment
  • New endpoints MAY be added in minor versions

Deprecation Policy

When a feature or endpoint is deprecated:

  1. A deprecation notice is published in the changelog and API responses include a Sunset header
  2. The feature continues to work for 6 months after the deprecation notice
  3. After the sunset date, the endpoint returns 410 Gone