Public Verification
Quick example
- curl
- Python
- Node.js
# Verify a single Trinitite receipt — no auth required
curl https://api.trinitite.ai/v1/public/verify/rcp_01HZ2N6T...
import requests
resp = requests.get("https://api.trinitite.ai/v1/public/verify/rcp_01HZ2N6T...")
print(resp.json())
const r = await fetch('https://api.trinitite.ai/v1/public/verify/rcp_01HZ2N6T...');
console.log(await r.json());
The verifier returns the receipt, the signature envelope, the JWKS URL, the RFC 3161 TSA token, and the Sigstore Rekor entry — enough to validate locally with no Trinitite trust assumption.
Overview
This page documents the stateless, no-auth surface of the platform. Anyone can use it — regulators, third-party auditors, the customer of a customer — without holding a Trinitite credential.
The reasoning is simple: a tamper-evident audit trail is only valuable if a third party can verify it without trusting the operator's word for it. Trinitite issues signed artifacts (attestation reports, evidence snapshots, shared links, MCP OAuth metadata) and exposes the keys plus verifier endpoints publicly so verification is fully external.
| What you want to verify | Use |
|---|---|
| A signature on an artifact | /.well-known/jwks.json |
| A published attestation report | GET /v1/public/attestations/{public_id} |
| An arbitrary signed payload | GET /v1/public/verify/* |
| MCP OAuth flow metadata | /.well-known/oauth-protected-resource |
| Customer-curated dashboards (with a one-time token from a customer) | GET /v1/portal/{token}/* |
JWKS — key distribution
The platform publishes its public key bundle following RFC 7517.
| Method | Path | Notes |
|---|---|---|
GET | /.well-known/jwks.json | Standard well-known location |
GET | /v1/public/jwks | Alias of the same bundle |
{
"keys": [
{
"kid": "trinitite-platform-2026-q2",
"kty": "OKP",
"crv": "Ed25519",
"x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo",
"alg": "EdDSA",
"use": "sig"
},
{
"kid": "trinitite-platform-2026-q1",
"kty": "EC",
"crv": "P-256",
"x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
"y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
"alg": "ES256",
"use": "sig"
}
]
}
Both Ed25519 (EdDSA) and ECDSA (P-256, ES256) signatures are supported. Verification is stateless: any third party can fetch JWKS and re-verify a published artifact without holding platform credentials.
Keys rotate quarterly; the kid carries the rotation epoch. Old keys remain in the bundle as long as artifacts they signed are still verifiable (typically several years).
Stateless verifier endpoints
GET /v1/public/verify/* — endpoints that accept a signed payload (or its content hash) and return whether it verifies against the current JWKS.
| Path | Use |
|---|---|
GET /v1/public/verify/attestation?public_id={id} | Re-verify a published attestation report by its public ID |
GET /v1/public/verify/snapshot?content_hash={sha256} | Verify an evidence snapshot's content hash against the platform's records |
GET /v1/public/verify/anchor?merkle_root={sha256}&anchor_at={rfc3339} | Verify that a Merkle root was anchored to an external trusted clock at the claimed time |
GET /v1/public/verify/skill?signature={sig}&content_hash={sha256} | Verify a Skill Vault signature on a SKILL.md content hash |
GET /v1/public/verify/dsr?dsr_id={id} | Verify the post-shred state of a DSR (the chain still verifies; the salts no longer can) |
All verifier endpoints return a uniform response:
{
"verified": true,
"kid": "trinitite-platform-2026-q2",
"alg": "EdDSA",
"evidence": {
"verified_at": "2026-05-01T22:14:00Z",
"platform_version": "1.0.0",
"fields": { /* endpoint-specific evidence */ }
}
}
If verification fails, verified is false and evidence.errors[] enumerates each failed step.
Public attestation lookup
GET /v1/public/attestations/{public_id}
Operators can mark an attestation report as publishable, which exposes a stable lookup URL anyone can hit. Common use cases:
- Linking to a SOC 2 attestation from your trust centre.
- Pinning a fairness report URL on a model card.
- Posting a public board-meeting attestation snapshot.
{
"public_id": "att-acme-soc2-2026-q1",
"report_type": "ssae_21",
"issued_at": "2026-04-01T00:00:00Z",
"period_start": "2026-01-01T00:00:00Z",
"period_end": "2026-03-31T23:59:59Z",
"merkle_root": "sha256:e3b0c44...",
"anchors": [
{ "anchor_type": "rfc3161_tsa", "anchor_at": "2026-04-01T00:01:00Z", "verified": true },
{ "anchor_type": "sigstore_rekor", "anchor_at": "2026-04-01T00:01:30Z", "rekor_log_index": 123456789, "verified": true }
],
"signature": "ed25519:e3b0c44...",
"signature_kid": "trinitite-platform-2026-q1",
"verifier_url": "https://api.trinitite.ai/v1/public/verify/attestation?public_id=att-acme-soc2-2026-q1"
}
Re-verify by fetching verifier_url and the JWKS bundle, then validating the signature locally. A worked example:
import requests, base64
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
# 1. Fetch the report
report = requests.get(
"https://api.trinitite.ai/v1/public/attestations/att-acme-soc2-2026-q1",
).json()
# 2. Fetch the JWKS bundle
jwks = requests.get("https://api.trinitite.ai/.well-known/jwks.json").json()
key_jwk = next(k for k in jwks["keys"] if k["kid"] == report["signature_kid"])
# 3. Verify the signature locally
public_key_bytes = base64.urlsafe_b64decode(key_jwk["x"] + "==")
public_key = Ed25519PublicKey.from_public_bytes(public_key_bytes)
# 4. Re-create the message that was signed (the canonical JSON of the report
# minus the `signature` and `verifier_url` fields), then verify.
# (Trinitite documents the exact canonicalisation rules in your enterprise contract.)
The verifier_url is a one-stop alternative if you don't want to handle the cryptography yourself.
MCP OAuth metadata
GET /.well-known/oauth-protected-resource
RFC 9728 Protected Resource Metadata describing the OAuth 2.1 configuration of the MCP Gateway.
{
"resource": "https://api.trinitite.ai/v1/mcp",
"authorization_servers": ["https://api.trinitite.ai/v1/mcp/oauth"],
"scopes_supported": ["tools:read", "tools:execute", "resources:read", "prompts:read"],
"bearer_methods_supported": ["header"],
"resource_documentation": "https://docs.trinitite.ai/docs/api-reference/mcp-gateway-endpoint"
}
MCP clients use this endpoint to discover the gateway's authorization server before performing dynamic client registration (POST /v1/mcp/oauth/register).
External-reviewer portal
When a customer issues a shared link, the recipient consumes it via the portal endpoints. Token-only — the recipient does not have or need a platform credential.
GET /v1/portal/{token}/...
Available views (controlled by the scope set on the shared link at creation time):
| Path | View |
|---|---|
/v1/portal/{token}/risk-decay | Risk-decay timeseries |
/v1/portal/{token}/benchmarks | Peer benchmarks |
/v1/portal/{token}/geographic-risk | Geographic risk distribution |
/v1/portal/{token}/model-risk | Model-risk posture |
/v1/portal/{token}/compliance-posture | Compliance posture (re-uses the executive summary shape) |
/v1/portal/{token}/chain-integrity | Live Merkle-chain integrity status |
/v1/portal/{token}/violation-summary | Violation summary for the period |
/v1/portal/{token}/evidence-snapshots | Evidence snapshots in scope |
Errors:
| HTTP | error.code | Cause |
|---|---|---|
401 | invalid_token | Token is unknown or malformed |
403 | forbidden | Token does not include the requested scope |
404 | not_found | View doesn't exist for this token's tenant |
410 | resource_gone | Token has been revoked |
422 | view_count_exhausted | max_views budget on the token has been spent |
Tokens carry a max_views budget; once exhausted further requests return 422 view_count_exhausted until the issuing customer raises the budget or reissues the link.
Rate limits
The public endpoints have generous IP-based rate limits but are still rate-limited to prevent abuse:
| Header | Description |
|---|---|
X-RateLimit-Limit | Per-IP quota for the current window |
X-RateLimit-Remaining | Remaining requests |
X-RateLimit-Reset | Unix epoch seconds at which the window resets |
On 429, retry after Retry-After seconds.
Errors
{
"error": {
"code": "not_found",
"message": "Attestation not found or not published.",
"request_id": "req_01J..."
}
}
| HTTP | error.code | Cause |
|---|---|---|
400 | validation_error | Malformed query parameter |
404 | not_found | Attestation not published or unknown public_id |
410 | resource_gone | Public attestation was un-published |
422 | signature_verification_failed | The supplied artifact failed verification against the current JWKS |
429 | rate_limited | Per-IP rate limit exceeded |
Next steps
- See what an organisation can publish for verification → Attestation & Compliance
- Verify a Skill Vault signature → Skill Vault
- Customer-managed external-reviewer access → Shared Links