@primethoughts/primecredence-sdk
v1.0.0
Published
TypeScript SDK for PrimeCredence Trust OS — typed client for the gateway endpoints covering W3C VCs, OID4VCI/OID4VP, Trust Registry, billing, and DPP lifecycle
Readme
@primethoughts/primecredence-sdk
TypeScript SDK for PrimeCredence Trust OS. Wraps 150+ gateway REST endpoints across 12 service modules covering W3C Verifiable Credentials, OID4VCI/OID4VP, DIDComm, Trust Registry, Hyperledger Indy VDR, billing, and Digital Product Passports.
Installation
Install
npm install @primethoughts/primecredence-sdkThe current release is published under the latest dist-tag, so a plain install
always resolves to the newest published version. (During the pre-1.0 phase the
release candidates are the current latest.)
Pin to a specific version
npm install @primethoughts/[email protected]Requirements
- Node.js >= 20.0.0
- Zero runtime dependencies (Node.js built-ins only)
Supply Chain Security
Every release is signed with npm provenance via Sigstore and GitHub OIDC. Verify the attestation:
npm audit signaturesYou should see: verified registry signature — proving the tarball was built by our GitHub Actions workflow from the source commit, not tampered with in transit.
Quick Start
import { PrimeCredenceClient } from '@primethoughts/primecredence-sdk';
// `auth` is required at construction. For public calls (register/login) pass an empty jwt
// and set the real token afterwards; for a backend integration use an access key.
const primecredence = new PrimeCredenceClient({
baseUrl: 'https://gateway.primecredence.example:8080',
auth: { type: 'jwt', token: '' },
// or: auth: { type: 'accessKey', keyId: 'ak_…', secret: process.env.PRIMECREDENCE_SECRET! }
});
const auth = await primecredence.identity.register({
name: 'Jane Doe',
email: '[email protected]',
password: 'Secret123!',
role: 'SUPPLIER',
});
primecredence.setToken(auth.token); // all subsequent calls authenticated
// Or login with existing credentials
const loginAuth = await primecredence.identity.login({
email: '[email protected]',
password: 'Secret123!',
});
primecredence.setToken(loginAuth.token);
// Identity — tenant management
const tenant = await primecredence.identity.createTenant({ name: 'Acme Corp' });
const tenants = await primecredence.identity.listTenants();
// Issue a credential over OID4VCI (the wallet claims it from the returned offer)
const offer = await primecredence.oid4vci.createOffer({ credentialType: 'InvoiceCredential', claims });
// Verify a presentation over OID4VP (5-check)
const result = await primecredence.presentations.verify(presentationId);
// Registry — TRQP read + admin authoring
const frameworks = await primecredence.registry.listFrameworks();
const framework = await primecredence.registry.admin.createFramework({ did, name, version });Issuance and presentation run over the OpenID rail (OID4VCI / OID4VP, SD-JWT VC). See the per-module docs for exact method signatures — the
oid4vci,presentations, andwalletmodules replace the legacy DIDComm/Indy flows.
What you can build
Note: parts of the walkthrough below predate the platform's move to the OpenID rail (ADR-0037) and still reference legacy
messaging/vdr/credentials.issue/did:indyflows that are not in the current SDK. Treat it as conceptual; the Modules table and the per-module docs are the source of truth for shipped methods. Issuance isoid4vci/wallet; presentation ispresentations.
The SDK follows the arc of a real trust ecosystem: connect, stand up your governance,
register the actors, then issue → verify → present → revoke credentials — and, if you're
running a paid service, meter it. Each step below uses real SDK methods; assume
const primecredence = new PrimeCredenceClient({ ... }) from step 1.
1. Connect & authenticate
Create a client with a tenant-issued access key. The SDK exchanges the key for a short-lived bearer token at the token endpoint and refreshes it transparently — the secret stays in memory only, and you never manage tokens by hand.
import { PrimeCredenceClient } from '@primethoughts/primecredence-sdk';
const primecredence = new PrimeCredenceClient({
baseUrl: 'https://gateway.primecredence.example:8080',
auth: { type: 'accessKey', keyId: 'ak_live_…', secret: process.env.PRIMECREDENCE_SECRET! },
});For a static token from a login flow, use auth: { type: 'jwt', token } and swap it later
with primecredence.setToken(newToken). When you operate as a wallet-gated participant,
upgrade the session by presenting a verified role credential — this returns the verified
roles and switches the client to the resulting session token:
const { roles, expiresIn } = await primecredence.connectWithWallet(presentationId);
// subsequent calls now carry the participant's verified roles2. Establish your trust foundation (governance — usually one-time)
Before credentials mean anything, someone defines the rules: the ledger schema and credential definition business VCs are signed against, plus the Trust Framework and the issuers it authorizes. This is typically done once by the platform/governance side, not on every request.
// Write the AnonCreds schema + cred-def to the Indy VDR
const schema = await primecredence.vdr.writeSchema({
name: 'scf.invoice',
version: '1.0',
attributes: ['invoiceId', 'amount', 'currency', 'dueDate'],
});
const credDef = await primecredence.vdr.writeCredentialDefinition({
schemaId: schema.schemaId,
tag: 'default',
supportRevocation: true,
});
// Register the trust framework and an authorized issuer under it
const framework = await primecredence.registry.admin.createFramework({
did: 'did:web:authority.example.com',
name: 'Supply Chain Finance Framework',
version: '1.0.0',
metadata: { description: 'Authorizes invoice-credential issuers' },
});
await primecredence.registry.admin.registerIssuer({
issuerDid: 'did:indy:sovrin:issuer123',
credentialType: 'InvoiceCredential',
issuerName: 'Acme Bank',
});
// Read the governance surface any verifier relies on
const frameworks = await primecredence.registry.listFrameworks();
const governanceVcs = await primecredence.registry.listGovernanceVcs({ status: 'ACTIVE' });3. Register identities (DIDs)
Issuers, holders, and verifiers each act under a DID. Register and list a tenant's DIDs, and optionally bind FIDO2 passkeys for user-level authentication.
const did = await primecredence.identity.registerDid({ method: 'did:key' });
const dids = await primecredence.identity.listDids();
// Optional: passkey (FIDO2/WebAuthn) registration for the logged-in user
const options = await primecredence.identity.fido2BeginRegistration();4. Issue a credential
Issue a VC to a subject. Provide an existing connectionId, or omit it and pass
recipientTenantId — the service resolves or creates the issuer→recipient DIDComm link and
delivers over it.
const credential = await primecredence.credentials.issue({
credentialType: 'InvoiceCredential',
schemaId: schema.schemaId,
credDefId: credDef.credDefId,
issuerDid: 'did:indy:sovrin:issuer123',
subjectDid: 'did:indy:sovrin:supplier456',
claims: { invoiceId: 'INV-2026-001', amount: '15000', currency: 'USD', dueDate: '2026-09-01' },
recipientTenantId: '…', // service finds-or-creates the DIDComm link
frameworkId: framework.id, // optional issuance-prerequisite evaluation
});5. Verify a credential (the 5-Check)
Verification is more than a signature check. The 5-check engine confirms: the proof is genuine (DID resolves, signature valid), the issuer is authorized in the Trust Registry, the schema is accepted, any requirement/predicate is satisfied, and the credential is not revoked (checked live against the ledger).
const result = await primecredence.credentials.verifyV2({
credentialId: credential.id,
policyId: 'invoice-verification-policy', // optional — selects which checks run
});
console.log(result.valid, result.checks); // per-check PASS/SKIP/FAIL/ERROR breakdown
// Or run a governance trust-check on a stored/held credential (ALLOW/DENY + breakdown)
const verdict = await primecredence.credentials.trustCheck(credential.id);6. Request & verify presentations (wallet flows)
Ask a holder to present specific credentials, then verify what comes back. Use a DIDComm exchange over a connection, or generate an OID4VP URL for a mobile wallet.
// DIDComm presentation request against an existing connection
const exchange = await primecredence.presentations.createRequest({
connectionId: '…',
presentationDefinition: { /* DIF Presentation Definition */ },
comment: 'Please present your invoice credential',
});
// Or an OID4VP authorization URL for a wallet to scan
const url = await primecredence.presentations.generateOid4vpUrl({
presentationDefinition: { /* … */ },
clientId: 'did:web:verifier.example.com',
redirectUri: 'https://verifier.example.com/callback',
});
// Verify the received presentation with the 5-check engine
const verified = await primecredence.presentations.verify(exchange.id);
console.log(verified.verified, verified.verificationContext);
// OpenID-rail authorization request (SD-JWT VC default, or the unlinkable
// BBS rail with format: 'bbs+vc-json' — ADR-0041)
const created = await primecredence.presentations.createOid4vpRequest({
vct: 'urn:primecredence:vc:invoice:1',
requestedClaims: ['invoice_number', 'invoice_amount'],
requestedPredicates: [{ claim: 'invoice_amount', op: 'lte', value: 5000 }],
format: 'bbs+vc-json',
});
console.log(created.authorizationUrl); // openid4vp://?client_id=...&request_uri=...7. Revoke & check status
Revoke an issued credential, then read the BitstringStatusList a verifier consults to see current revocation state.
await primecredence.credentials.revoke(credential.id);
const statusList = await primecredence.registry.getStatusList('status-list-2026');
console.log(statusList.encodedList); // gzip+base64 bitstring8. Meter usage & billing (for paid services)
If you're building a metered service on top of PrimeCredence, ingest usage events, attach a pricing plan, and rate/invoice the period.
// Ingest a batch of usage events (idempotent by eventId)
await primecredence.billing.ingestEvents({
events: [
{ eventId: 'evt-1', eventType: 'credential.issued', quantity: 1 },
{ eventId: 'evt-2', eventType: 'credential.verified', quantity: 1 },
],
});
// Attach a catalog plan, then rate and invoice the period
const plans = await primecredence.billing.listPricingPlans();
const contract = await primecredence.billing.createContractFromPlan({ planKey: 'pro-monthly' });
const rated = await primecredence.billing.rateUsage({
periodStart: '2026-07-01T00:00:00Z',
periodEnd: '2026-08-01T00:00:00Z',
});
const invoice = await primecredence.billing.generateInvoice({ /* period bounds */ });Full method-by-method documentation lives in the in-Studio API Reference and the SDK's typed exports — every request/response shape above is a TypeScript type you can import.
Modules
| Module | Description | Endpoint Prefix |
|--------|------------|----------------|
| identity | Auth (register, login, password reset, refresh, FIDO2), tenants, DID management, user onboarding, role grants | /api/v1/auth/**, /api/v1/tenants/**, /api/v1/identity/**, /api/v1/onboarding/** |
| credentials | Get/list, verify (legacy 3-check + verifyV2 5-check), revoke, delete, trust-check, verification history/count, held-by. (Issuance moved to oid4vci/wallet.) | /api/v1/credentials/** |
| presentations | OID4VP presentation exchange + verify (5-check), SD-JWT + unlinkable BBS rails | /api/v1/presentations/** |
| registry | TRQP queries + full admin: frameworks/config/detail, schemas, issuers, policies, governance-VC lifecycle, solutions, participant onboarding, verifier profiles, DIA, feature-toggles, KMS, ledger-events | /api/v1/registry/**, /api/v1/admin/** |
| compliance | Checks, audit events, rules, lifecycle models, retention policies | /api/v1/compliance/** |
| evidence | Upload, verify, link | /api/v1/evidence/** |
| oid4vci | Issuer metadata, offers, token, credential | /api/v1/oid4vci/** |
| payments | Create, track, refund, invite-to-pay | /api/v1/payments/** |
| billing | Metering, contracts, invoices, settlement, analytics (KPIs/usage), pricing-plan catalog | /api/v1/billing/**, /api/v1/pricing-plans/** |
| wallet | Entity wallet (organizational holder): receive OID4VCI offers (format dc+sd-jwt or bbs+vc-json — the unlinkable BBS rail, ADR-0041), vault credentials, answer OID4VP requests (approval queue), holder keys, settings | /api/v1/wallet/** |
| signingKeys | Per-issuer signing identity (ADR-0043): list / provision / import (BYO key) / rotate / retire, self-sovereign did:web:<domain> + domain-control verify, and BYOK key-protection custody (PLATFORM / TENANT_KEY / EXTERNAL_KMS, ADR-0044). signingKeys.participants.* covers onboarded participants (owner-managed) | /api/v1/issuer-keys/** |
Features
- Zero runtime dependencies — uses only Node.js builtins (
node:crypto) - Dual ESM + CJS build — works in all Node.js environments
- Full TypeScript types — mirrored from PrimeCredence backend DTOs
- Auto correlation ID —
X-Correlation-IDheader on every request - Retry with backoff — configurable retry for 429/502/503/504
- RFC 7807 errors — structured error responses with
PrimeCredenceApiError - DID validation — client-side allowlist helper (did:key, did:web — ADR-0037)
- Key material detection — helper to prevent accidental secret leakage
Configuration
const primecredence = new PrimeCredenceClient({
baseUrl: 'https://gateway:8080',
auth: { type: 'jwt', token: 'eyJ...' },
retry: { maxRetries: 3, baseDelay: 1000, maxDelay: 30000 },
timeout: 30000,
correlationId: 'custom-correlation-id', // optional; auto-generated if omitted
});
// Refresh token
primecredence.setToken(newToken);
// Add interceptors
primecredence.addRequestInterceptor(async (url, init) => {
// modify request before sending
return init;
});Breaking Changes (v0.2.0)
Governance VC lifecycle methods now require LifecycleTransitionRequest
All 5 governance VC lifecycle methods (submitForReview, activateGovernanceVc, suspendGovernanceVc, reinstateGovernanceVc, revokeGovernanceVc) now require a LifecycleTransitionRequest body with a mandatory actorDid field:
// Before (v0.1.x) — no longer works
await primecredence.registry.admin.submitForReview(vcId);
// After (v0.2.0) — actorDid is required
await primecredence.registry.admin.submitForReview(vcId, {
actorDid: 'did:web:steward.example.com',
reason: 'Ready for governance board review', // optional
});GovernanceVcCreateRequest now requires proofHash
The proofHash field (SHA-256 hash of canonical VC JSON) is now required when creating governance VCs for deduplication:
await primecredence.registry.admin.createGovernanceVc({
frameworkId: '...',
vcType: 'ISSUER_AUTHORIZATION',
vcJson: { /* W3C VCDM 2.0 */ },
issuerDid: 'did:web:authority.example.com',
subjectDid: 'did:web:issuer.example.com',
validFrom: '2026-01-01T00:00:00Z',
proofHash: 'sha256-hex-hash-of-canonical-vc-json', // now required
});Framework request field renames
TrustFrameworkCreateRequest and TrustFrameworkUpdateRequest use did (not governingAuthority) and metadata (not description):
await primecredence.registry.admin.createFramework({
did: 'did:web:authority.example.com', // was: governingAuthority
name: 'My Framework',
version: '1.0.0',
metadata: { description: '...' }, // was: description (string)
});Development
npm install # Install dependencies
npm run build # Build ESM + CJS + DTS
npm test # Run unit tests
npm run typecheck # TypeScript type checking
npm run check:drift # SDK ⇄ OpenAPI coverage/drift checkStaying in sync with the API
The SDK's typed modules are hand-written for ergonomics, so they can drift from the
backend as endpoints are added. npm run check:drift (scripts/check-drift.mjs, zero
dependencies) guards against that: it extracts every path the SDK calls and compares it
to the contract of record in contracts/openapi/*.json.
- Fails (exit 1) when a spec endpoint has no SDK method — a real coverage gap. Wire the
method, or, if it's genuinely not SDK-callable (discovery metadata, internal
service-to-service, inbound webhook receivers), add it to
scripts/drift-allowlist.jsonwith a reason. - Warns (exit 0) when the SDK calls a path no spec declares — usually a stale/incomplete spec (the OpenAPI files trail the live controllers), occasionally a dead route.
Run it in CI to keep coverage from regressing. Note the comparison is SDK-vs-spec; keeping the specs themselves current against the Spring controllers is a separate, backend-side task.
Releases (maintainers only)
This SDK uses a semi-automated release workflow. From the monorepo root:
# Pre-release (publishes under `next` dist-tag):
make sdk-release VERSION=1.0.0-rc.2
# Stable release (publishes under `latest` dist-tag):
make sdk-release VERSION=1.0.0The script:
- Runs safety checks (clean tree, on main, in sync with origin, tag available)
- Bumps
package.jsonversion - Opens your editor with a CHANGELOG template
- Commits, tags (
sdk-vX.Y.Z), and pushes
Pushing the tag triggers .github/workflows/npm-publish.yml which:
- Runs 152 tests + TypeScript strict + tsup build
- Publishes to npmjs.com with Sigstore provenance attestation
- Smart dist-tag selection (pre-release →
next, stable →latest) - Auto-creates a GitHub Release with changelog
Full runbook: docs/operations/sdk-release-process.md
Changelog
See CHANGELOG.md for release history.
Spec & Compliance
- Spec:
specs/primecredence-sdk/spec.md(85 FRs, 8 NFRs) - Compliance audit:
specs/primecredence-sdk/compliance-audit.md— all PASS - KB references:
[KB:00-system],[KB:01-architecture],[KB:14-learnings-v1-v2]
License
Apache License 2.0 — Copyright 2026 PrimeThoughts Innovation Pvt. Ltd.
