> ## Documentation Index
> Fetch the complete documentation index at: https://docs.voicemark.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# TypeScript SDK

> Full API reference for the VoiceMark TypeScript/JavaScript SDK.

## Initialisation

```typescript theme={null}
import { VoiceMark } from "@defchat-ltd/voicemark-sdk";

const vm = new VoiceMark({
  apiKey: process.env.VOICEMARK_API_KEY,
  baseUrl: "https://api.voicemark.dev/v1", // optional override
});
```

## Methods

### `enroll(audio, userId)`

```typescript theme={null}
const enroll: EnrollResponse = await vm.enroll(blob, userId);
```

| Param | Type | Notes |
| - | - | - |
| `audio` | `Blob \| File` | Audio recording |
| `userId` | `string` | Your internal user ID |

Returns `EnrollResponse`:

```typescript theme={null}
interface EnrollResponse {
  voiceprint_id: string;
  enrolled_at: string;
  quality_score: number;    // 0–1
  duration_s: number;
  glyph_params: Record<string, number>;
}
```

***

### `challenge(excludePhrase?)`

```typescript theme={null}
const { phrase, challenge_id } = await vm.challenge();
```

Returns `ChallengeResponse`:

```typescript theme={null}
interface ChallengeResponse {
  phrase: string;
  challenge_id: string;
  expires_in: number;
  source?: { title?: string; author?: string; year?: string; attribution?: string };
}
```

***

### `verify(audio, options?)`

```typescript theme={null}
const verify: VerifyResponse = await vm.verify(blob, {
  voiceprintId: storedVoiceprintId,
  challengeId: challenge_id,
});
```

| Option | Type | Notes |
| - | - | - |
| `voiceprintId` | `string?` | Identity check |
| `challengeId` | `string?` | Anti-replay check |

Returns `VerifyResponse`:

```typescript theme={null}
interface VerifyResponse {
  token: string;
  token_id: string;
  authorized: boolean;
  pii: null;
  expires_in: number;
  liveness_score?: number;
  transcription?: string;
  cloud_data?: {
    words: Array<{ word: string; f0: number; rms: number; bands: number[] }>;
    glyph_params: Record<string, number>;
  };
}
```

***

### `token(tokenId, tokenJwt?)`

```typescript theme={null}
const { valid, expires_in } = await vm.token(tokenId, tokenJwt);
```

***

### `policy(token, action)`

```typescript theme={null}
const { permitted } = await vm.policy(verify.token, "payment.authorise");
```

***

### `receipt(token, action, result, metadata?)`

```typescript theme={null}
await vm.receipt(verify.token, "payment.authorise", "success", {
  amount: 250, currency: "GBP",
});
```

## Error handling

All methods throw `VoiceMarkError` on failure:

```typescript theme={null}
import { VoiceMarkError } from "@defchat-ltd/voicemark-sdk";

try {
  const verify = await vm.verify(blob, { voiceprintId });
} catch (err) {
  if (err instanceof VoiceMarkError) {
    console.error(err.code);    // "VOICE_MISMATCH" | "CHALLENGE_EXPIRED" | ...
    console.error(err.status);  // HTTP status code
    console.error(err.message);
  }
}
```

### Error codes

| Code | Description |
| - | - |
| `UNAUTHORIZED` | Missing or invalid API key |
| `VOICE_MISMATCH` | Speaker below match threshold |
| `TOKEN_EXPIRED` | Token TTL elapsed |
| `INVALID_AUDIO` | Unrecognised audio format |
| `AUDIO_TOO_SHORT` | Clip under 2 seconds |
| `AUDIO_TOO_QUIET` | RMS below threshold |
| `LOW_VOICE_SIGNAL` | No voice identity in audio |
| `CHALLENGE_EXPIRED` | Challenge TTL elapsed |
| `NETWORK_ERROR` | Fetch-level error |
| `MICROPHONE_DENIED` | getUserMedia permission refused |
| `PIPELINE_UNAVAILABLE` | Transient model unavailability (503) |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.