# Create a workflow (/en/docs/api/native/automation/createWorkflow)





Save a YAML workflow as an editable draft without publishing or starting a run. Choose your own namespace without registering it first; praxis is read-only. To test the draft, send its source and language=yaml to praxis.automation.runs.create. Scripts and workflows share names within the tenant; a duplicate returns NAME_TAKEN. run.workflow accepts ns/name@range or {namespace, name, version, input}; run.script uses the same reference shape as a platform extension. Object namespace, name and version are required; version accepts an exact version, dist-tag or range, locked at publication. Object input defaults to {} and supports expressions; string references retain task-level with. run.await defaults to true and returns the child output. With false, the child uses detach and the task immediately returns {run_id}; parent cancellation does not cascade. Inline script.code returns DEFINITION_INVALID with a detail asking you to save a script and reference it first. raise.error retains its type URI, status, title and detail in the run error.

`POST /automation/v1/workflows`

## Authentication [#authentication]

`Authorization: Bearer $PRAXIS_API_KEY`

## Request fields [#request-fields]

| Parameter | Type | Description |
| --- | --- | --- |
| header: Idempotency-Key | `string` | optional; Optional; 1–256 characters. Within 24 hours, the same key replays the first response with Idempotent-Replayed: true; a different request body returns 422; an in-flight request returns 409. minLength: 1; maxLength: 256 |

### application/json [#applicationjson]

no additional fields.

| Field | Type | Description |
| --- | --- | --- |
| namespace | `string` | required; Choose a namespace without prior registration; praxis is read-only. Folded to lowercase; matches [a-z0-9][a-z0-9._-]&#123;0,63&#125;. pattern: "^[a-zA-Z0-9][a-zA-Z0-9._-]&#123;0,63&#125;$" |
| name | `string` | required; Name, folded to lowercase; matches [a-z0-9][a-z0-9._-]&#123;0,63&#125;. pattern: "^[a-zA-Z0-9][a-zA-Z0-9._-]&#123;0,63&#125;$" |
| description | `string` | optional; Description, at most 1,000 characters. maxLength: 1000 |
| draft | `string` | optional; Editable source: TypeScript for scripts, YAML for workflows. Defaults to an empty string on creation. |
| labels | `object` | optional; At most 50 labels; keys contain 1–40 characters and values at most 500 characters. |

## Examples [#examples]

[SDK installation and example environment](/en/docs/api/native/automation)

```bash
curl --fail-with-body -X POST "https://api.deepraxis.ai/automation/v1/workflows" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "namespace": "docs-samples",
  "name": "sample-workflows",
  "draft": "document:\n  dsl: '\''1.0.3'\''\n  namespace: docs-samples\n  name: sample-workflows\n  version: '\''1.0.0'\''\ndo:\n  - answer:\n      set:\n        answer: 42\n"
}'
```

```typescript
import { createAutomationClient } from '@deepraxis/sdk/automation';

function env(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Set ${name}`);
  return value;
}
const automation = createAutomationClient({
  apiKey: env('PRAXIS_API_KEY'),
  baseUrl: 'https://api.deepraxis.ai',
  maxRetries: 0,
  timeoutMs: 90_000,
});
const result = await automation.workflows.create({
  "body": {
    "namespace": "docs-samples",
    "name": "sample-workflows",
    "draft": "document:\n  dsl: '1.0.3'\n  namespace: docs-samples\n  name: sample-workflows\n  version: '1.0.0'\ndo:\n  - answer:\n      set:\n        answer: 42\n"
  }
});
console.log(result);
```

## Response [#response]

### HTTP 200 [#http-200]

Success

| Header | Type | Description |
| --- | --- | --- |
| Idempotent-Replayed | `boolean` | Present and true when replaying the first response for this key. |

`application/json`

| Field | Type | Description |
| --- | --- | --- |
| draft | `object` | required; The editable draft of a script or workflow; publishing takes the draft or a run's source. no additional fields. |
| draft.source | `string` | required; Draft source: TypeScript for scripts, YAML for workflows. |
| draft.revision | `string` | required; Draft revision tag (ETag); send it as expected_draft_revision when publishing or as If-Match when updating the draft; a mismatch returns 412. |
| draft.updated_at | `string` | required; Time the draft was last changed (RFC 3339 UTC). |
| draft.updated_by | `object` | required; Principal &#123;type, id&#125; injected by the gateway that says who initiated or acted. This service does not resolve names; the console resolves them in batches. no additional fields. |
| draft.updated_by.type | `"user"` / `"api_key"` / `"agent"` / `"run"` / `"trigger"` | required; Principal type. user is a signed-in user; api_key is a platform API key; agent is an agent; run is an action performed by a run itself (for example a parent run); trigger is a trigger. |
| draft.updated_by.id | `string` | required; Principal identifier whose meaning follows type: a user, API key, agent, run or trigger id. Treat it as an opaque string. |
| id | `string` | required; Definition id, prefixed scr_ for scripts and wf_ for workflows; calls normally use namespace and name. |
| kind | `"script"` / `"workflow"` | required; Orchestration kind. script is a TypeScript script that executes once; workflow is a YAML workflow made of steps that can wait for events, timers or child runs and can be suspended. |
| namespace | `string` | required; Namespace; references take the form namespace/name@version. |
| name | `string` | required; Name; with namespace it is unique within the tenant, and scripts and workflows share one namespace (duplicates return 409 NAME_TAKEN). |
| description | `string` | required; Free-text description, at most 1000 characters. |
| labels | `object` | required; User-defined string key and value tags for grouping and list filtering (labels[key]=value); keys must not start with praxis. |
| owner | `string` | required; Tenant that owns the definition, injected by the gateway; treat it as an opaque string. |
| latest_version | `null` / `object` | required; The published version the latest tag points to, as &#123;version, published_at&#125;; null if nothing is published. |
| latest_version (variant 2).version | `string` | required; Version number (semver) of the latest published version. |
| latest_version (variant 2).published_at | `string` | required; Time that version was published (RFC 3339 UTC). |
| dist_tags | `object` | required; Map from dist-tag to the exact version it points to, for example latest to 1.2.0; ns/name@tag resolves through it. |
| draft_changed | `boolean` | required; true when the draft content (digest) differs from the latest version, meaning there are unpublished changes. |
| latest_run | `null` / `object` | required; Summary of the most recent run of this definition, or null if it has never run. |
| latest_run (variant 2).id | `string` | required; Run id (run_ prefix); pass it to runs.retrieve. |
| latest_run (variant 2).number | `null` / `number` | required; Increasing sequence number of the run within its script or workflow. |
| latest_run (variant 2).status | `"running"` / `"completed"` / `"faulted"` / `"cancelled"` / `"pending"` / `"waiting"` / `"suspended"` | required; Run status. pending is created but not started; running is executing; waiting means a workflow is waiting on an event, timer or child run; suspended means a workflow was suspended; cancelled was cancelled; faulted failed; completed finished successfully. |
| latest_run (variant 2).created_at | `string` | required; Time the run was created (RFC 3339 UTC). |
| latest_run (variant 2).current_wait | `null` / `object` | required; The wait point currently open, or null when the run is not waiting. |
| latest_run (variant 2).current_wait (variant 2).id | `string` | required; Wait point id, prefixed wait_; use it as wait_id when completing an event wait. |
| latest_run (variant 2).current_wait (variant 2).run_id | `string` | required; Id (run_) of the run this wait belongs to. |
| latest_run (variant 2).current_wait (variant 2).kind | `"event"` / `"timer"` / `"child"` | required; Wait kind. event waits for an external event that can be submitted with runs.completeWait; timer waits until resume_at; child waits for a child run to finish. |
| latest_run (variant 2).current_wait (variant 2).state | `"cancelled"` / `"open"` / `"resolved"` / `"expired"` | required; Wait point state. open is still waiting; resolved was satisfied; expired passed its expires_at; cancelled was cancelled and can no longer be satisfied. |
| latest_run (variant 2).current_wait (variant 2).task | `null` / `object` | required; The workflow step &#123;reference, name&#125; that produced the wait; null when there is no such step. |
| latest_run (variant 2).current_wait (variant 2).task (variant 2).reference | `string` | required; JSON Pointer of the step, for example /do/2/wait_payment. |
| latest_run (variant 2).current_wait (variant 2).task (variant 2).name | `string` | required; Step name, the key in the workflow YAML. |
| latest_run (variant 2).current_wait (variant 2).resume_at | `null` / `string` | required; For kind=timer, the instant the run resumes (RFC 3339 UTC); null for other kinds. |
| latest_run (variant 2).current_wait (variant 2).event_type | `null` / `string` | required; For kind=event, the event type being awaited; null for other kinds. |
| latest_run (variant 2).current_wait (variant 2).child_run_id | `null` / `string` | required; For kind=child, the id of the child run being awaited; null for other kinds. |
| latest_run (variant 2).current_wait (variant 2).created_at | `string` | required; Time the wait point was created (RFC 3339 UTC). |
| latest_run (variant 2).current_wait (variant 2).expires_at | `null` / `string` | required; Time the wait point expires (RFC 3339 UTC), or null if it has no deadline. |
| latest_run (variant 2).current_wait (variant 2).resolved_at | `null` / `string` | required; Time the wait point was resolved (RFC 3339 UTC), or null if still open. |
| stats_7d | `object` | required; Run statistics for the last seven days, bucketed by the day each run ended and updated when runs finish. no additional fields. |
| stats_7d.runs | `number` | required; Number of runs that ended in the last seven days, in any terminal status. |
| stats_7d.failures | `number` | required; How many of those runs ended faulted. |
| archived_at | `null` / `string` | required; Archive time, or null while not archived. An archived name stays reserved and cannot be reused. |
| created_at | `string` | required; Creation time (RFC 3339 UTC). |
| updated_at | `string` | required; Time of the last update (RFC 3339 UTC). |

### Measured response [#measured-response]

HTTP 200

```json
{
  "id": "wf_00mv67m4jad0d5c2a3d1e04dc9ac4c18cff616eca7",
  "owner": "tnt_3a9759864ccb4e00",
  "kind": "workflow",
  "namespace": "docs-samples",
  "name": "sample-workflows-1791867412840-b05e8a",
  "description": "",
  "labels": {},
  "latest_version": null,
  "dist_tags": {},
  "draft_changed": true,
  "latest_run": null,
  "stats_7d": {
    "runs": 0,
    "failures": 0
  },
  "archived_at": null,
  "created_at": "2026-10-13T04:57:29.206Z",
  "updated_at": "2026-10-13T04:57:29.206Z",
  "draft": {
    "source": "document:\n  dsl: '1.0.3'\n  namespace: docs-samples\n  name: sample-workflows-1791867412840-b05e8a\n  version: '1.0.0'\ndo:\n  - answer:\n      set:\n        answer: 42\n",
    "revision": "draft_00mv67m4ja0e38625d463646e3a526bb774bf453ee",
    "updated_at": "2026-10-13T04:57:29.206Z",
    "updated_by": {
      "type": "api_key",
      "id": "key_3e00b8984967"
    }
  }
}
```

## Errors [#errors]

| HTTP | Codes and description |
| --- | --- |
| 400 | INVALID_PARAMS: Invalid request parameters, path, cursor, or body format. |
| 403 | NAMESPACE_FORBIDDEN: The namespace is read-only, or the run token does not permit this call. |
| 409 | IDEMPOTENCY_IN_FLIGHT: A request with the same idempotency key is still in progress. NAME_TAKEN: The name is already used by this tenant. |
| 422 | IDEMPOTENCY_KEY_MISMATCH: The idempotency key was already used for different request content. |
| default | RFC 9457 automation problem. 429 includes Retry-After. |

[Authentication and common errors](/en/docs/api/errors) · Retain the `X-Request-Id` response header for troubleshooting.
