Overriding a capability
This is the mechanism the app model exists for. When your app implements a capability key another app already defined, your app takes over that route for the tenants that install you. The route, the request shape and the response shape stay exactly as the contract says; only the code behind them changes.
{
"type": "implement",
"capability": "inventories.availability",
"compatible": "^1.0"
}
No route, no response, no version — those belong to the contract, and redeclaring them would be claiming authorship of somebody else's API. compatible is the semver range of the contract your implementation satisfies.
What it buys a customer
A tenant whose stock lives in an ERP does not fork the inventory app and does not get a bespoke API. The stock-keeping CRUD stays as shipped. One capability is replaced, and:
- The URL does not change.
POST /v1/inventories/availabilityis still the URL. - The request and response schemas do not change, so the published SDK method still works.
- Every other app that calls
inventories.availabilitykeeps working, unmodified, unaware. - The storefront, the checkout and any partner integration keep calling the same contract.
That is the whole design: the contract is the interface, and the implementation is swappable per tenant.
The three designated override points
Any capability whose contract you can satisfy can be implemented. Three exist specifically to be replaced — the platform apps were designed around them:
| Capability | Route | Replace it when |
|---|---|---|
prices.resolve | POST /v1/prices/resolve | Pricing is computed by an external system |
inventories.availability | POST /v1/inventories/availability | Stock lives in an ERP rather than in the platform |
payments.webhooks.ingest | POST /v1/payments/webhooks/ingest | A payment provider's callbacks need custom handling |
Who answered
On every response the gateway says which app served the capability:
| Header | Meaning |
|---|---|
X-Capability-App | Which installed app served the capability. |
X-Capability-Degraded | Present when a fallback implementation served the request. |
So a caller can tell an overridden route from a standard one without changing a line of client code, and an operator can confirm an override is actually in the path. See API usage for the rest of the response headers.
Honest status
No shipped manifest uses implement today. Every capability in every app the platform ships is a define. The mechanism is in the schema, the resolution is in the gateway, and the headers exist — but there is no production override to point at, so there is no field experience to pass on to you.
What that means in practice, stated plainly rather than hedged:
- Treat an override as something you verify, not something you assume. Deploy it to a staging tenant, call the route, and check
X-Capability-Appnames your app before you build anything on top of it. - Do not design a customer's architecture around an override before you have seen one answer. If the whole integration depends on it, prove the mechanism first with a trivial implementation.
- Expect the details to firm up. How a fallback is selected, exactly when
X-Capability-Degradedappears, and what happens when two installed apps implement the same key are the sort of specifics that get pinned down by the first real use.
The alternative, when you need certainty today, is to define your own capability on your own route and have the customer's storefront or integration call yours. You lose the drop-in property — that is the whole point of an override — but you gain a contract you author and control.
Satisfying the contract
Implementing is a promise about behaviour, not just about shape. Before you ship one:
Read the contract in the published document, not in your assumptions. /v1/openapi.json for a tenant with the defining app installed has the authoritative request schema, response schema and declared statuses. See The published OpenAPI document.
Answer every status the contract declares, with the same meaning. If the contract says 409 means "already reserved", yours cannot use 409 for "unknown SKU". A caller written against the contract will get that wrong, and it will not be their bug.
Be no stricter than the contract. You may accept a request the original would have rejected; you may not reject one it would have accepted. A field the contract marks optional cannot be required by you.
Return the whole response, not the part you care about. A missing field a caller depends on is a break, even though your response validates.
Match the performance envelope. If the capability is on the checkout path and your implementation calls an ERP over the internet, that latency is now in a customer's checkout. Consider a cache on your side of it, and a timeout that fails fast rather than hanging.
config_schema is the field for whatever per-tenant configuration your implementation needs — an endpoint, a credential reference, a rounding mode — without changing the contract callers see. See Capability reference.
Next steps
- Capabilities —
defineversusimplement. - Calling another app — the other side of the resolution.
- The published OpenAPI document — reading the contract you are satisfying.
- Verifying live — confirming who answered.