---
title: "Create an intern"
method: POST
path: "/interns"
tags: ["Interns"]
---

# Create an intern

`POST /interns`

Creates an intern in an explicit workspace. The operation also creates its private vault. It can start provisioning immediately or wait for a later provision call. A retry with the same idempotency key and body resumes unfinished work. The request body is capped at 1048576 bytes and a larger body is refused with 413. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.

## Headers

- `Idempotency-Key` string — Key that makes retries resume the same create operation, from 1 through 255 characters. An empty or longer key is refused with 400. Without the header, the server derives a stable key from the request body.

## Request body

- CreateInternRequest — Settings for a new intern.
  - `description` string, nullable — Free-form description, or null.
  - `instructions` string, nullable — Standing instructions the intern boots with, or null.
  - `name` string, required — Intern name, unique per creator within the workspace.
  - `provision` boolean — Start provisioning during this create operation. Defaults to false.
  - `vault_id` string, uuid — Vault owned by another intern in this workspace to attach as a borrowed vault.
  - `workspace_id` string, uuid — Workspace that will own the intern. Defaults to the workspace the API key resolves to. When given, it must match the API key workspace.

## Response `200`

A completed create operation was replayed.

- Intern — Public lifecycle state and settings for one intern.
  - `attached_vault_id` string, nullable, required — Vault the intern borrows from another intern, or null when it borrows none.
  - `created_at` string, required — ISO 8601 creation time.
  - `description` string, nullable, required — Free-form description.
  - `hostname` string, nullable, required — Public hostname the intern is reachable at, or null until provisioning has assigned one.
  - `id` string, required — Intern id.
  - `instructions` string, nullable, required — Standing instructions the intern boots with.
  - `last_failure_message` string, nullable, required — Why the last provisioning attempt failed, when status is failed.
  - `model` string, nullable, required — OpenRouter model slug the intern runs, or null for the workspace default.
  - `name` string, required — Intern name, unique per creator within a workspace.
  - `progress` object, nullable, required — Active provisioning step, or null once provisioning has settled.
    - `step_label` string, required — Human-readable label of the active provisioning step.
    - `step_number` integer, required — One-based index of the active step.
    - `total_steps` integer, required — Number of provisioning steps.
  - `status` 'awaiting_slack_install' | 'queued' | 'provisioning' | 'running' | 'failed' | 'stopped' | 'destroying' | 'destroy_failed', required — Lifecycle status.
  - `updated_at` string, required — ISO 8601 last update time.
  - `vault_id` string, nullable, required — Vault the intern owns, or null before it has been created.
  - `workspace_id` string, required — Workspace that owns the intern and scopes its secrets.

## Other responses

- `201` — Intern created.
- `400` — The request body is invalid.
- `401` — Missing, unknown or provisioning API key.
- `403` — The key acts as an organization and has no member who can own the intern, or regional access is refused.
- `404` — The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled.
- `408` — The request exceeded its route deadline. The deadline quoted in the message is the route's own, so it differs between operations.
- `409` — The idempotency key was reused, the intern name is already taken in the workspace, the member reached the intern limit, or the requested vault cannot be attached.
- `413` — The request body is larger than 1048576 bytes.
- `500` — The request could not be completed. `metadata.reason` says whether to try again: `internal_error` is a transient failure and carries `metadata.retryable: true`, so the same request may be sent again, while `configuration_error` carries `retryable: false` because the next attempt reads the same missing binding or unusable stored credential.
- `502` — The vault or provisioner did not complete a recoverable create step. Retry the same request.

## Changes

- **2026-09-21** `50d23050da7a` — 1 warning, 9 info
  - for the `header` request parameter `Idempotency-Key`, the maxLength was set to `255`
  - added the optional property `error/metadata` to the response with the `400` status
  - added the optional property `error/metadata` to the response with the `401` status
  - added the optional property `error/metadata` to the response with the `403` status
  - …6 more
- **2026-09-19** `e82559908cfc` — 1 info
  - the request property `workspace_id` became optional
- **2026-09-18** `c4cafb1919d1` — 14 breaking, 14 info
  - removed the required property `createdAt` from the response with the `200` status
  - removed the required property `createdAt` from the response with the `201` status
  - removed the required property `lastFailureMessage` from the response with the `200` status
  - removed the required property `lastFailureMessage` from the response with the `201` status
  - …24 more
- **2026-09-17** `c3b9702bd9d7` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/openrouterteam/apis/openrouter-api/changes/interns/post.md)

---

[API](https://skmtc.dev/openrouterteam/apis/openrouter-api.md) · [All operations](https://skmtc.dev/openrouterteam/apis/openrouter-api/llms.txt) · [OpenAPI document](https://skmtc.dev/openrouterteam/apis/openrouter-api/revisions/a14f20a270fd?raw)
