# @humanity-org/connect-sdk

{% hint style="info" %}
Looking for a simple a front end solution with React? → [@humanity-org/react-sdk](/build-with-humanity/build-with-the-sdk-api/humanity-org-react-sdk.md)
{% endhint %}

## 1. About humanity-org/connect-sdk

The `@humanity-org/connect-sdk` package is the **official TypeScript** **integration layer** for Humanity’s Public API.

## 2. Common SDK use cases

Use `@humanity-org/connect-sdk` if you are building a Node.js or TypeScript application and want:

* Typed helpers instead of raw HTTP calls
* Built-in handling for OAuth, PKCE, and preset verification
* Safer defaults for retries, errors, and token handling

## 3. Installation

```bash
npm install @humanity-org/connect-sdk
# or
yarn add @humanity-org/connect-sdk
# or
pnpm add @humanity-org/connect-sdk
```

```tsx
import { HumanitySDK } from '@humanity-org/connect-sdk';
```

## 4. 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. |
| `fetch`          | ➖        | Provide your own implementation of `fetch`                                                        |
| `defaultHeaders` | ➖        | Pass a map of header names → values, and the SDK will merge them into all outgoing requests       |

### **Full Interface**

```typescript
interface HumanitySdkConfig {
    clientId: string;
    redirectUri: string;
    clientSecret?: string;           // For confidential clients
    environment?: EnvironmentName | string;
    baseUrl?: string;                // Override API base URL
    defaultHeaders?: Record<string, string>;
    fetch?: typeof fetch;            // Custom fetch implementation
}
```

### **Example: Local or serverless project**

```tsx
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 a new SDK instance per request (common in serverless), or reuse a shared instance and pass tokens as needed.

> :warning:\
> \
> Build-time vs Runtime SDK Instantiation\
> \
> When using Next.js or similar SSG/SSR frameworks, the SDK cannot be instantiated at module level (build time) because environment variables may not be available.
>
> ```tsx
> // ❌ This breaks builds:
> export const sdk = new HumanitySDK({ clientId: process.env.HUMANITY_CLIENT_ID! });
>
> // ✅ Use lazy initialization:
> let sdk: HumanitySDK | null = null;
> export function getHumanitySDK() {
>     if (!sdk) {
>         sdk = new HumanitySDK({ ... });
>     }
>     return sdk;
> }
> ```

### Confidential vs public clients

| App type                | Client type  | Uses `clientSecret` |
| ----------------------- | ------------ | ------------------- |
| Browser SPA             | Public       | No                  |
| Mobile app              | Public       | No                  |
| Next.js backend         | Confidential | Yes                 |
| API server              | Confidential | Yes                 |
| Background job / worker | Confidential | Yes                 |

* **Frontend apps** → do not set `clientSecret`
* **Backend apps** → may use `clientSecret` for confidential flows
* **Serverless** → create a new SDK instance per request (stateless)
* **Node server** → initialize once and pass tokens into helpers as needed

{% hint style="warning" %}
Always store credentials in a secrets manager—never commit them to source control.
{% endhint %}

## 5. OAuth helpers

These helpers implement the full OAuth redirect flow: redirecting the user to Humanity, exchanging the authorization code, and managing tokens.

**Build the authorization URL**

```tsx
const { url, codeVerifier } = sdk.buildAuthUrl({
  scopes: ['identity:read', 'kyc:read']
  additionalQueryParams: { prompt: 'consent' }
});
```

**Redirect the user to `url`. When Humanity calls back with `?code=...`, exchange it**

```tsx
const token = await sdk.exchangeCodeForToken({
  code: callbackQuery.get('code')!,
  codeVerifier, // must match the one from buildAuthUrl
});
```

{% hint style="info" %}
Store `codeVerifier` and `state` temporarily (for example, in a session or HTTP-only cookie) and reuse them when handling the callback.
{% endhint %}

{% hint style="warning" %}
**Avoid these common mistakes:**

* Forgetting to store `codeVerifier` between the redirect and callback
* Passing a redirect URI that does not match the one registered
* Missing required preset scopes during URL construction
  {% endhint %}

The SDK returns a structured **TokenResult** object that contains more than just the access and refresh tokens.

This object includes important metadata you should store for your session management and user mapping.

### TokenResult raw interface

```typescript
interface TokenResult {
  accessToken: string;
  tokenType: string;
  expiresIn: number;
  scope: string;
  grantedScopes: string[];
  presetKeys: DeveloperPresetKey[];
  authorizationId: string;

  // 🔑 Stable user identifier for your application
  appScopedUserId: string;

  issuedAt?: string;
  refreshToken?: string;
  refreshTokenExpiresIn?: number;
  refreshIssuedAt?: string;
  idToken?: string;

  raw: OauthTokenResponse;
  rateLimit?: RateLimitInfo;
}
```

### TokenResult interface description

| 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 information from response headers.                  |

### **Token revocation**

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

## 6. Preset verification

Call preset verification after you have an access token—typically right after sign-in or when gating a sensitive action.

```tsx
const presets = await sdk.verifyPresets({
  accessToken: token.accessToken,
  presets: ['is_human', 'is_21_plus'],
});

// Example output:
// {
//   results: [
//     { preset: 'is_human', value: true, status: 'valid', ... },
//     { preset: 'is_21_plus', value: true, status: 'valid', ... }
//   ],
//   errors: []
// }
```

* `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 Interface**

`VerifyPresets` helper returns a `PresetBatchResult` describing the outcome of each requested check.

```typescript
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
  };
}
```

## 7. Query Engine <a href="#query-engine" id="query-engine"></a>

For declarative queries against user credentials.

```typescript
// 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' }
    ]
  }
});
```

* Responses include verification outcomes and safe evidence metadata.
* The SDK normalizes return types so you can write stable application logic.
* Errors propagate as typed `HumanitySDKError` objects (see below).

## 8 Using the generated client directly

The generated sdk.client exposes every API endpoint exactly as defined in the OpenAPI specification. Both the SDK helpers and the raw client share the same authentication and transport logic

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

**Why this is useful**

* For advanced edge cases
* For writing internal abstractions
* For accessing controllers not wrapped by the SDK
* For debugging or prototyping low-level requests

{% hint style="info" %}
The SDK and API reference regenerate from the same DTOs (`src/contracts`), TypeScript will always warn you about breaking changes before deploy time.
{% endhint %}

## 9. Error handling

The SDK exports typed error classes for precise error handling:

```tsx
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
    });
  }
}

```

### HumanitySDKError Interface description

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

* Rate limits follow the guidance in [Environments & tooling](https://humanity-eaeda8f6.mintlify.app/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.

## **10. Before You Ship to Production**

A final checklist for production readiness:

* The PKCE flow works end-to-end across all supported browsers
* Redirect URIs are registered for both sandbox and production
* Preset scopes requested by the app are enabled and verified
* Error cases are handled gracefully (expired tokens, revoked access, etc.)
* Retries are safe and don’t create duplicate actions
* Advanced use cases using the raw client have been validated
* The build and deployment pipeline points to the production environment

{% hint style="success" %}
Need integration examples?. Head to [connect-sdk-examples](/starter-templates-and-examples/sdk-integration-templates/connect-sdk-examples.md)
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.humanity.org/build-with-humanity/build-with-the-sdk-api/humanity-org-connect-sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
