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

# Quickstart

> Define a workflow, run it in your own worker and start it with an event.

You define workflows in your own code and run them in a worker you host. The
worker connects to your project and runs each step; your project keeps every
run's state, so a run survives a worker restart.

You need a project with Workflows on, a worker key (`dtn_wk_`) for the worker
and a secret key (`dtn_sk_`) to send events.

## 1. Install the SDK

```sh theme={null}
npm install @duraton/sdk
```

## 2. Define a workflow

A workflow is a handler made of named steps. A step that finished is never run
again: after a restart the run carries on from the next one.

```ts theme={null}
import { defineWorkflow } from "@duraton/sdk";

export const welcome = defineWorkflow<{ email: string }>({
  name: "welcome-email",
  triggers: [{ event: "user/signed-up" }],
  handler: async ({ event, step }) => {
    await step.run("send-welcome", () => ({ to: event.data.email }));
    await step.sleep("wait-a-day", "1d");
    await step.run("send-tips", () => ({ to: event.data.email }));
  },
});
```

Two more steps cover a stage you leave out and a resource you wait on:

| Step | What it does |
| - | - |
| `step.skip(id, reason?)` | Records the step as `skipped`, with the reason, without running anything |
| `step.poll(id, probe, { every, timeout, until? })` | Runs `probe` as a step every `every` until it returns a value that is not `null` or `undefined` and that `until` (when given) accepts, then returns it. Each check is a step `<id>:probe:<n>` and each wait between checks a step `<id>:gap:<n>`. With no ready value within `timeout` it throws `PollTimeoutError`, a `NonRetriableError` |

## 3. Connect a worker

```ts theme={null}
import { connect } from "@duraton/sdk";
import { welcome } from "./workflows";

const worker = connect({
  url: "https://<slug>.<project-domain>/workflows/v1",
  apiKey: process.env.DURATON_WORKER_KEY ?? "",
  app: "shop",
  workflows: [welcome],
});

await worker.ready;
process.on("SIGTERM", () => worker.close());
```

`ready` settles once your project has the worker's workflows. `close()` stops
taking new steps and lets the ones in flight finish. See
[Workers](https://docs.duraton.dev/workflows/workers.md) for builds, reconnects and concurrency.

## 4. Send an event

```ts theme={null}
import { createClient } from "@duraton/sdk/client";

const client = createClient({
  url: "https://<slug>.<project-domain>/workflows/v1",
  apiKey: "dtn_sk_...",
});

const result = await client.events.send({
  name: "user/signed-up",
  data: { email: "ana@example.test" },
});
```

Every workflow the event triggers starts a run. Follow it with
`client.runs.list({ workflow: "welcome-email" })` or live, as the
[reference](https://docs.duraton.dev/workflows/rest-reference.md#following-runs-live) shows.

## Next

* [Events](https://docs.duraton.dev/workflows/events.md): names, platform events and delivery.
* [Schedules](https://docs.duraton.dev/workflows/schedules.md): start a workflow on a cron expression.
* [Wait tokens](https://docs.duraton.dev/workflows/wait-tokens.md): pause a run until someone answers.
* [Limits](https://docs.duraton.dev/workflows/limits.md): what a project may run at once.
* [MCP tools](https://docs.duraton.dev/workflows/mcp-tools.md): manage workflows from an AI assistant.


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