REST
REST is a set of constraints, not a specification: address things as resources, use the uniform meaning of HTTP methods, keep the server stateless between requests, and send representations rather than internal objects. Connect's public API follows it closely enough that a generic client works. Several internal surfaces deliberately do not, and knowing which is which saves you from writing a client against the wrong shape.
The constraints, and what each one is worth#
| Constraint | In practice | What it buys |
|---|---|---|
| Resources with addresses | A thing has a URL; the URL does not change when the thing does | Links work, records can be referenced in a bug report, caches key on something meaningful |
| Uniform interface | GET reads, DELETE removes, and they mean that everywhere | A client author guesses correctly without reading a manual for every path |
| Statelessness | Each request carries what it needs | Any instance can serve any request; a restart does not strand a conversation |
| Representations | A body is a public shape, not the database row | The storage can change without breaking every client |
The constraint that almost nobody implements is hypermedia — responses that carry the links to what you may do next, so a client discovers the API by following them. Connect does not implement it either. What replaces it here is a written description: a public OpenAPI 3.1.0 document, an Arazzo 1.1.0 workflow description for multi-step sequences, and an AsyncAPI 3.1.0 document for events.
Where Connect is deliberately not RESTful#
- Actions that are verbs. Approving a held draft, placing a call, resolving a case and moving an opportunity are transitions with rules, not edits to a field. Modelling them as a
PATCHon a status column invites a client to set a state the domain service would never have allowed. They stay action-shaped, and the service that owns the record stays the only way in. - Screen endpoints.
workspace_consoleanswers *what this screen needs*, not *what this resource is*. That is a departure with a measured reason: composing on the server took Home from 133 statements to 15, and the workspace console from 89 to 17, flat with page size. A pure resource API pushes that composition into the client and the cost grows with the business. - The MCP endpoint. It is JSON-RPC 2.0 over a single POST path, per the 2026-07-28 revision — one URL, POST only, GET and DELETE answering 405. Nothing about it is resource-shaped, and it is not meant to be.
- The event stream. Server-sent events is one long-lived response rather than a series of requests. It is HTTP, it is not a resource fetch, and polling it as though it were will not work.
Does Connect use REST?#
Supported, for the public API. The public surface is described as OpenAPI 3.1.0 and behaves the way a REST client expects: resources have addresses, methods mean what they say, errors come back in one documented shape, and pagination is explicit. If you are writing an integration, this is the surface to write it against.
The internal app surfaces — the Owner's /api/… paths and the customer's /api/customer/ui/… facade — are not a public contract and are not REST-shaped. They exist to serve screens, they are rewritten between audiences by tenantAdapt, and anything the rewrite does not recognise fails closed with a 403. Building on them means building on something designed to change whenever a screen does.
Questions#
Is an API that uses POST for everything still REST?
Not really, and it loses the practical benefits: intermediaries cannot tell a read from a write, nothing is cacheable, and a client author has to be told the meaning of each path individually. Connect uses action-shaped endpoints where the domain genuinely has transitions, not as a default.
Should I call the same endpoints the web app calls?
No. They are internal, they answer in screen shapes rather than record shapes, and a customer session reaches them only through a rewrite whose unrecognised cases return 403. The public API and the MCP server are the two surfaces with a contract behind them.
Why describe workflows separately from the API?
Because a sequence — discover, then qualify, then create a follow-up — is not expressible as a list of endpoints, and getting the order wrong is a common integration failure. Arazzo 1.1.0 describes those sequences alongside the OpenAPI document that describes the calls.