Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.beltic.com/llms.txt

Use this file to discover all available pages before exploring further.

Overview

This guide walks through issuing a credential with POST /v1/credentials. You’ll learn what goes in the request body, what comes back, and how the four credential types differ.

Prerequisites

  • A Beltic API key with credentials:write permission
  • A subject (the entity the credential is about) — an organisation, person, agent, or document
  • Knowledge of which credential_type you want to issue

Choosing a Credential Type

TypeWhen to use
businessAttest that an organisation has been KYB-verified — registered, beneficial owners disclosed, sanctions cleared.
userAttest a fact about a person — KYC status, age, jurisdiction, trust tier.
agent_authorizationAuthorize an AI agent to act on behalf of a principal within explicit, resource-scoped limits.
outcome_attestationWorkflow-attested credentials carrying generic claims — useful for compliance, audit, or workflow-block outputs.

Step 1: Build the Request

The request body has three required fields plus a few optional ones:
{
  "credential_type": "business",
  "subject": {
    "id": "biz_widgetcorp",
    "type": "organisation",
    "name": "WidgetCorp Ltd"
  },
  "claims": {
    "kyb_status": "approved",
    "verified_at": "2026-05-20T00:00:00Z",
    "jurisdiction": "US-DE"
  },
  "expires_at": "2027-05-20T00:00:00Z"
}
British spelling matters: subject.type for a company is "organisation", not "organization". The schema follows the W3C VC business profile.

Subject Shapes by Type

The required fields on subject and claims depend on credential_type:
{
  "credential_type": "business",
  "subject": {
    "id": "biz_acmecorp",
    "type": "organisation",
    "name": "Acme Corp"
  },
  "claims": {
    "kyb_status": "approved",
    "verified_at": "2026-05-20T00:00:00Z",
    "jurisdiction": "US-DE"
  }
}
Required claims: kyb_status (one of pending | approved | declined | manual_review).

Step 2: Send the Request

curl -X POST https://api.beltic.com/v1/credentials \
  -H "X-Api-Key: $BELTIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "credential_type": "business",
    "subject": {
      "id": "biz_widgetcorp",
      "type": "organisation",
      "name": "WidgetCorp Ltd"
    },
    "claims": {
      "kyb_status": "approved",
      "verified_at": "2026-05-20T00:00:00Z",
      "jurisdiction": "US-DE"
    }
  }'

Step 3: Inspect the Response

{
  "id": "cred_01HQ7P4M6...",
  "credential_id": "cred_01HQ7P4M6...",
  "credential_type": "business",
  "subject": {
    "id": "biz_widgetcorp",
    "type": "organisation",
    "name": "WidgetCorp Ltd"
  },
  "claims": {
    "kyb_status": "approved",
    "verified_at": "2026-05-20T00:00:00Z",
    "jurisdiction": "US-DE"
  },
  "issuer_did": "did:web:beltic.com",
  "kid": "K8L9...",
  "alg": "ES256",
  "proof_format": "jwt_vc",
  "signed_payload": "eyJhbGciOiJFUzI1NiIs...",
  "status": "active",
  "status_list_index": 4287,
  "issued_at": "2026-05-21T10:30:00Z",
  "expires_at": "2026-08-19T10:30:00Z",
  "created_at": "2026-05-21T10:30:00Z",
  "updated_at": "2026-05-21T10:30:00Z"
}
Fields worth knowing:
  • signed_payload — the JWT-VC. This is the artifact you hand to verifiers; it carries all the claims plus the signature.
  • credential_id — the globally unique identifier. Stable across the credential’s lifetime; use it in verify requests via by_credential_id.
  • status_list_index — the bit slot reserved in your org’s Status List 2021 bitstring. You don’t need this for verification, but it’s useful for audit.
  • expires_at — defaults to 90 days from issuance. Override it by passing expires_at (ISO 8601) in the request body. Passing a date in the past returns 422.

Idempotency

Issue requests support Stripe-style idempotency keys via the Idempotency-Key header. Retrying the same request with the same key within 24 hours returns the original response without minting a new credential. Concurrent retries with the same key return 409 conflict.
curl -X POST https://api.beltic.com/v1/credentials \
  -H "X-Api-Key: $BELTIC_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d @payload.json

Error Codes

HTTPCodeCause
400validation_failedRequest body failed Zod validation (missing field, wrong enum value, British vs American spelling)
401unauthorizedAPI key missing, invalid, or environment-mismatched
403forbiddenAPI key lacks credentials:write
409idempotency_conflictConcurrent request with the same idempotency key
422unprocessable_entityPayload structurally valid but semantically rejected (e.g., expires_at in the past)

Next Steps

Verify a Credential

Validate the JWT-VC you just received.

Batch Issue

Issue thousands of credentials in a single async job.