Skip to main content
Every request to the MeshQu API requires two headers, except on the public paths listed below:

Public paths

These paths carry no API key and no tenant header. They are not an oversight — each hosts its own access control, and offline verification and hosted forms depend on them being reachable without a key. But the exception is wider than “health checks”, so it is set out in full: Infrastructure:
  • GET /v1/health, GET /v1/ready
  • GET /v1/.well-known/signing-keys, GET /v1/.well-known/trust-registry
  • the OpenAPI document and docs UI, when the operator enables them
  • GET /metricsnot free of tenant data. Many metric families carry a tenant label, so the endpoint exposes per-tenant volumes and outcomes. It is guarded by a bearer token (METRICS_BEARER_TOKEN, required in production), not by an API key — which is why it sits on this list at all.
Tenant-scoped, unauthenticated — these do reach tenant data, addressed by an unguessable identifier rather than by a key:
  • GET /v1/receipts/:decisionId and GET /v1/receipts/:decisionId/bundle
  • GET /v1/chains/:chainId/verify, GET /v1/chains/:chainId/seal, GET /v1/chains/:chainId/bundle
  • GET /v1/forms/:formId/schema, GET /v1/forms/:formId/api-contract, GET /v1/forms/:formId/receipts/:decisionId
  • POST /v1/forms/:formId/submit — the one public write. A submission to a hosted form is evaluated and mints a signed receipt without any API key being presented. Rate limiting is per (form, IP) and the form’s own token budget caps total consumption; treat a form’s ID as a capability and disable forms you no longer want submissions on.
“Unauthenticated” here means no API key and no tenant header — not unrestricted. Every one of these paths is rate-limited, and a request still only ever reaches the tenant that owns the identifier in the URL. What it does not do is prove who the caller is.

API keys

API keys are created via the /v1/api-keys endpoint (requires the api-keys:admin scope) or through the MeshQu Console. When you create a key, the plaintext value is returned exactly once. Store it securely — it cannot be retrieved again. The API stores only a hashed representation. Each key has:
  • Name — a human-readable label for audit trails.
  • Scopes — the set of permissions the key grants (see below).
  • Expiry (optional) — an expires_at timestamp after which the key is rejected.
  • Prefix/suffix — a safe fragment (e.g. mqu_...c123) shown in dashboards for identification.
Keys are mqu_ followed by a base64url-encoded random token (e.g. mqu_EXAMPLEKEYdonotuse_replace_with_ownx_abc123). There is no environment segment such as _live_ or _test_ — a single key format is used everywhere.

Revoking a key

Revoked keys are rejected immediately. Revocation is permanent.

Scopes

Each API key carries one or more scopes that control what it can access:
A tenants:provision scope also exists for cross-tenant operator keys, but it is not grantable through the API — an api-keys:admin key cannot mint itself one. It is assigned out-of-band by MeshQu operators only.
Principle of least privilege: create separate keys for different services. A service that only evaluates decisions needs decisions:evaluate — not api-keys:admin.

Multi-tenancy

All data in MeshQu is isolated per tenant. The X-MeshQu-Tenant-Id header determines which tenant’s data is accessed. The API key must belong to the specified tenant; a mismatch returns 403 Forbidden.

Rate limits

MeshQu applies two tiers of rate limiting: When a limit is exceeded the API returns 429 Too Many Requests with a Retry-After header. Standard rate-limit headers are included on every response:

Example: creating an API key

Response (key shown once):
Store the key value immediately — it will not be returned again.