Conventions
Pagination, error shapes, rate limits, and how the API is versioned and deprecated.
Rules that hold across every endpoint and every tool. Learn them once.
Pagination
Every list — REST endpoint or MCP tool — paginates the same way, with two optional parameters:
| Parameter | Default | Notes |
|---|---|---|
limit | 20 | Maximum items to return. Capped at 100. |
offset | 0 | Items to skip. offset: 20 with limit: 20 is the second page. |
The limit is a clamp, not a validation rule
Ask for limit: 10000 and you get 100 back — the maximum — not a 400. This
is deliberate, so an agent that guesses a large number gets useful results
instead of an error it has to recover from. Never assume you received everything
you asked for; read the response.
Every list response carries the numbers you need to page:
total— the count of matching items before pagination. Compare it againstoffset + returnedto know whether another page exists.limitandoffset— echoed back, so a client can compute the next request without tracking state.
curl https://api.passo.co/v1/workspaces?limit=20&offset=20 \ -H "Authorization: Bearer $PASSO_TOKEN"MCP tools take the same limit and offset arguments and return the same
total / limit / offset fields alongside their data.
Errors
REST
The REST API uses conventional HTTP status codes. The JSON body carries a
machine-readable code and a human-readable message:
{
"code": "NOT_FOUND",
"message": "No workspace with that id."
}| Status | Code | Meaning |
|---|---|---|
| 400 | BAD_REQUEST | The request was malformed. |
| 401 | UNAUTHORIZED | The token is missing, invalid, or expired. |
| 403 | FORBIDDEN | Authenticated, but not allowed to do this. |
| 404 | NOT_FOUND | The resource does not exist — or your account cannot see it. |
| 409 | CONFLICT | The change collides with existing state (e.g. a duplicate). |
| 422 | UNPROCESSABLE_CONTENT | The input was well-formed but failed validation. |
404 hides what you can't see
Because access is enforced by row-level security, a resource outside your scope is
indistinguishable from one that does not exist — both are 404. The API never
confirms the existence of something your account cannot access. See
Authentication.
MCP
MCP tools do not raise a JSON-RPC error for an expected failure. They return a
structured result the calling model can read and act on — a missing required
argument comes back as { "error": "invalid" }, an unreachable record as
{ "error": "not_found" }. This lets the agent ask you for the missing piece or
try another record, rather than hit an opaque protocol error it cannot interpret.
Genuine protocol problems (an expired token, a malformed call) still surface as
transport errors.
Rate limits
There are no per-request rate-limit headers to parse today. Traffic is subject to
platform-level protection, not a published per-account quota. Formal limits, when
introduced, will be documented here and announced in the
changelog before they take effect. In the
meantime, be a good citizen: paginate rather than over-fetch, and cache stable
results like whoami instead of calling it on every turn.
Versioning and deprecation
The API is versioned in the path: REST lives under /v1, and the MCP endpoint is
/v1/mcp. Everything under a version is a stable contract.
- Additive changes are not breaking and can land at any time: new endpoints, new tools, new optional fields on a response. Write clients that ignore unknown fields, and a new field will never break you.
- Breaking changes get a new version. A changed or removed field, a renamed
tool, a different default — none of these happen in place under
/v1. They arrive under a new version so your integration keeps working. - Deprecations are announced first. Anything on a path to removal is called out in the changelog with a timeline, so you have notice before it goes.
Every change to the contract is recorded in the changelog — it is generated from the committed API spec, so it cannot silently drift from what the API actually does.