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

# TypeScript SDK

> Check planned TypeScript SDK availability and read Threetone agent records with Node.js fetch and response validation.

Read agent records from a server-side TypeScript application using Node.js `fetch`. This example checks your API key, adds a timeout, validates response fields, and supports pagination.

<Note>
  The first-party Threetone TypeScript SDK is planned. No verified installable release has been identified. This example uses built-in Node.js APIs and has no Threetone package installation or import.
</Note>

## Before you start

Use Node.js 24 or later and a personal [API key](/overview/administration/workspaces/api-keys) with permission to read agents. Set `THREETONE_API_KEY` in your server environment. Do not expose it through a public environment variable or browser bundle.

The `.mts` example uses Node.js TypeScript support. You do not need an additional HTTP library to run it.

## Read a page of agents

Save this as `list-agents.mts`. It reads up to 20 agents through [List agents](/api-reference/agents-platform/list-agents).

```typescript list-agents.mts theme={null}
export {};

const apiKey = process.env.THREETONE_API_KEY;
if (!apiKey?.trim()) {
  throw new Error("Set THREETONE_API_KEY in your server environment.");
}

function parseAgentPage(value: unknown) {
  if (
    typeof value !== "object" || value === null ||
    !("agents" in value) || !Array.isArray(value.agents) ||
    !("has_more" in value) || typeof value.has_more !== "boolean"
  ) {
    throw new Error("Invalid agents response.");
  }
  const nextCursor = "next_cursor" in value ? value.next_cursor : null;
  if (nextCursor !== null && typeof nextCursor !== "string") {
    throw new Error("Invalid cursor.");
  }
  if (value.has_more && !nextCursor) {
    throw new Error("Missing next cursor.");
  }
  const agents = value.agents.map((agent: unknown) => {
    if (
      typeof agent !== "object" || agent === null ||
      !("agent_id" in agent) || typeof agent.agent_id !== "string" ||
      !("name" in agent) || typeof agent.name !== "string"
    ) {
      throw new Error("Invalid agent entry.");
    }
    return { agent_id: agent.agent_id, name: agent.name };
  });
  return { agents, has_more: value.has_more, next_cursor: nextCursor };
}

async function listAgents(apiKey: string, cursor?: string) {
  const url = new URL("https://api.threetone.in/v1/convai/agents");
  url.searchParams.set("page_size", "20");
  if (cursor !== undefined) url.searchParams.set("cursor", cursor);

  let response: Response;
  try {
    response = await fetch(url, {
      headers: { "x-api-key": apiKey },
      signal: AbortSignal.timeout(30_000),
      redirect: "error",
    });
  } catch {
    throw new Error(
      "GET /v1/convai/agents failed before a usable response arrived.",
    );
  }

  const requestId = JSON.stringify(
    (response.headers.get("X-Request-Id") ?? "unavailable").slice(0, 128),
  );
  const context =
    `GET /v1/convai/agents status=${response.status} request_id=${requestId}`;
  if (response.status !== 200) throw new Error(context);

  try {
    const value: unknown = await response.json();
    return parseAgentPage(value);
  } catch {
    throw new Error(`Unreadable or invalid agents response; ${context}`);
  }
}

try {
  const page = await listAgents(apiKey);
  for (const agent of page.agents) {
    console.log(agent.agent_id, agent.name);
  }
  console.log("More agents available:", page.has_more);
} catch (error) {
  console.error(error instanceof Error ? error.message : "Agent read failed.");
  process.exitCode = 1;
}
```

Run the file in the environment that contains your key:

```bash theme={null}
node list-agents.mts
```

A successful request prints the ID and name of each returned agent, followed by whether another page is available. An empty list prints no agent rows. The parser validates only the fields this example consumes. TypeScript types alone do not validate JSON received over the network.

The request aborts after 30 seconds. Redirects are disabled to avoid forwarding the API key to another destination.

## Read the next page

When `page.has_more` is true and `page.next_cursor` is a string, pass it to `listAgents(apiKey, page.next_cursor)`. Continue with each newly returned cursor until `has_more` is false. Keep cursor values unchanged.

`page_size` accepts 1 to 100 and defaults to 30 when omitted. The example uses 20. Keep any filters unchanged between pages. Use [Get agent](/api-reference/agents-platform/get-agent) to inspect one agent's complete saved configuration.

## Troubleshoot a request

For `401`, check the key and its expiry. For `403`, check its permissions and workspace access. For `429`, follow `Retry-After` when supplied. Read [Errors and retries](/api-reference/errors) before adding automatic retries.

The error context includes the method, path, status, and a JSON-escaped request ID limited to 128 characters. It excludes the key and response body. A connection failure or timeout may have no response status or request ID.

## Frequently asked questions

<AccordionGroup>
  <Accordion title="Which Threetone npm package should I install?" id="faq-typescript-package">
    No verified first-party package release is documented yet. The SDK is planned. This example runs with Node.js and does not install a Threetone package.
  </Accordion>

  <Accordion title="Can I run this in a React component?" id="faq-typescript-browser">
    Keep this request on your server because it uses a personal API key. Let browser code call your own authenticated server route.
  </Accordion>

  <Accordion title="Does Node.js check the TypeScript types at runtime?" id="faq-typescript-validation">
    No. Node.js removes the supported type syntax when running this file. The explicit response checks validate the fields used by the example. Run your project's TypeScript checker separately.
  </Accordion>
</AccordionGroup>


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