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

# AI quickstart

> Make your first model call crash-safe: add a durable AI step, point it at your provider, and watch its spend, tokens, and latency land in the console.

Turn a model call into a durable step, trigger it, and watch its spend, tokens, and latency roll up
in the console's **AI** view.

<Note>
  This picks up where the [Quickstart](/start/quickstart) leaves off - it assumes you already
  have a project, an API key, and a connected runner. If you don't, start there first.
</Note>

## 1. Add an AI step

[`ctx.step.ai.generate`](/reference/sdk/ai-steps#step-ai-generate) makes a model call a durable step: its
result is recorded once under the step id, so a retry after a crash returns the saved result instead
of calling - and paying for - the model again.

```ts title="runner.ts" theme={null}
import { workflow } from "@duraton/sdk";

export const triageTicket = workflow<{ subject: string }>({
  name: "ticket.created",
  handler: async (ctx) => {
    const { text } = await ctx.step.ai.generate("classify", {
      model: "claude-opus-4-8",
      prompt: `Classify this ticket: ${ctx.event.data.subject}`,
    });
    return { text };
  },
});
```

## 2. Set your provider key

The built-in provider is Anthropic. Your **runner** makes the model call, so the key stays with your
runner - Duraton meters tokens but never sees your key, your prompt, or the response. Set it in the
runner's environment:

```sh theme={null}
export ANTHROPIC_API_KEY="sk-ant-..."
```

<Note>
  Duraton is bring-your-own-keys. Omit `apiKey` on the call and the provider SDK reads its
  conventional env var (`ANTHROPIC_API_KEY`); pass `apiKey` per call to override it. Either way the
  key is used for that one call and is never recorded in the run history.
</Note>

<Note>
  This page is the SDK path - your own runner, your own key. A workflow built without code has no
  runner to hold an env var, so it resolves a key you add once under
  [Credentials](/integrations/credentials) instead - same guarantee, same "used for one call, never
  recorded" rule, different placement.
</Note>

## 3. Trigger it and watch spend land

Send the event your workflow listens for - with the SDK client, or over the
[REST API](/reference/api/events):

<Tabs>
  <Tab title="TypeScript">
    ```ts theme={null}
    import { createClient } from "@duraton/sdk";

    const duraton = createClient({
      url: process.env.DURATON_URL!,
      apiKey: process.env.DURATON_API_KEY,
    });

    await duraton.events.send({
      name: "ticket.created",
      data: { subject: "Refund not received" },
    });
    ```
  </Tab>

  <Tab title="REST API">
    ```sh theme={null}
    curl -X POST "$DURATON_URL/events" \
      -H "Authorization: Bearer $DURATON_API_KEY" \
      -d '{"name":"ticket.created","data":{"subject":"Refund not received"}}'
    ```
  </Tab>
</Tabs>

As the AI step runs, open the **AI** view in the console. Once the first call is recorded it fills
in: total **spend** and **tokens** for the window, **average latency**, **cache hit** rate, and
breakdowns of cost by hour, by model, and by workflow.

## Read it over MCP

An AI agent reading your project sees the same rollup: Duraton exposes the AI spend summary as the
[`ai_spend`](/integrations/mcp-server) MCP tool, so an assistant can pull window totals and the by-model /
by-workflow breakdowns without the console.

## Next steps

<CardGroup cols={2}>
  <Card title="AI steps" href="/reference/sdk/ai-steps">
    generate, wrap, embed, and loop - the full step.ai reference.
  </Card>

  <Card title="AI agents" href="/ai/ai-steps">
    Durable agent loops and the classic patterns, made crash-safe.
  </Card>

  <Card title="Cost controls" href="/ai/cost-controls">
    Cap and throttle model spend per run and per workflow.
  </Card>

  <Card title="AI observability" href="/ai/observability">
    Token and cost rollups, sessions, and traces for every run.
  </Card>
</CardGroup>
