Skip to content

01 — HTTP wire

Status: Draft
Applies to: Compliance Level 1+

Adapters mount under a configurable base path. Unless otherwise noted, examples use /mesh. Implementations MUST support remapping the base path.

MethodPathPurpose
GET/{base}/:entityList read (or empty list selection)
GET/{base}/:entity/:idPoint read
POST/{base}Complex query in JSON body
PUT/{base}/:entity/:idPoint read with PUT transport (same query headers as GET)

:entity is the MeshQL entity key (e.g. user). :id is the resource primary key as a path segment (string; implementations MAY coerce numerics when talking to storage).

Core write mutations (create/update/delete) are not part of the read protocol. DELETE SHOULD return 405 until a mutation profile is specified.

Persisted queries are an optional production optimization. When enabled, clients MAY send a short query ID instead of the full base64 payload.

MethodPathPurpose
POST/{base}/queriesRegister { "query": "...", "format": "json" } → { "id": "q_a3f1b2c8" }

Execution uses X-Mesh-Query-Id on GET/PUT instead of X-Mesh-Query. The two headers are mutually exclusive.

MethodPathPurpose
POST/{base}/authLogin — returns signing token material
POST/{base}/logoutRevoke session
MethodPathPurpose
POST/{base}/:entity/:id/:fieldMultipart file upload (attach to existing)
POST/{base}/:entityMultipart upload (create)

See 07 — Uploads.

HeaderRequiredDescription
X-Mesh-QueryOne of X-Mesh-Query / X-Mesh-Query-IdBase64-encoded query payload (UTF-8). Padding MAY be present.
X-Mesh-Query-IdOne of X-Mesh-Query / X-Mesh-Query-IdPersisted query ID from POST /{base}/queries (e.g. q_a3f1b2c8)
X-Mesh-FormatNojson (default) or ql
X-Mesh-SignatureL3sha256= + hex HMAC over the exact X-Mesh-Query or X-Mesh-Query-Id header value
X-Mesh-TokenL3Opaque wire token from auth

X-Mesh-Query and X-Mesh-Query-Id are mutually exclusive. X-Mesh-Query MUST NOT be passed as a URL query parameter for L1 compliance.

  1. Serialize the query as UTF-8 text (JSON string or QL string).
  2. Base64-encode (standard alphabet). Strip newlines when transmitting.
  3. Place the result in X-Mesh-Query.
{
"query": "{\"user\":{\"$select\":{\"id\":true,\"name\":true}}}",
"format": "json"
}

QL remains available when format is set to ql:

{
"query": "{ user { id name } }",
"format": "ql"
}
FieldRequiredNotes
queryYesRaw query string (not base64)
formatNoDefaults to json

Content-Type: application/json.

  • Status 200
  • Point read body: selected object or null
  • Collection body: { "items": [...], "pageInfo": { "hasNextPage", "startCursor", "endCursor" } }
  • POST and docs proxies MAY wrap either result as { "data": ..., "meta": ... }

Status codes:

ConditionStatuserror field
Missing / invalid transport (X-Mesh-Query)400TransportError
Unknown entity/field/join or invalid query400ValidationError
Integrity failure401 / 403IntegrityError (L3)
Resolver failure500ResolverError
Unexpected failure500InternalError

Body shape:

{
"error": "ValidationError",
"message": "Field 'secret' not found on entity 'user'"
}

Implementations MUST use JSON error bodies on failure for these routes. Additional fields (e.g. requestId) are allowed.

Not normative. Implementations serving browsers SHOULD allow the X-Mesh-* request headers.