> ## Documentation Index
> Fetch the complete documentation index at: https://humanity-eaeda8f6.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# @humanity-org/connect-sdk

> Typed TypeScript helper layered on top of the generated REST client.

`@humanity-org/connect-sdk` is the official TypeScript helper for Humanity’s Public API. It wraps the generated REST client with ergonomic helpers for OAuth, preset verification, feeds, and error handling so partner teams can ship integrations quickly.

## Installation

```bash theme={null}
npm install @humanity-org/connect-sdk
# or
yarn add @humanity-org/connect-sdk
# or
pnpm add @humanity-org/connect-sdk
```

```ts theme={null}
import { HumanitySDK } from '@humanity-org/connect-sdk';
```

## Initialization & configuration

| Option             | Required | Description                                                                                       |
| ------------------ | -------- | ------------------------------------------------------------------------------------------------- |
| `clientId`         | ✅        | Issued when your app is approved.                                                                 |
| `redirectUri`      | ✅        | Must match one of the URIs registered with Humanity.                                              |
| `environment`      | ➖        | `sandbox` or `production`. Sets the Humanity base URL automatically (defaults to `sandbox`).      |
| `baseUrl`          | ➖        | Advanced override for regional/private deployments (takes precedence over `environment`).         |
| `clientSecret`     | ➖        | Only required for confidential clients or service-to-service flows. Never ship it to the browser. |
| `clockToleranceMs` | ➖        | Adjusts token expiry validation for skewed environments.                                          |
| `defaultHeaders`   | ➖        | Custom headers to include with every request (e.g., for tracing).                                 |
| `fetch`            | ➖        | Custom fetch implementation for environments without native fetch or for request interception.    |

```ts theme={null}
const sdk = new HumanitySDK({
  clientId: process.env.HUMANITY_CLIENT_ID!,
  redirectUri: process.env.HUMANITY_REDIRECT_URI!,
  environment: process.env.HUMANITY_ENVIRONMENT ?? 'sandbox',
  clientSecret: process.env.HUMANITY_CLIENT_SECRET, // optional
});
```

Create an instance per incoming request (ideal for serverless) or share a singleton and pass tokens into each helper—whichever matches your runtime. Store secrets in your platform's secret manager; never embed them in client-side bundles.

<Warning>
  **Next.js / SSR frameworks:** Do not instantiate the SDK at module level during build time, as environment variables may not be available. Use lazy initialization instead:

  ```ts theme={null}
  let sdk: HumanitySDK | null = null;

  export function getHumanitySDK() {
    if (!sdk) {
      sdk = new HumanitySDK({
        clientId: process.env.HUMANITY_CLIENT_ID!,
        redirectUri: process.env.HUMANITY_REDIRECT_URI!,
        environment: process.env.HUMANITY_ENVIRONMENT ?? 'sandbox',
      });
    }
    return sdk;
  }
  ```
</Warning>

## OAuth helpers

```ts theme={null}
const sdk = new HumanitySDK({
  clientId: process.env.HUMANITY_CLIENT_ID!,
  redirectUri: process.env.HUMANITY_REDIRECT_URI!,
  environment: 'sandbox',
});

// Generate state for CSRF protection
const state = HumanitySDK.generateState();

const { url, codeVerifier } = sdk.buildAuthUrl({
  // Use OAuth scopes (not preset names) - see /concepts/scopes
  scopes: ['identity:read', 'identity:date_of_birth', 'kyc:read'],
  state, // Pass state as input - it is NOT returned by buildAuthUrl
  additionalQueryParams: { prompt: 'consent' },
});

// Store state and codeVerifier server-side, then redirect user to `url`
// On callback, verify state matches before exchanging the code:
const token = await sdk.exchangeCodeForToken({
  code: callbackQuery.get('code')!,
  codeVerifier,
});

await sdk.revokeToken({
  token: token.refreshToken,
  tokenType: 'refresh_token',
});
```

Every helper maps to an OAuth endpoint (`/oauth/authorize`, `/oauth/token`, `/oauth/revoke`) and enforces the PKCE + grant-type requirements documented in the API reference.

### buildAuthUrl options

| Option                  | Required | Description                                                                                  |
| ----------------------- | -------- | -------------------------------------------------------------------------------------------- |
| `scopes`                | ✅        | Array of OAuth scopes to request (e.g., `['identity:read', 'kyc:read']`).                    |
| `state`                 | ➖        | CSRF protection token. Generate with `HumanitySDK.generateState()` and verify on callback.   |
| `nonce`                 | ➖        | Replay protection for ID tokens. Generate with `HumanitySDK.generateNonce()`.                |
| `codeVerifier`          | ➖        | Provide your own PKCE code verifier, or let the SDK generate one.                            |
| `codeVerifierLength`    | ➖        | Length of auto-generated code verifier (default: 43).                                        |
| `additionalQueryParams` | ➖        | Extra query parameters like `{ prompt: 'consent' }` or `{ login_hint: 'user@example.com' }`. |

**Returns:** `{ url: string, codeVerifier: string }` — the `state` is NOT returned; you must pass it in and store it yourself.

### TokenResult

The `exchangeCodeForToken` helper returns a fully typed `TokenResult`:

| Property                | Type       | Description                                                  |
| ----------------------- | ---------- | ------------------------------------------------------------ |
| `accessToken`           | `string`   | Bearer token for API requests.                               |
| `tokenType`             | `string`   | Always `"Bearer"`.                                           |
| `expiresIn`             | `number`   | Seconds until the access token expires.                      |
| `scope`                 | `string`   | Space-separated list of granted scopes.                      |
| `grantedScopes`         | `string[]` | Array of granted scopes.                                     |
| `presetKeys`            | `string[]` | Preset keys available for verification.                      |
| `authorizationId`       | `string`   | Unique ID for this authorization grant.                      |
| `appScopedUserId`       | `string`   | User ID scoped to your app—use this for user identification. |
| `issuedAt`              | `string?`  | ISO timestamp when the token was issued.                     |
| `refreshToken`          | `string?`  | Refresh token (confidential clients only).                   |
| `refreshTokenExpiresIn` | `number?`  | Seconds until the refresh token expires.                     |
| `refreshIssuedAt`       | `string?`  | ISO timestamp when the refresh token was issued.             |
| `idToken`               | `string?`  | OIDC ID token (when `openid` scope is requested).            |
| `raw`                   | `object`   | Raw API response for advanced use cases.                     |
| `rateLimit`             | `object?`  | Rate limit info from response headers.                       |

### Static security helpers

The SDK provides static methods for OAuth security parameters:

```ts theme={null}
// Generate cryptographically secure state for CSRF protection
const state = HumanitySDK.generateState();

// Generate nonce for replay protection (when using openid scope)
const nonce = HumanitySDK.generateNonce();

// Verify state matches on callback (timing-safe comparison)
if (!HumanitySDK.verifyState(storedState, callbackState)) {
  throw new Error('State mismatch - possible CSRF attack');
}

// Verify nonce in ID token
if (!HumanitySDK.verifyNonce(storedNonce, idTokenNonce)) {
  throw new Error('Nonce mismatch - possible replay attack');
}
```

## Preset verification

```ts theme={null}
const presets = await sdk.verifyPresets({
  accessToken: token.accessToken,
  presets: ['is_human', 'age_over_21', 'kyc_passed'],
});
```

* `verifyPreset`, `verifyPresets`, and `getPreset` expose the `/presets/*` endpoints with fully typed responses (including evidence payloads).
* Use `listPresets()` to discover all available presets with their metadata.
* Maximum of 10 presets per batch request; the helper enforces this before hitting the API.

### PresetBatchResult

The `verifyPresets` helper returns a `PresetBatchResult` with two arrays:

```ts theme={null}
interface PresetBatchResult {
  results: PresetCheckResult[];  // Successful verifications
  errors: PresetError[];         // Failed verifications
}

interface PresetCheckResult {
  preset: string;                // The preset key (e.g., "is_human")
  value: boolean | string | number | null;  // The verification result
  status: 'valid' | 'expired' | 'pending' | 'unavailable';
  evidence?: object;             // Credential evidence (varies by preset)
  expiresAt?: string;            // ISO timestamp when the result expires
}

interface PresetError {
  preset: string;
  error: {
    error: string;               // Error code
    error_description?: string;  // Human-readable description
  };
}
```

## Query Engine

For declarative queries against user credentials, use the Query Engine:

```ts theme={null}
// Predicate query (boolean check)
const ageCheck = await sdk.evaluateQuery({
  accessToken: token.accessToken,
  query: {
    check: { claim: 'identity.age', operator: '>=', value: 21 }
  }
});

if (ageCheck.passed) {
  // User is 21+
}

// Compound policy with multiple conditions
const eligibility = await sdk.evaluateQuery({
  accessToken: token.accessToken,
  query: {
    policy: {
      allOf: [
        { check: { claim: 'kyc.passed', operator: '==', value: true } },
        { check: { claim: 'identity.country', operator: 'in', value: ['US', 'CA'] } }
      ]
    }
  }
});

// Projection query (data extraction)
const userData = await sdk.evaluateQuery({
  accessToken: token.accessToken,
  query: {
    projections: [
      { claim: 'identity.email', lens: 'pluck' },
      { claim: 'identity.country', lens: 'pluck' }
    ]
  }
});
```

See the [Query Engine documentation](/api-reference/endpoint/queries-evaluate) for operators and examples.

## Dropping down to the raw client

The generated `sdk.client` exposes every controller method exactly as declared in the OpenAPI. Use it whenever you need lower-level access or when rolling your own abstractions.

```ts theme={null}
const preset = await sdk.client.presets.getPreset('humanity_user', {
  headers: { Authorization: `Bearer ${token.accessToken}` },
});
```

Because the SDK and API reference regenerate from the same DTOs (`src/contracts`), you can rely on TypeScript to catch breaking changes long before runtime.

## Error handling

The SDK exports typed error classes for precise error handling:

```ts theme={null}
import { HumanitySDKError, HttpError } from '@humanity-org/connect-sdk';

try {
  const token = await sdk.exchangeCodeForToken(code, codeVerifier);
} catch (error) {
  if (error instanceof HumanitySDKError) {
    console.error('SDK error:', {
      message: error.message,
      code: error.code,        // e.g., "invalid_grant", "E4003"
      status: error.status,    // HTTP status code
      details: error.details,  // Additional context from the API
    });
  }
}
```

| Error Class        | Description                                                                             |
| ------------------ | --------------------------------------------------------------------------------------- |
| `HumanitySDKError` | Base error for all SDK operations. Includes `message`, `code`, `status`, and `details`. |
| `HttpError`        | Network-level errors (timeouts, connection failures).                                   |

* Rate limits follow the guidance in [Environments & tooling](/development). Honor `Retry-After` headers and reuse `idempotency_key` values when retrying POSTs.
* If you lose track of the SDK abstraction, call `sdk.client` directly—both layers share the same authentication headers and transport pipeline.
