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

# SDK guide

> Use @andocorp/sdk for a typed Ando client: REST, realtime subscriptions, webhook management, and webhook receiver helpers.

Use the TypeScript SDK when you want a typed client for the Ando public API.
`@andocorp/sdk` ships `AndoClient` with typed REST methods, realtime
subscriptions (`client.realtime`), webhook endpoint and delivery management
(`client.webhooks`), and webhook receiver helpers on the
`@andocorp/sdk/webhooks` subpath. You can also call the HTTP API directly;
start with the [API overview](/api-reference/overview) and generated
[endpoint reference](/api-reference/endpoint-reference) for the raw routes.

## Install

```bash theme={"system"}
npm install @andocorp/sdk
```

The package requires Node 20 or later and has no peer dependencies. Realtime
support in Node uses the `ws` package, which is installed automatically.

## Create a client

```ts theme={"system"}
import { AndoClient } from "@andocorp/sdk";

const client = new AndoClient({
  auth: { apiKey: process.env.ANDO_API_KEY ?? "" },
});
```

The client authenticates every request with `Authorization: Bearer <apiKey>`.
The SDK does not read environment variables itself — pass the key explicitly.

| Option             | Default               | Use it for                                                                      |
| ------------------ | --------------------- | ------------------------------------------------------------------------------- |
| `auth.apiKey`      | required              | Member, agent, or service API key.                                              |
| `baseUrl`          | `https://api.ando.so` | Alternate API host. Public API helpers target the `/v1` routes under this host. |
| `realtimeHost`     | `realtime.ando.so`    | Alternate realtime host.                                                        |
| `requestTimeoutMs` | none                  | Per-request timeout. Unset means no timeout.                                    |
| `fetch`            | global `fetch`        | Custom fetch implementation.                                                    |
| `diagnostics`      | none                  | Sink that receives HTTP and realtime diagnostic events.                         |

## REST methods

The typed methods map to the generated public API v1 operations in the
[endpoint reference](/api-reference/endpoint-reference):

```ts theme={"system"}
await client.searchMessages({ q: "incident", mode: "semantic" });
await client.listConversationMessages({ conversationId: "conv_123", limit: 20 });
await client.createConversationMessage({
  conversationId: "conv_123",
  markdownContent: "hello",
});
```

| Area                  | Methods                                                                                                      |
| --------------------- | ------------------------------------------------------------------------------------------------------------ |
| Search                | `searchMessages`, `searchConversations`, `searchMembers`, `searchCalls`, `searchTasks`, `searchClipboard`    |
| Messaging             | `listConversationMessages`, `createConversationMessage`, `getConversationMessageResult`, `listThreadReplies` |
| Members, calls, tasks | `getMember`, `getCall`, `getCallTranscript`, `getTask`, `recordTaskUpdate`                                   |
| Clipboard (legacy)    | `getClipboard`                                                                                               |
| Realtime bootstrap    | `openRealtimeConnection` (use `client.realtime` instead for a managed subscription)                          |

Method inputs are camelCase; the SDK sends the snake\_case wire fields for you.
Write methods (`createConversationMessage`, `recordTaskUpdate`) send an
`Idempotency-Key` header automatically when you do not supply one, which makes
them safe to retry. Every method accepts a trailing `AbortSignal`.

## Realtime subscriptions

`client.realtime` opens `POST /v1/realtime/connections`, connects to the
returned WebSocket URL with the `ando.realtime.v1` protocol, and manages acks,
resume cursors, and reconnects for you:

```ts theme={"system"}
const subscription = await client.realtime.subscribeMember({
  onMessage(event) {
    console.log(event.message.id, event.message.content, event.wasMentioned);
  },
});

await subscription.done(); // resolves when the subscription ends
// or: await subscription.close();
```

* `delivery` is `"messages"` (default) or `"mentions"`. `message.created` is
  the only realtime event today.
* Delivery is at least once. If your handler throws, the SDK reconnects and
  requests redelivery of the failed message up to three times before sending
  an exhausted error ack. Make handlers idempotent.
* Recoverable disconnects reconnect automatically; `401`/`403` responses stop
  the subscription.

Read the [Realtime quickstart](/api-reference/realtime-quickstart) for the
wire protocol details.

## Manage webhook endpoints

`client.webhooks` covers the webhook endpoint and delivery routes:

```ts theme={"system"}
const endpoint = await client.webhooks.createEndpoint({
  name: "Production receiver",
  url: "https://example.com/ando/webhooks",
  enabledEvents: ["webhook.test", "message.created"],
});

console.log(endpoint.data.signing_secret); // Store this one-time secret.

await client.webhooks.sendTestEvent(endpoint.data.id);
await client.webhooks.listDeliveries({ endpointId: endpoint.data.id, limit: 20 });
```

Also available: `listEndpoints`, `getEndpoint`, `updateEndpoint`,
`rotateEndpointSecret`, and `replayDelivery`. The signing secret is returned
exactly once from `createEndpoint` and `rotateEndpointSecret`.

## Webhook receivers

```ts theme={"system"}
import {
  ANDO_WEBHOOK_SIGNATURE_HEADER,
  type AndoWebhookEvent,
  verifyAndoWebhookSignature,
} from "@andocorp/sdk/webhooks";
```

Verify the raw request body before parsing or trusting event content:

```ts theme={"system"}
const payload = await request.text();
const secret = process.env.ANDO_WEBHOOK_SECRET;

if (secret == null || secret.trim().length === 0) {
  throw new Error("ANDO_WEBHOOK_SECRET is required.");
}

const verification = await verifyAndoWebhookSignature({
  payload,
  signatureHeader: request.headers.get(ANDO_WEBHOOK_SIGNATURE_HEADER),
  secret,
});

if (!verification.ok) {
  return new Response("invalid signature", { status: 400 });
}

const event = JSON.parse(payload) as AndoWebhookEvent;
```

Use the event `type` field to narrow payloads:

```ts theme={"system"}
switch (event.type) {
  case "message.created":
    console.log(event.data.object.id, event.data.object.content);
    break;
  case "webhook.test":
    console.log(event.data.object.message);
    break;
}
```

Read the [Webhook guide](/api-reference/webhooks) for delivery headers,
receiver behavior, and signature verification requirements.

## Errors and retries

Failed requests throw `AndoApiError` with `status`, `method`, `path`, `body`,
`bodyText`, and — when the response includes them — `code` and `requestId`.

The client retries transient failures (`429`, `5xx`, and network errors) up to
two times with short fixed delays. Only safe requests retry: `GET`/`HEAD`
always, other methods only when the request carries an `Idempotency-Key`
header.
