API overview¶
Every Trilocore API call is an HTTPS request to https://api.trilocore.ai, carrying one
Authorization: Bearer header. There is no separate API host, no per-service hostname, and
no SDK requirement — the API is plain HTTP and JSON.
See Authentication for how to obtain a token.
Base URL and versioning¶
| Base URL | https://api.trilocore.ai |
| Product surface | /api/v1/<product>/… — see Product namespaces |
| Transport | HTTPS only, HTTP/1.1 and HTTP/2 |
| Request and response bodies | application/json (errors use application/problem+json) |
The version lives in the path, not in a header. v1 is the only version currently served, and
it is additive: new endpoints, new optional request fields and new response fields may appear at
any time. Treat unknown response fields as forgiving — do not fail a parse on a field you have
not seen before.
A single front door serves the whole product. It authenticates the caller once, applies rate limits, quota and idempotency, and forwards the request to the service that owns the resource. Which service that is shows up in the reference as the endpoint's upstream; it is an implementation detail, not something you address directly.
Product namespaces¶
Every endpoint lives under exactly one product namespace, so the path alone tells you which product you are calling:
| Namespace | Product | Reference |
|---|---|---|
/api/v1/bevm/ |
EVM auditing tools: sessions and forks, targets, scans, Composer, the contract sandbox, EVM analyses | Sessions and forks and the other EVM pages |
/api/v1/bsvm/ |
the same auditing tools for Solana (SVM) programs | Solana sessions and programs |
/api/v1/workbench/ |
what both auditing workbenches share: the audit evidence plane, long-running operations, artifacts, your Auditing IDE view | Workbench |
/api/v1/radar/ |
chain intelligence: contract code search | Radar |
/api/v1/workspaces/ |
workspaces, projects, activity, the contract and audit indexes, invitations, notes, Audit Passport attestations | Workspaces and the pages after it |
/api/v1/ide/ |
the Contract IDE | Workspaces and files |
/api/v1/arch/ |
the Architecture Explorer | Architecture |
/api/v1/public/ |
attestation verification and shared reports, no credential needed | Public |
A namespace names a product, never the service behind it: bevm, bsvm and workbench are
served by the same backend, and that is an implementation detail you never address. Each
operation has exactly one path; when one moves, the old path is removed rather than kept as an
alias. See Deprecations.
The resource model¶
The API is a resource API, not an RPC API. Three consequences are worth internalising before you write a client:
Identifiers live in the path. A call names the thing it acts on — POST
/api/v1/workspaces/{workspace_id}/attestations — rather than passing an operation name and an id
in a body. On the auditing surface the front door additionally validates each path parameter's
shape before forwarding, so a malformed address or transaction hash is rejected with
400 validation_failed instead of reaching a service.
Most creates answer 201; exactly one adds a Location. Many POSTs answer
201 Created, and the per-endpoint tables in the endpoint reference state
which. Only POST /api/v1/bevm/scans is promoted by the front door to 201 with a
Location header and an X-Resource-Id, because that is the one route where the gateway itself
derives the identifier. Everywhere else, read the id out of the response body — do not write a
client that depends on Location, because it will be absent.
Some operations are custom methods. Where an action does not map onto a noun, the path ends
in :verb — POST /api/v1/bevm/sessions/{uid}/snapshots:restore,
POST /api/v1/workbench/operations/{op_id}:cancel, POST /api/v1/public/attestations/verify. The colon may be sent raw or percent-encoded as
%3A; both resolve identically.
Beyond that:
- Every list is paginated the same way. A collection takes
page_size(default 50, at most 200 — larger values are clamped, never refused) andpage_token, and answers{"data": [...], "has_more", "next_page_token", "page_size"}plus an RFC 8288Link: rel="next"header. Follownext_page_tokenuntil it isnull. See Pagination. - Conditional requests work end to end.
If-None-MatchandIf-Matchare forwarded to the owning service, andETag,Cache-ControlandVarycome back. Use them for polling: a304still counts as a request, but it saves you transferring and re-parsing an unchanged body. - Some auditing singletons accept
current. Several/api/v1/bevm/*resources are singletons keyed by the caller, and there the literalcurrentmay stand in for the id to mean "mine" — which is how a first-time caller addresses a resource that has no id yet. This is a property of the auditing surface only: on/api/v1/workspaces/*and the other prefixes an id must be a real UUID, andcurrentfails the matcher. - Unknown resources answer
404, never403. An identifier that exists but is not yours is indistinguishable from one that does not exist. This is deliberate: it stops the API confirming that another tenant's resource exists.
The machine-readable specification¶
An OpenAPI 3.1.0 document is served publicly and needs no authentication:
It is generated from the same routing table that serves traffic, so it cannot drift from the
endpoints it covers. It is cacheable (Cache-Control: public, max-age=300) and CORS-open, so a
browser tool can fetch it directly.
It expands every product namespace above: the EVM and Solana auditing tools, the shared
workbench, radar contract search, the workspace plane, the Contract IDE, architecture and the
public verification endpoints. It lists the canonical path of every operation and nothing
else. Operations that require an Idempotency-Key declare it, and each session-scoped operation
declares the trilocore-session-tag header.
Prefixes whose contract belongs entirely to the service behind them are listed under
x-forwarded-prefixes rather than expanded: sign-in and account management under
/api/v1/auth/*, and the AI planes, which are parked.
What this API does not serve¶
Documenting an endpoint that does not answer is worse than omitting it, so two absences are stated plainly rather than left for you to discover:
- The model plane at
/v1/is mounted but not in service. Unlike the surfaces below, this prefix is routed — an unauthenticated request to it answers401rather than404, which can easily read as "this exists and my token is wrong". It does not currently serve traffic: an authenticated request fails at the upstream. Do not build against it. - The fork platform, billing and webhook-receiver surfaces are not mounted at all. They
return
404because no route exists. They are built but not deployed, and there is no behaviour to integrate with today.
Where to go next¶
| Authentication | Bearer keys, browser sessions, CSRF, and the headers the front door strips |
| Idempotency | The endpoints that require Idempotency-Key, and replay semantics |
| Errors | RFC 9457 problem documents and the full code catalogue |
| Deprecations | What happens when an operation moves, and porting older integrations |
| Rate limits and quota | x-ratelimit-* headers, 429 handling, daily quota |
| Pagination | page_size / page_token, the list envelope, and which lists are not paginated |
| Endpoint reference | Every live endpoint, by product namespace |