The published OpenAPI document
Your tenant's API is published as one OpenAPI document:
curl -s https://api.revenexx.com/v1/openapi.json \
-H "X-Revenexx-Tenant: <TENANT_SLUG>" \
-H "X-Revenexx-Api-Key: rvxk_..."
It is generated from the capabilities of the apps that tenant has installed — the platform's commerce apps and yours, merged into one surface under one /v1 prefix. Install another app and the document grows. Install nothing and there is nothing to call.
manifest.capabilities.json (every installed app)
│
▼
/v1/openapi.json ──► generated SDKs
──► API Explorer
──► MCP server
What lands in it
Everything you declared, and only that:
| Your declaration | Becomes |
|---|---|
route | The path and method under /v1 |
capability | The operationId — and therefore the generated SDK method name |
summary | The operation summary: the line in the Explorer's list, the doc comment on the SDK method |
description | The operation description |
parameters | The documented query, path and header parameters — and the only ones the gateway forwards |
request / response | The request and response schemas; a title hoists it into components.schemas as a named type |
responses | The documented statuses, merged with the gateway's standard ones |
tag and manifest.tags | The section the operation is grouped under |
Nothing else. There is no supplementary description field, no separate documentation site, and no way to annotate an operation after the fact.
There is no second place to correct a wrong description
This is the sentence worth taking literally.
A vague summary is a vague line in the API Explorer, a vague doc comment in the TypeScript SDK, a vague tool description the MCP server offers a model, and a vague answer to the partner who has to integrate with you. A field with no description is a field nobody can guess the meaning of, in every one of those places at once.
The fix is always the same shape, and it is never quick:
- Edit the declaration.
- Bump
versioninmanifest.json. revenexx deploy app.
There is no cache to clear, no doc build to trigger, and no override to apply in a console. Which is a good property — one source, no drift — but it does mean the cheapest time to write a good summary is while you are writing the capability.
Two habits follow:
- Write summaries and field descriptions for a stranger, because a stranger is who reads them.
- Review the published document, not your source file, before you tell anybody the API is ready. Your manifest is what you meant; the document is what they get.
What reads it
The generated SDKs. Every API client the platform publishes is generated from this document, which is how a new language gets added without anybody hand-writing your methods. Your capability key becomes the method name; your titled schemas become named types. As a partner you install the published package — you do not run the generator. See SDKs.
The API Explorer. The browsable, callable reference. It renders your parameters, your schemas, your example values and your declared statuses.
The MCP server. Each capability is offered as a tool, described by your summary and description, with your request schema as its input schema. A model calling your app reads exactly the prose you wrote.
Checking that your capability made it
After a deploy, confirm the operation is really published rather than assuming the build implies it:
curl -s https://api.revenexx.com/v1/openapi.json \
-H "X-Revenexx-Api-Key: $REVENEXX_API_KEY" \
-H "X-Revenexx-Tenant: $REVENEXX_TENANT" \
| grep -o '"/serials[^"]*"'
If the path is missing, the app is not installed on this tenant, or the install step did not run — routes are written at install time, and a build alone publishes nothing.
Worth checking in the same pass, because each is a common miss:
- Your pagination parameters are present on the list operation. Absent means every caller is stuck on page one.
- Your
201is there on a create, and the200it replaced is gone. - Your schemas have names, not
inline_response_200. That means you forgot atitle. - Your
operationIdis the capability key you expected, because that is the SDK method a partner will call by name.
It is per tenant
Two tenants with different apps installed have different documents, and that is by design — a tenant's contract describes what that tenant can actually call.
So when you generate a client, generate it against a tenant that has the apps you depend on installed. And when a partner reports an endpoint missing, the first question is which tenant they fetched the document for.
Next steps
- Capability reference — the fields that become the document.
- Tags — how operations are grouped in it.
- SDKs — the clients generated from it.
- Verifying live — the calls to make after a deploy.