Digitalyser.io for developers
Guides

Conventions

Errors, replaying a write, pagination, and the one visible difference between the two transports.

Read this once and the rest of the reference reads itself.

The two transports refuse differently

Same cause, two shapes — and this trips up anyone who reads the MCP guide and then writes REST.

MCPREST
Transport-level refusal401 with WWW-Authenticate401 with WWW-Authenticate
Capability-level refusal200 with a JSON-RPC error envelopeReal HTTP status code

Past the transport guard, the MCP layer wraps every error in a 200 JSON-RPC response — that is the protocol, not a choice. Do not branch on the HTTP status alone when speaking MCP: read the envelope.

One deliberate exception: a capability outside your granted scope is refused before the transport, as a real 403 insufficient_scope with a WWW-Authenticate challenge. It has to be, because a refusal buried in a 200 is one no client can read as an invitation to re-authorise.

Refusals are typed

A refusal tells you which of four things went wrong: the capability does not exist, your credential may not use it, the request is malformed, or a precondition failed. Refusals are stable and enumerable — the full list is generated from the registry itself, so it cannot drift from what the server does.

Identifiers

Capability identifiers are dotted, lowercase, and stable: audit.overview.get, content.items.list, brand-voice.define. The last segment is the verb. Resource identifiers are UUIDs. Neither is ever recycled.

Pagination

Two reads paginate, and they do not use the same envelope. We would rather tell you than let you find out from a second parser.

GET /v1/projects/{projectId}/topicsGET /v1/projects/{projectId}/contents
The pageitemscontents
Where the counts liveat the root: total, page, pageSize, totalPagesin a pagination object: page, pageSize, totalPages, totalItems
The total is calledtotaltotalItems
Is there a next page?hasNextPage and hasPreviousPagenot given — compare page with totalPages

Both take the same two query parameters. page starts at 1 and defaults to 1. pageSize defaults to 20 and is capped at 50: ask for more and you get 50, not a refusal. Every other read returns its whole document and takes neither.

To walk a list, request page 1, then keep going until hasNextPage is false on topics, or until page reaches totalPages on contents. Do not assume the last page is full.

Replaying a write

There is no Idempotency-Key header, and we will not pretend otherwise. What the API guarantees instead is narrower and lives in the state of the change itself: a proposal is applied once.

Apply it a second time — a retry after a timeout, a double click — and you get 409 with not_pending, which means nothing to retry: the proposal was already applied, or it was discarded. Read the current state before proposing again.

Reads are safe to repeat. For the 5xx failures, retry with backoff, as the error catalogue says on each of those entries.

Timestamps

Every timestamp is UTC, ISO 8601, with an explicit offset. There are no naive timestamps in the API surface.

Rate limits

Requests are bounded per credential and per project. We publish no numbers here — a limit written in documentation becomes a promise, and we only promise what the code enforces. When limits are enforced at the edge you will see them announced in standard RateLimit-* response headers, and this page will say so.

One project per connection

Not a convention — an invariant. A session carries exactly one project, resolved from the credential. No parameter can change it, and passing a project identifier in the body of a call is refused rather than ignored. An agency opens one connection per client.

Was this page helpful?

On this page