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

# Installation & setup

> Install the TypeScript SDK and construct a Tally client.

The Tally TypeScript SDK is published as `@tallyforagents/sdk`. It targets Node 20+ and uses the platform's native `fetch` — no extra dependencies for the network layer.

## Install

```bash theme={null}
npm install @tallyforagents/sdk
```

`pnpm`, `yarn`, and `bun` work the same way. The SDK has no peer dependencies and ships its own type definitions.

## Construct a client

```ts theme={null}
import { Tally } from "@tallyforagents/sdk";

const tally = new Tally({
  apiKey: process.env.TALLY_API_KEY!,
});
```

`new Tally({ apiKey })` is the only call you'll make to set up. The returned client exposes `agents`, `payments`, and `webhooks` resources.

## `ClientOptions`

| Field     | Type           | Required | Description                                                                                                    |
| --------- | -------------- | -------- | -------------------------------------------------------------------------------------------------------------- |
| `apiKey`  | `string`       | Yes      | A Tally API key starting with `tly_test_` (test mode) or `tly_live_` (live mode).                              |
| `baseUrl` | `string`       | No       | Base URL of the Tally API. Defaults to `http://localhost:3000`. Production callers should set this explicitly. |
| `fetch`   | `typeof fetch` | No       | Custom fetch implementation. Useful for tests, non-Node runtimes, or wrapping with retry middleware.           |

### API key validation

The constructor validates the key prefix and throws a `TallyError` (`type: "validation_failed"`) if the key doesn't start with `tly_test_` or `tly_live_`. This catches misconfigured environments at startup, not at first request.

```ts theme={null}
try {
  const tally = new Tally({ apiKey: "wrong_prefix_key" });
} catch (err) {
  // err.message: "Invalid API key. Tally keys start with 'tly_test_' or 'tly_live_'."
}
```

### Setting `baseUrl` in production

The SDK defaults `baseUrl` to `http://localhost:3000` so a fresh install Just Works against a locally running Tally. For any deployed environment, set it explicitly:

```ts theme={null}
const tally = new Tally({
  apiKey: process.env.TALLY_API_KEY!,
  baseUrl: process.env.TALLY_BASE_URL ?? "https://api.tally.example.com",
});
```

Trailing slashes are stripped — `https://api.example.com/` and `https://api.example.com` are equivalent.

### Custom `fetch`

If you want to wrap requests with logging, retries, or use a runtime where `globalThis.fetch` isn't available, pass a custom implementation:

```ts theme={null}
import fetch from "node-fetch"; // or any fetch-compatible impl

const tally = new Tally({
  apiKey: process.env.TALLY_API_KEY!,
  fetch: fetch as unknown as typeof globalThis.fetch,
});
```

The SDK doesn't add automatic retries on its own — the client is a thin transport and idempotency is the recommended retry primitive. See [Payments](/sdk/payments) for the `idempotency_key` pattern.

## Request shape

Every SDK call goes through one HTTP request. Headers Tally sends:

| Header          | Value                                    |
| --------------- | ---------------------------------------- |
| `Authorization` | `Bearer <apiKey>`                        |
| `Content-Type`  | `application/json` (when there's a body) |
| `Accept`        | `application/json`                       |

Responses are always JSON. Non-2xx responses are mapped to typed exceptions — see [Errors](/sdk/errors).

## Minimal end-to-end example

The smallest working app: load an env, construct a client, upsert an agent.

```ts theme={null}
import { Tally } from "@tallyforagents/sdk";

async function main() {
  const tally = new Tally({
    apiKey: process.env.TALLY_API_KEY!,
    baseUrl: process.env.TALLY_BASE_URL,
  });

  const agent = await tally.agents.upsert({ id: "smoke-test" });
  console.log(`agent ${agent.id} status=${agent.status}`);
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});
```

Run with `node --env-file=.env.local index.ts` (Node 20+) and you should see `agent smoke-test status=no_permissions`.

## Where to go next

* [Agents](/sdk/agents) — `tally.agents.*`
* [Payments](/sdk/payments) — `tally.payments.*`
* [Webhooks](/sdk/webhooks) — `tally.webhooks.verifySignature`
* [Errors](/sdk/errors) — typed exceptions and the recovery patterns
