Skip to content
cresvaDevelopers
All posts
Updated September 16, 2026ProtocolDiscovery

What an agent sees when it asks us who we are

Discovery is the first thing an agent does and the last thing anybody writes

about. It is one unauthenticated GET, it returns a small JSON document, and

everything the agent does afterwards is shaped by what that document said. This

post is that document, quoted whole, with a note on why it says what it says.

The platform address

curl https://api.cresva.ai/.well-known/osp.json
{
  "osp_version": "3.0",
  "acp_version": "3.0",
  "type": "platform",
  "is_storefront": false,
  "platform": { "name": "Cresva", "host": "cresva.ai", "multi_tenant": true },
  "catalogue": {
    "present": false,
    "reason": "This is the platform address. Products belong to a storefront, and a storefront is named by its brand id."
  },
  "addressing": {
    "descriptor_by_query": "https://api.cresva.ai/.well-known/osp.json?brand=<brandId>",
    "storefront_root": "https://api.cresva.ai/api/storefront/<brandId>",
    "openapi_by_query": "https://api.cresva.ai/.well-known/openapi.yaml?brand=<brandId>"
  },
  "brand_lookup": {
    "available": false,
    "endpoint": null,
    "reason": "There is no public endpoint that maps a domain to a brand id, and this says so rather than leaving the question open. The platform does not record which host belongs to which brand in a form it could answer from, so any mapping offered here would be a guess. Ask the merchant for their storefront URL: the brand id is in it."
  },
  "documentation": "https://developers.cresva.ai/protocol/spec",
  "rate_limits": { "public": "60/minute", "authenticated": "300/minute", "anonymous": "10/minute" }
}

Captured 16 September 2026. Three things in it are worth more than the rest.

is_storefront: false. An agent that arrives at a host and finds a

well-known file will assume it has found a shop. Here it has found a building

with many shops in it. Saying so in a boolean, at the top, means an agent does

not have to infer it from an empty catalogue.

catalogue.present: false, with a reason. The alternative was to return an

empty products array. An empty array is indistinguishable from a shop with

nothing in it, and an agent acting on that would tell a user this merchant sells

nothing. A refusal with a sentence attached cannot be misread that way.

brand_lookup.available: false, with a longer reason. This is the one an

agent most wants to be true. Give it a domain, get back a brand id. It is false,

and the field says why: the platform does not record which host belongs to which

brand in a form it could answer from, so any mapping offered would be a guess.

A guess here is worse than a refusal, because an agent cannot tell one from the

other and will send a shopper to the wrong merchant.

A storefront address

The same file, with a brand id on it:

curl "https://api.cresva.ai/.well-known/osp.json?brand=cmqmr1f6j0003la04nu93f4k4"
{
  "osp_version": "3.0",
  "acp_version": "3.0",
  "type": "storefront",
  "is_storefront": true,
  "storefront_url": "https://cresva.ai/api/storefront/cmqmr1f6j0003la04nu93f4k4",
  "brand_id": "cmqmr1f6j0003la04nu93f4k4",
  "brand_name": "Cresva",
  "capabilities": ["search", "recommend", "compare", "negotiate"],
  "supported_currencies": ["USD"],
  "supported_languages": ["en"],
  "rate_limits": { "public": "60/minute", "authenticated": "300/minute", "anonymous": "10/minute" },
  "documentation": "https://developers.cresva.ai/protocol/spec"
}

capabilities is the load bearing field, and this storefront declares four.

The protocol defines five. transact is absent, which means this storefront

will not open a checkout session and an agent should not try. An agent that

reads the declaration first gets a clean refusal from its own code; an agent

that assumes and calls anyway gets a refusal from ours, naming the capability

that was missing. The first is faster and neither is a guess.

The two hosts are not interchangeable

api.cresva.ai serves the .well-known documents and the /v1/ platform API,

and answers every other path with a 404 before routing. Storefront routes are

on cresva.ai, under /api/storefront/{brandId}/. A storefront path sent to

the first host returns not_found whatever else is right about it, and that is

the single most common way a first integration fails.

The rate limit is in the document and in the header

Both manifests declare 10 requests a minute anonymous, 60 on a public key, 300

on a secret key. So does every response:

$ curl -sI "https://cresva.ai/api/storefront/$BRAND_ID/products" | grep -i ratelimit
x-ratelimit-limit: 10
x-ratelimit-remaining: 8
x-ratelimit-reset: 1789565882

Publishing a ceiling in two places is a way of being wrong in two places, so

the header is the one to trust: it is enforced by the thing that answers you.

Read it rather than a page, including this one.

With one caveat that will confuse you if nobody says it. **A repeated identical

GET is served from CDN cache, and a cached response carries the rate limit

counter from whenever it was first computed.** So x-ratelimit-remaining can

sit still, or go up, across requests you know you made. The limiter is not

wrong and neither is the header; you are reading a copy. Vary the query string

if you want to watch the counter move.

Why any of this matters

A discovery document is a contract about what an agent may assume. Every field

that says false with a reason attached is a place this protocol chose to

refuse rather than to guess. That is not modesty. An agent cannot tell a guess

from a fact, and a wrong fact at discovery propagates into every call that

follows it.