Skip to main content

Overview

Verification answers a simple question: is this credential currently valid, and what does it say? The Beltic Credentials API runs a deterministic seven-step pipeline for every verify call, returning a flat response that’s either a success (with the full subject + claims) or a structured rejection (with a machine-readable reason code).

Prerequisites

  • A Beltic API key with credentials:verify permission
  • A signed credential JWT — the signed_payload field from a previous issue response

The Seven-Step Pipeline

Every verify call runs through these checks, in order. The first failure short-circuits the rest.
1

Parse JWS

Decode the JWT header and payload. Extract alg, kid, and iss. Reject if malformed or if alg isn’t ES256.
2

Resolve the issuer key

Look up iss in the trusted-issuer list (V1 is just did:web:beltic.com), then fetch the public JWK by kid from /.well-known/jwks.json.
3

Verify the signature

Cryptographically verify the JWT against the resolved key using jose.jwtVerify. Reject on signature mismatch.
4

Check standard claims

Validate iat, exp, nbf. Optionally validate aud if context.audience was provided.
5

Validate the schema

Match the JWT claims against the registered credential-type schema. Catches forged credentials whose signature is valid but whose claim shape is wrong.
6

Check status

Look up the credential in Beltic’s registry, then check the Status List 2021 bit. Reject if revoked, expired, or suspended.
7

Apply policy

For agent_authorization credentials with a verify context, evaluate the credential’s permissions[] against the request context — fields like amount, currency, resource. Reject on no matching permission or condition failure.

Basic Verify

The minimum request: just the JWT.
The issue response returns the JWT as signed_payload; the verify endpoint accepts it as credential. Same value, different field names — signed_payload is the persisted resource field, credential follows the JWT-VC presentation convention. Pass the JWT string directly either way.

Success Response

  • valid: true is the headline.
  • status is the persisted lifecycle (active, revoked, expired, suspended) — different from valid, which is the protocol outcome.
  • verification_id is unique per call. Use it as a correlation handle for audit and support.

Rejection Response

Verify with Policy Context

For agent_authorization credentials, you can pass a context object to evaluate the agent’s permissions against a specific request. This is how downstream services (e.g. a payment gateway) check that the agent is authorized for this particular call.
If the credential’s permissions allow the action, the response includes a policy_match:
If a condition fails, you get a structured rejection:

Reject Reason Codes

Verifying Offline (Without the API)

The full pipeline runs server-side, but the cryptographic checks (steps 1-5) can be replicated offline:
  1. Fetch https://api.beltic.com/.well-known/jwks.json and cache it. Honour the response’s Cache-Control header (typically 1 hour).
  2. Use any JWT library to verify the JWS against the JWKs.
  3. Validate iat, exp, nbf yourself.
  4. To check revocation, fetch https://api.beltic.com/.well-known/status-lists/v1 and decode the bitstring at the credential’s status_list_index.
The Beltic verify endpoint is recommended for most callers — it handles trust-list management, JWKS caching, and policy evaluation. Offline verification is appropriate when you need to verify in air-gapped environments or want to minimize calls to Beltic.

Public Verify (No Auth)

There’s also a public verify endpoint at POST /v1/credentials/_public/verify that doesn’t require an API key. It returns the same shape but doesn’t expose org-internal fields. Use it for verifier integrations where you can’t ship an API key (e.g. browser-side checks).

Next Steps

Revoke a Credential

Mark a credential revoked and understand how verifiers see the change.

Issue a Credential

Mint a new credential to verify.