<!-- markdown mirror of https://mintid.net/en/sdk/typescript-client — generated at build time -->

> @mintid/verifier-client: a transport-only client for Node backends — zero runtime dependencies, no cryptography, no policy.

index — 12 documents

1.  [overviewsdk/00](/en/sdk)
2.  [getting startedsdk/01](/en/sdk/getting-started)
3.  [python sdksdk/02](/en/sdk/python)
4.  [service modesdk/03](/en/sdk/service-mode)
5.  [typescript clientsdk/04](/en/sdk/typescript-client)
    *   [quickstart](#quickstart)
    *   [error semantics](#error-semantics)
    *   [types](#types)
    *   [conformance](#conformance)
    *   [framework bridges](#framework-bridges)
6.  [mcp serversdk/mcp](/en/sdk/mcp-server)
7.  [conformancesdk/05](/en/sdk/conformance)
8.  [reason codessdk/06](/en/sdk/reason-codes)
9.  [adr-0001 · kyc trust modeladr/0001](/en/sdk/adr-0001-kyc-trust-model)
10.  [adr-0002 · packagingadr/0002](/en/sdk/adr-0002-packaging)
11.  [adr-0003 · multi-languageadr/0003](/en/sdk/adr-0003-multilanguage)
12.  [bip-0001 · contract freezebip/0001](/en/sdk/bip-0001-verifier-service-contract)

SDK docs · sdk/04

# TypeScript client

@mintid/verifier-client: a transport-only client for Node backends — zero runtime dependencies, no cryptography, no policy.

## Quickstart

A transport-only client for **Node backends** (Node ≥ 20, ESM + types, zero runtime dependencies). It talks to the verifier service **your agency deploys**; it carries no cryptography, no chain access, no nonce store and no policy. If a change to this package ever looks like a verification feature, it belongs to the service instead.

**Node-only, on purpose.** Challenges are bound to your registered verifier identity and signed with your request keys; the decision gates your business logic. That is server-side material — a browser build will not be provided.

typescriptsdk/04 · verbatim

```
import { VerifierClient } from "@mintid/verifier-client";

// Your own service instance — never a third party's.
const client = new VerifierClient("http://127.0.0.1:8471");

// 1. Issue a challenge (policy only — expiry is always +10 s, server-side).
const challenge = await client.createChallenge({
  claim_policy: [{ claim: "age_over", value: 18, operator: ">=" }],
});
// → forward challenge.request + challenge.signature_hex to the holder.

// 2. Validate the holder's response.
const decision = await client.validatePresentation({
  request: challenge.request,
  envelope: holderResponse, // { proof_hex, issuer_id, status_root, claimed_predicates }
});

if (decision.accepted) {
  decision.verified?.proven_predicates; // e.g. ["age_over"]
} else {
  decision.reason_code; // closed vocabulary, e.g. "nonce_replayed"
}
```

## Error semantics (the part people get wrong)

**A rejection is a resolved decision, not an exception.** The client throws only for transport-level events:

Throws

When

What to do

`MalformedBodyError`

HTTP 400 — body not parseable into the contract schema

fix the caller; this is a programming error

`StateUnavailableError`

HTTP 503 — service fail-closed on unproven chain state

retry later; never bypass

`UnexpectedResponseError`

network failure, non-JSON body, undocumented status

treat as an outage

Everything else — replayed nonces, expired presentations, unbound proofs, suspended issuers — arrives as `{ accepted: false, reason_code }` with HTTP 200. Branch on data, not on exceptions.

## Types

Wire types mirror the contract 1:1 (`PresentationRequestBody`, `PresentationEnvelope`, `PresentationDecision`, `BuildInfo`, …), with `REASON_CODES` as a `const` tuple and `ReasonCode` as its union type. The vocabulary is test-locked against the shared conformance suite: a reason code cannot be added, renamed or dropped anywhere in the system without every language shipping the change together.

## Conformance

`npm test` replays the entire cross-language vector suite through this client over real HTTP against the reference service and asserts byte-equal decisions. A client release declares the suite version it passed — that declaration is its compatibility contract.

## Framework bridges

Express/Nest adapters are deliberately not in this package; they will ship as separate optional packages so the core client stays dependency-free and auditable at a glance. PHP (`mintid/verifier-client`, Composer, PSR-18) is the next client in the committed order.

[previous← service mode](/en/sdk/service-mode)[nextmcp server →](/en/sdk/mcp-server)

---
Source: https://mintid.net/en/sdk/typescript-client · TypeScript client — MintID verifier SDK docs
