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

# TypeScript client

> Use the project-scoped DevTune client to read Actions, citation coverage, AI Traffic and Results, or launch an explicitly intended managed-agent task.

`@devtune/client` provides typed methods for every operation in the public API.
It uses fetch and has no runtime dependencies. Use ESM in Node 20+ or a modern
fetch-capable runtime. Keep project API keys in server-side environment variables.

<Note>
  Installation from npm will be available after release. Publication has not
  been verified. The installation command below applies after the package is
  published.
</Note>

```sh theme={null}
npm install @devtune/client
```

## Project configuration

Create a project API key in **API Keys** in the account sidebar. Select the scopes
your integration needs, then set `DEVTUNE_API_KEY` and `DEVTUNE_PROJECT_ID` in your
environment. The key must belong to that project. See [authentication](/api-reference/authentication).

```ts theme={null}
import { createClient } from '@devtune/client';

const apiKey = process.env.DEVTUNE_API_KEY;
const projectId = process.env.DEVTUNE_PROJECT_ID;
if (!apiKey || !projectId)
  throw new Error('Set DEVTUNE_API_KEY and DEVTUNE_PROJECT_ID');
const client = createClient({ apiKey, projectId });

const report = await client.listActions({
  query: { detailLevel: 'context', page: 1, pageSize: 100 },
});
console.log(report);
```

The client binds `projectId` once. Method names match the public API's operation
names. Pass other resource identifiers in `path`, filters in `query` and JSON in
`body`. Responses retain their envelope, metadata and nullable fields.

An unspecified success schema returns `unknown`, so narrow the value before using
it. Explicitly bodyless successes return `void`, including HTTP 204/205 or an
explicitly empty content map. The client accepts an empty body when the response
is bodyless or unspecified. Declared JSON content requires nonempty valid JSON.

```ts theme={null}
const run = await client.getManagedAgentRun({ path: { runId: 'RUN_UUID' } });
console.log(run.data.status);
```

Exported types include `ProjectClient`, `OperationId`, `OperationInput<'listActions'>`,
`OperationResponse<'listActions'>` and the generated OpenAPI `operations`, `paths`
and `components`. Types preserve the API's required and optional fields. UUIDs,
numeric ranges and cross-field constraints are validated by the API.

## Metrics and coverage

```ts theme={null}
const [citations, traffic] = await Promise.all([
  client.getCitationStats({ query: { windowDays: 30 } }),
  client.getTrafficSummary({ query: { windowDays: 30 } }),
]);
console.log(JSON.stringify({ citations, traffic }, null, 2));
```

Use the operation's supported fixed windows and the returned window dates.
Citation stats with `coverage.status === 'unavailable'` and `stats === null` mean
the window has no measurement yet. Keep that state distinct from a measured zero.
AI Traffic returns project-wide sensor state alongside traffic totals. Domain and
path filters narrow totals, not sensor state. `no_recent_traffic` means a healthy
sensor was quiet; `inactive` needs attention. The browser snippet does not establish
server-side answer fetch or 404 coverage.

## Managed-agent runs

Launching an agent can spend credits. Use `triggerManagedAgentRun` only for an
explicitly intended task with the required `agents.run` scope, available evidence
and credits, and a key creator who belongs to the project with manage permission.
Reading status also requires `agents.read`.

Save a UUID with the intended request before launching, and supply it as
`requestIdempotencyKey`. Reuse that same key with the same agent and inputs if you
explicitly retry after a lost response. A new key can start another charged run.
The client never retries launches automatically.

The packaged `recipes/managed-agent.ts` requires these environment inputs:

* `DEVTUNE_API_KEY` and `DEVTUNE_PROJECT_ID`
* `DEVTUNE_APPROVED_METERED_RUN=true`, acknowledging the intended metered task
* `DEVTUNE_AGENT_KEY` and `DEVTUNE_AGENT_INSTRUCTIONS`
* `DEVTUNE_RUN_IDEMPOTENCY_KEY`, the saved request UUID

It launches once, prints the task ID and waits at most 20 polls within two minutes.
If waiting ends, resume `getManagedAgentRun` with that task ID. Cancelling the
request does not cancel the server run. Completed drafts still need human approval
before publishing.

## Shipped Action Results

```ts theme={null}
const interventionId = process.env.DEVTUNE_INTERVENTION_ID;
if (!interventionId)
  throw new Error('Set an existing measured action intervention ID');
const results = await client.listOutcomesLedger({
  query: { windowDays: 90, interventionId, pageSize: 100 },
});
console.log(JSON.stringify(results, null, 2));
```

Get an existing measurement's `interventionId` from `listOutcomesLedger`.
The API keeps its `/outcomes/` path and operation name for compatibility.
Results compare observed before/after windows. They show what moved, not what
caused it. Preserve evidence quality, null deltas, `still_measuring` and `unmeasured`
states. Missing conversion measurements are null, not zero.

## Pagination

Actions use `page` and `pageSize` with returned `totalPages`. Managed-agent runs and
Results use `pagination.hasMore` and `pagination.nextCursor`. Keep filters unchanged
when continuing. Action edits return `hasMore` and `nextCursor` directly inside
`data`. Analytics search rollups require their returned generation with subsequent
offsets. Bound loops and stop if continuation metadata is missing or inconsistent.

`listVisibilityResponses` returns only the latest 20 successful executions and has
no cursor. It cannot retrieve complete history and is not a sample for calculating
visibility rates. Use the measurement summary operations for those rates.

## Timeouts and errors

The default timeout is 30 seconds for the entire call, including retries, waits and
response body reading. Configure `timeoutMs` on the client or a call, up to five
minutes, and pass `signal` for cancellation.

```ts theme={null}
import { DevTuneHttpError } from '@devtune/client';

try {
  await client.getProjectUsage(undefined, {
    signal: AbortSignal.timeout(5000),
  });
} catch (error) {
  if (error instanceof DevTuneHttpError) {
    console.error(error.status, error.body?.error, error.retryAfterMs);
  } else {
    throw error;
  }
}
```

GET requests retry network failures and HTTP 408, 429, 500, 502, 503 and 504 up to
twice. Set `maxRetries` from 0 to 5 to change the read budget. The client respects
`Retry-After` seconds or HTTP dates, falling back to `X-RateLimit-Reset` Unix seconds.
A required wait beyond the remaining budget returns the HTTP error immediately.
POST, PATCH, PUT and DELETE are never retried automatically.

`DevTuneHttpError` includes status, operation ID, attempts, sanitized documented error
fields, retry timing and rate limits. `DevTuneNetworkError` reports connection
failure, `DevTuneAbortError` reports cancellation or timeout, and
`DevTuneProtocolError` reports malformed success JSON or a success response that
contradicts its documented status/body contract. The client never logs
credentials or retains raw request headers or network causes. A timeout after a
write may mean the server accepted it; inspect state before deciding to retry.

For compatible environments and tests, configure `baseUrl`, including the API root
such as `/api/v2`, and a custom `fetch` implementation. Redirects are refused.

## Runnable recipes

The package includes `actions-report.ts`, `metrics.ts`, `managed-agent.ts` and
`action-results.ts` with a shared `environment.ts` in its `recipes/` directory.
Copy the directory into an ESM project with the client installed. Set the required
environment variables, then run:

```sh theme={null}
npx tsx recipes/metrics.ts
```

The Actions report reads at most 10 pages and reports when that bound prevents a
complete report. The Results recipe reads an existing intervention; it does not
ship or mark an action live. Read recipes call the API when run. The managed-agent
recipe can spend credits when its explicit metered-task input is set.


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