# Create a workflow

> Compose a recurring workflow from a schedule in plain words and a list of steps.

Canonical: https://revnu.com/docs/workflow-create
Last updated: 2026-10-18

```bash
curl -X POST -H "Authorization: Bearer $REVNU_API_TOKEN" \
  -H "content-type: application/json" \
  -d '{"name":"EU HPC daily","scheduleText":"every weekday at 09:00 Europe/London","steps":[{"title":"Find five leads","details":["EU operators of owned GPU or HPC capacity","Five per day, skip anything on the block list"]},{"title":"Draft and deliver","details":["One LinkedIn draft per lead, sourced hook, no pitch"]}],"deliverTo":"web"}' \
  https://revnu.com/api/v1/workflows
```

## Body

`name` (up to 120 characters), `scheduleText` (plain words, up to 200 characters; name a time zone such as `America/New_York`, `ET` or `UTC` to run on that clock, otherwise the account's zone is used, and `scheduleEcho` in the response names the zone it resolved to), `steps` (1 to 25). A step is `{ title, details?, gate?, id? }`: `title` is up to 1000 characters, `details` is up to 8 lines of up to 1000 characters each, and `gate: { on: true, label? }` means the step waits for a human ok before it acts. Optional `description` (240 characters) and `deliverTo`, one of the account's connected destinations. Unknown fields or a broken limit are a `400` whose body names the problem, e.g. `{ "error": "steps[2].details lines are at most 1000 characters" }`. The whole workflow also has to fit in one run, about 6,500 characters of steps in total; past that the `400` says how far over it is.

## Response

`{ "workflow": { workflowId, status, version, scheduleText, scheduleEcho, scheduleError, nextRunAt, steps, url, … } }`, status `201`. The workflow is live. The schedule resolves after the write: read it back for `scheduleEcho` and `nextRunAt`, or `scheduleError` when the words could not be understood.

## Frequently asked questions

### Where does daily volume go?

In a step's `details`, as words: "five per day". Revnu reads it on every run and aims for it, but it is a target, not a ceiling the API enforces. There is no numeric volume, budget or end-date field. Sending limits on each inbox and LinkedIn account still apply.

### Which scope does this need?

`workflows:write`. A token without it gets `403` with `requiredScope` in the body. `GET /me` shows a token's scopes.

### Are responses cached?

No. Every response is `Cache-Control: no-store`, so what you read is current.
