---
title: 'REST API: Deploy'
path: reference/rest-api/deploy
status: published
---

# REST API: Deploy

The canonical deploy endpoint lives under [Flows](./flows#post-v1flowsflow_iddeploy) — `POST /v1/flows/{flow_id}/deploy`. This page covers the legacy and supporting paths.

## `POST /v1/dev/deploy` (deprecated)

Legacy M1 deploy path. Single-shot — compiles + POSTs to ScaiGrid without persisting the flow first.

**Auth:** shared bearer token via `SCAIFLOW_API_TOKEN` env (NOT ScaiKey). Set the env var on the backend; clients send `Authorization: Bearer <token>`.

**Body:**

```jsonc
{
  "content": { /* full FlowGraph JSON */ },
  "publish_as_model": false       // optional override
}
```

**Response:**

```jsonc
{
  "core_id": "core_xxx",
  "published_slug": null
}
```

**Deprecated.** Kept until the canvas's auth-mode-switching code path fully transitions to ScaiKey. New code should use `POST /v1/flows/{flow_id}/deploy` after saving the flow via `POST /v1/flows`.

## The full deploy flow (canonical, via flows)

For completeness:

1. `POST /v1/flows` — create the flow row in the backend.
2. `POST /v1/flows/{id}/deploy` — compile + deploy.

The canonical deploy endpoint does:

1. Reads the flow from object storage.
2. Pre-deploy ScaiQueue provisioning (if `flow.config.scaiqueue` is set) — calls `ensure_scope` + `ensure_queue` on ScaiQueue. Idempotent (find-or-create, tolerates 409 races). Aborts the deploy on failure (502 before the ScaiGrid create call).
3. Compiles to YAML.
4. `POST /v1/modules/scaicore/cores` on ScaiGrid with the YAML body.
5. If `publish_as_model` is true (from body override or flow config), `POST /v1/modules/scaicore/cores/{id}/publish` with `group_ids`.
6. Persists a deployment record (visible via `GET /v1/flows/{id}/deployments`).

The deploy auth flow:

1. If caller has a JWT and `SCAIFLOW_DEPLOY_AUTH != "api_key"` — forward their JWT to ScaiGrid.
2. Else look up the tenant's API key from ScaiVault.
3. Else fall back to `SCAIGRID_API_KEY` env (dev only).
4. Else return 412 `missing_scaigrid_credentials`.

## Error matrix

| Status | Detail.error | Cause |
|---|---|---|
| **400** | `compile_error` | Flow doesn't compile. Detail has compile messages. |
| **412** | `missing_scaigrid_credentials` | No JWT, no tenant API key. Tenant admin should `POST /v1/tenants/me/scaigrid_credentials`. |
| **502** | `scaiqueue_auth` | Tenant lacks `scaiqueue:view`/`:manage` for pre-deploy provisioning. |
| **502** | `scaiqueue_provision_failed` | Provisioning failed for non-auth reasons (network, scope conflict). |
| **502** | `scaicore_create_failed` | ScaiGrid rejected the manifest (verifier error, quota, etc.). |
| **502** | `scaicore_publish_failed` | Core was created but the publish step failed. The Core is still deployed. |
