> For AI assistants: read [llms.txt](https://docs.saturation.io/llms.txt) first for the complete documentation map, API contract, and endpoint Markdown files.

# Quickstart (HTTP)

Authenticate, confirm the token's workspace, read budget totals, and page transactions with `fetch`.

## Setup

Create a personal token in **Settings > Developers > API**, then set it in your shell:

```bash
export SATURATION_TOKEN="<token>"
```

Point the client at the base URL:

```ts
const baseURL = 'https://next-api.saturation.io/v1';
const token = process.env.SATURATION_TOKEN;
if (!token) throw new Error('SATURATION_TOKEN is required');
```

## Request helper

`2xx` returns the item or page. Other responses use the format in [Errors](/errors.md).

```ts
async function apiJson<T>(path: string, init: RequestInit = {}): Promise<T> {
  const response = await fetch(`${baseURL}${path}`, {
    ...init,
    headers: {
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/json',
      ...init.headers,
    },
  });

  const body = await response.json() as { code?: string; message?: string; requestId?: string } & T;
  if (!response.ok) {
    throw new Error(`${body.code}: ${body.message} (${body.requestId})`);
  }
  return body;
}
```

## Confirm the token

`GET /me` returns the token's identity and workspace ([Concepts](/concepts.md)).

```ts
type Me = {
  id: string;
  type: 'user' | 'service';
  email?: string;
  workspaces: Array<{ workspaceId: string; workspaceRole: string }>;
};

const me = await apiJson<Me>('/me');
console.log(me.email, me.workspaces[0]?.workspaceId, me.workspaces[0]?.workspaceRole);
```

## Read budget totals

Project paths start at `/projects/{projectId}`. Use the permanent ID or the project's short name.

```ts
type BudgetTotals = {
  computedAt: string;
  totals: Record<string, { amount: number; currency: string }>;
};

const totals = await apiJson<BudgetTotals>('/projects/prj_a1/budget/totals');
for (const [phaseId, value] of Object.entries(totals.totals)) {
  console.log(phaseId, value.amount, value.currency, totals.computedAt);
}
```

## Page transactions

List responses return `data` and may return `nextCursor`. Pass it back as `cursor` until it is absent or `null` ([Pagination](/pagination.md)).

```ts
type Page<T> = { data: T[]; nextCursor?: string | null };
type Transaction = { id: string; amount: { amount: number; currency: string } };

let cursor: string | null = null;
do {
  const qs = new URLSearchParams({ limit: '100', source: 'manual' });
  if (cursor) qs.set('cursor', cursor);

  const page = await apiJson<Page<Transaction>>(
    `/transactions?projectId=prj_a1&${qs.toString()}`,
  );
  for (const txn of page.data) {
    console.log(txn.id, txn.amount.amount, txn.amount.currency);
  }
  cursor = page.nextCursor ?? null;
} while (cursor);
```

## Next

- [Guides](/guides.md): apply a rate pack, add an incentive, handle errors, and subscribe to webhooks.
- [API Reference](/api-reference.md): every endpoint, request, and response schema.
- [API Reference](/api-reference.md): generated schemas and operation definitions.
