Skip to Content
Legacy PlatformReferenceAPI Reference

API Reference

The Iron.sh REST API lets you manage sandboxes, agents, environment variables, egress rules, and audit logs programmatically.

Base URL: https://api.iron.sh

Authentication: Pass your API key in the Authorization header:

Authorization: Bearer <api_key>

All responses use JSON. All timestamps are ISO 8601 UTC.


Conventions

Resource IDs

All resources use prefixed, opaque IDs:

ResourcePrefixExample
VMvm_vm_k3mf9xvw2p
Egress Ruleegr_egr_9xm2kfp4
Egress Eventee_ee_w8n3vqx1
Secretsec_sec_m4xk9wp2
Snapshotsnap_snap_abc123
Agentagt_agt_x9k2mf4p
Env Variableenv_env_m4xk9wp2
Userusr_usr_w3n8vqx1
API Keykey_key_p4t7xm2k

Pagination

All list endpoints return a consistent envelope:

{ "data": [], "has_more": false, "cursor": null }

When has_more is true, pass the returned cursor as a query parameter on the next request to fetch the next page.

Errors

Error responses include a machine-readable code and a human-readable message:

{ "error": { "code": "vm_not_found", "message": "No VM with ID vm_k3mf9xvw2p" } }
HTTP StatusMeaning
400Bad request / validation error
401Missing or invalid API key
404Resource not found
409Conflict (e.g. VM already running)
422Unprocessable entity
429Rate limited
500Internal server error

VMs

VM Status

The API exposes simplified statuses derived from internal VM states. The status field is stable and safe to branch on. The status_detail field exposes the internal state for debugging and observability.

statusstatus_detail valuesDescription
pendingqueued, creating, startingVM is being provisioned
runningrunning, readyVM is up and accepting connections
stoppedstopping, stoppedVM is shut down
destroyeddestroying, destroyedVM has been terminated
failedfailedVM encountered an error

Create a VM

POST /v1/vms

Request body:

FieldTypeRequiredDescription
namestringyesHuman-readable name. Must be unique among non-destroyed VMs within the account. Can be reused once the previous VM with that name is destroyed.
public_keystringyesSSH public key for access.
snapshot_idstringnoSnapshot ID to restore from. The VM will boot from this snapshot instead of the default base image.
curl -X POST https://api.iron.sh/v1/vms \ -H "Authorization: Bearer $IRONS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "my-dev-env", "public_key": "ssh-ed25519 AAAA..." }'

Response: 201 Created

{ "id": "vm_k3mf9xvw2p", "name": "my-dev-env", "status": "pending", "status_detail": "creating", "created_at": "2026-02-28T12:00:00Z", "updated_at": "2026-02-28T12:00:00Z" }

Once the VM is created, you can retrieve its details using the GET /v1/vms/{id} endpoint. You will need to poll that endpoint until the status is running and the status_detail is ready prior to connecting via SSH.


List VMs

GET /v1/vms

Query parameters:

ParamTypeDefaultDescription
statusstringFilter by simplified status: pending, running, stopped, destroyed, failed
status_detailstringFilter by internal status: queued, creating, starting, running, ready, stopping, stopped, destroying, destroyed, failed
namestringFilter by exact name match
cursorstringPagination cursor from previous response
limitinteger20Results per page. Max 100.
sortstringcreated_atSort field: created_at, updated_at, name
orderstringdescSort order: asc, desc
curl https://api.iron.sh/v1/vms?status=running&limit=10 \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

{ "data": [ { "id": "vm_k3mf9xvw2p", "name": "my-dev-env", "status": "running", "status_detail": "ready", "created_at": "2026-02-28T12:00:00Z", "updated_at": "2026-02-28T12:01:00Z" } ], "has_more": false, "cursor": null }

Get a VM

GET /v1/vms/{vm_id}
curl https://api.iron.sh/v1/vms/vm_k3mf9xvw2p \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

{ "id": "vm_k3mf9xvw2p", "name": "my-dev-env", "status": "running", "status_detail": "ready", "created_at": "2026-02-28T12:00:00Z", "updated_at": "2026-02-28T12:01:00Z" }

Destroy a VM

DELETE /v1/vms/{vm_id}
curl -X DELETE https://api.iron.sh/v1/vms/vm_k3mf9xvw2p \ -H "Authorization: Bearer $IRONS_API_KEY"

The VM must be stopped before it can be destroyed. Returns 409 Conflict if the VM is still running:

{ "error": { "code": "vm_not_stopped", "message": "VM must be stopped before it can be destroyed" } }

Response: 204 No Content


Start a VM

POST /v1/vms/{vm_id}/start
curl -X POST https://api.iron.sh/v1/vms/vm_k3mf9xvw2p/start \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

Returns the full VM object with status: "running".


Stop a VM

POST /v1/vms/{vm_id}/stop
curl -X POST https://api.iron.sh/v1/vms/vm_k3mf9xvw2p/stop \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

Returns the full VM object with status: "stopped".


Get SSH Connection Info

GET /v1/vms/{vm_id}/ssh
curl https://api.iron.sh/v1/vms/vm_k3mf9xvw2p/ssh \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

{ "host": "203.0.113.10", "port": 2222, "username": "root", "command": "ssh -p 2222 root@203.0.113.10" }

Egress Policy (Account-Level)

Account-level egress settings apply to all VMs unless overridden at the VM level.

Get Default Policy

GET /v1/egress/policy
curl https://api.iron.sh/v1/egress/policy \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

{ "mode": "enforce" }
ModeBehavior
enforceBlock all egress traffic except to hosts/CIDRs in the allowlist.
warnAllow all traffic but log requests to non-allowlisted destinations.

Update Default Policy

PUT /v1/egress/policy

Request body:

FieldTypeRequiredDescription
modestringyesenforce or warn
curl -X PUT https://api.iron.sh/v1/egress/policy \ -H "Authorization: Bearer $IRONS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"mode": "enforce"}'

Response: 200 OK

Returns the updated policy object.


List Default Egress Rules

GET /v1/egress/rules
curl https://api.iron.sh/v1/egress/rules \ -H "Authorization: Bearer $IRONS_API_KEY"

Query parameters:

ParamTypeDefaultDescription
hoststringFilter by exact host match
cidrstringFilter by exact CIDR match
namestringFilter by exact name match
cursorstringPagination cursor
limitinteger50Results per page. Max 200.
sortstringcreated_atSort field: created_at, host
orderstringdescSort order: asc, desc

Response: 200 OK

{ "data": [ { "id": "egr_9xm2kfp4", "name": "github-api", "host": "api.github.com", "cidr": null, "comment": "GitHub API access for code pulls", "created_at": "2026-02-28T12:00:00Z" }, { "id": "egr_t4wn8xk2", "name": "internal-network", "host": null, "cidr": "10.0.0.0/8", "comment": "Internal network access", "created_at": "2026-02-28T12:01:00Z" } ], "has_more": false, "cursor": null }

Create Default Egress Rule

POST /v1/egress/rules

Request body:

FieldTypeRequiredDescription
namestringnoUnique human-readable identifier for the rule. Must be unique across all rules in the account.
hoststringnoDomain to match (e.g. api.github.com, *.npmjs.org). Provide host or cidr, not both.
cidrstringnoCIDR range to match (e.g. 10.0.0.0/8). Provide host or cidr, not both.
commentstringnoOptional human-readable note about the rule’s purpose.
curl -X POST https://api.iron.sh/v1/egress/rules \ -H "Authorization: Bearer $IRONS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "github-api", "host": "api.github.com", "comment": "GitHub API access for code pulls" }'

Response: 201 Created

Returns the created rule object.


Delete Default Egress Rule

DELETE /v1/egress/rules/{rule_id}
curl -X DELETE https://api.iron.sh/v1/egress/rules/egr_9xm2kfp4 \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 204 No Content


Audit Logs

List Egress Audit Events

GET /v1/audit/egress
curl "https://api.iron.sh/v1/audit/egress?vm_id=vm_k3mf9xvw2p&verdict=denied&limit=20" \ -H "Authorization: Bearer $IRONS_API_KEY"

Query parameters:

ParamTypeDefaultDescription
vm_idstringFilter by VM ID (e.g. vm_k3mf9xvw2p)
verdictstringFilter by verdict: allowed, denied
allowedbooleanFilter by whether the request was actually permitted
modestringFilter by egress mode at time of event: enforce, warn
hoststringFilter by exact host match
cidrstringFilter by CIDR match
protocolstringFilter by protocol: http, tls, tcp
sincestring (ISO 8601)Only events after this timestamp
untilstring (ISO 8601)Only events before this timestamp
cursorstringPagination cursor
limitinteger50Results per page. Max 500.
orderstringdescSort order: asc, desc (always sorted by timestamp)

Response: 200 OK

{ "data": [ { "id": "ee_w8n3vqx1", "timestamp": "2026-02-28T12:05:30Z", "vm_id": "vm_k3mf9xvw2p", "host": "api.github.com", "cidr": null, "protocol": "tls", "verdict": "allowed", "allowed": true, "mode": "enforce" } ], "has_more": true, "cursor": "ee_p3xn7vm2" }

Secrets

Secrets let you store credentials that the egress proxy injects into outbound requests on behalf of workloads, so the workload never sees the actual credential. Instead, workloads use a proxy_value placeholder in environment variables, and the proxy replaces it with the real secret at the network level.

The proxy is generic: it scans all HTTP headers on every outbound request for known proxy values and replaces them. There is no per-provider logic. Optionally, secrets can be scoped to specific destination hosts.

Secrets are scoped to the authenticated user. The secret value itself is write-only — it is never returned by any endpoint.

Create a Secret

POST /v1/secrets

Request body:

FieldTypeRequiredDescription
namestringyesUnique human-readable identifier. Alphanumeric, hyphens, underscores only. Max 64 characters.
secretstringyesThe secret value. Encrypted at rest. Never returned in responses.
env_varstringyesEnvironment variable name to set inside sandboxes (e.g. GITHUB_TOKEN). Must be a valid env var name: uppercase letters, digits, and underscores, starting with a letter. Must be unique within the user’s secrets.
hostsarray of stringsnoHosts where this secret may be injected. Supports exact hostnames (e.g. api.github.com), wildcards (e.g. *.github.com, single subdomain level), and * (any host). Default: ["*"].
commentstringnoHuman-readable note about the secret’s purpose.
curl -X POST https://api.iron.sh/v1/secrets \ -H "Authorization: Bearer $IRONS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "github-main", "secret": "ghp_abc123def456...", "env_var": "GITHUB_TOKEN" }'

Response: 201 Created

{ "id": "sec_m4xk9wp2", "name": "github-main", "env_var": "GITHUB_TOKEN", "hosts": ["*"], "proxy_value": "IRONSH_PROXY_github-main", "comment": null, "created_at": "2026-03-04T12:00:00Z", "updated_at": "2026-03-04T12:00:00Z" }

The proxy_value field is the placeholder that gets set as the value of the environment variable inside sandboxes. The egress proxy scans all outbound HTTP headers for this value and replaces it with the real secret. The proxy_value is safe to expose — it is meaningless outside the proxy.

By default, secrets are injected on requests to any host allowed by the egress policy. To restrict a secret to specific destinations, provide a hosts array. If a request goes to a host not in the list, the proxy value is left as-is and the upstream receives a meaningless placeholder.

Example with host scoping:

curl -X POST https://api.iron.sh/v1/secrets \ -H "Authorization: Bearer $IRONS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "github-main", "secret": "ghp_abc123def456...", "env_var": "GITHUB_TOKEN", "hosts": ["api.github.com", "*.github.com"] }'

Creating a secret with a duplicate name returns 409 Conflict with code secret_name_taken. Creating a secret with a duplicate env_var returns 409 Conflict with code env_var_taken. Invalid host entries return 422 with code validation_error.


List Secrets

GET /v1/secrets

Query parameters:

ParamTypeDefaultDescription
namestringFilter by exact name match
cursorstringPagination cursor from previous response
limitinteger50Results per page. Max 200.
sortstringcreated_atSort field: created_at, name
orderstringdescSort order: asc, desc
curl https://api.iron.sh/v1/secrets \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

{ "data": [ { "id": "sec_m4xk9wp2", "name": "github-main", "env_var": "GITHUB_TOKEN", "hosts": ["*"], "proxy_value": "IRONSH_PROXY_github-main", "comment": null, "created_at": "2026-03-04T12:00:00Z", "updated_at": "2026-03-04T12:00:00Z" } ], "has_more": false, "cursor": null }

Get a Secret

GET /v1/secrets/{secret_id}
curl https://api.iron.sh/v1/secrets/sec_m4xk9wp2 \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

Same shape as the create response.


Update a Secret

PATCH /v1/secrets/{secret_id}

All fields are optional. Only provided fields are updated. name cannot be changed after creation — delete and recreate instead.

Request body:

FieldTypeRequiredDescription
secretstringnoNew secret value.
env_varstringnoUpdated environment variable name.
hostsarray of stringsnoUpdated host scoping. Replaces existing hosts.
commentstringnoUpdated comment.
curl -X PATCH https://api.iron.sh/v1/secrets/sec_m4xk9wp2 \ -H "Authorization: Bearer $IRONS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"secret": "ghp_newtoken789..."}'

Response: 200 OK

Returns the updated secret object (without the secret value).


Delete a Secret

DELETE /v1/secrets/{secret_id}
curl -X DELETE https://api.iron.sh/v1/secrets/sec_m4xk9wp2 \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 204 No Content


Snapshots

Snapshots capture the state of a virtual machine. A snapshot is sourced from either a base image or another snapshot (never both).

Snapshot object

FieldTypeDescription
idstringUnique identifier (prefixed snap_).
source_virtual_machine_idstringID of the VM this snapshot was taken from.
source_base_imagestring | nullBase image name the VM was running when snapshotted. Present if the VM had no prior snapshot.
source_snapshot_idstring | nullID of the snapshot the VM was restored from when this snapshot was taken. Present if the VM was snapshot-based.
labelstring | nullOptional user-provided label.
statusstringOne of pending, uploading, ready, failed.
r2_keystring | nullStorage key for the snapshot data. Present once uploaded.
size_bytesinteger | nullSize of the snapshot in bytes. Present once uploaded.
created_atstringISO 8601 timestamp.

Create a snapshot

POST /v1/vms/{vm_id}/snapshots

Creates a snapshot of a running or ready VM. To create a new VM from a snapshot, pass the snapshot ID as snapshot_id when creating a VM.

Path parameters:

ParameterTypeDescription
vm_idstringThe VM ID.

Request body:

FieldTypeRequiredDescription
labelstringnoOptional label for the snapshot.
curl -X POST https://api.iron.sh/v1/vms/vm_xyz789/snapshots \ -H "Authorization: Bearer $IRONS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"label": "before-refactor"}'

Response: 201 Created

{ "data": { "id": "snap_abc123", "source_virtual_machine_id": "vm_xyz789", "source_base_image": "ubuntu-24.04", "source_snapshot_id": null, "label": "before-refactor", "status": "pending", "r2_key": null, "size_bytes": null, "created_at": "2026-03-10T12:00:00Z" } }

Errors:

CodeStatusDescription
vm_not_found404VM does not exist or does not belong to you.
vm_not_running409VM must be in running or ready status.
validation_error422Snapshot validation failed.

List snapshots

GET /v1/snapshots GET /v1/vms/{vm_id}/snapshots

Returns snapshots owned by the authenticated user. Optionally scoped to a single VM.

Query parameters:

ParamTypeRequiredDescription
limitintegernoMax number of results to return.
cursorstringnoCursor for pagination (snapshot ID).
curl https://api.iron.sh/v1/snapshots?limit=10 \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

{ "data": [ { "id": "snap_abc123", "source_virtual_machine_id": "vm_xyz789", "source_base_image": "ubuntu-24.04", "source_snapshot_id": null, "label": "before-refactor", "status": "ready", "r2_key": "snapshots/snap_abc123.raw", "size_bytes": 1073741824, "created_at": "2026-03-10T12:00:00Z" } ], "has_more": false, "cursor": null }

Results are ordered by created_at descending (newest first).


Get a snapshot

GET /v1/snapshots/{id}

Path parameters:

ParameterTypeDescription
idstringThe snapshot ID.
curl https://api.iron.sh/v1/snapshots/snap_abc123 \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

{ "data": { "id": "snap_abc123", "source_virtual_machine_id": "vm_xyz789", "source_base_image": "ubuntu-24.04", "source_snapshot_id": null, "label": "before-refactor", "status": "ready", "r2_key": "snapshots/snap_abc123.raw", "size_bytes": 1073741824, "created_at": "2026-03-10T12:00:00Z" } }

Errors:

CodeStatusDescription
snapshot_not_found404Snapshot does not exist or does not belong to you.

Delete a snapshot

DELETE /v1/snapshots/{id}

Soft-deletes a snapshot. It will no longer appear in list or get responses.

Path parameters:

ParameterTypeDescription
idstringThe snapshot ID.
curl -X DELETE https://api.iron.sh/v1/snapshots/snap_abc123 \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 204 No Content

Errors:

CodeStatusDescription
snapshot_not_found404Snapshot does not exist or does not belong to you.

Signup

Create a User

POST /v1/users

Creates a new user account and returns an API key. This endpoint does not require authentication.

Request body:

FieldTypeRequiredDescription
first_namestringyesUser’s first name.
last_namestringyesUser’s last name.
emailstringyesEmail address. Must be unique.
passwordstringyesAccount password.
curl -X POST https://api.iron.sh/v1/users \ -H "Content-Type: application/json" \ -d '{ "first_name": "Alice", "last_name": "Smith", "email": "alice@example.com", "password": "s3cureP@ssword" }'

Response: 201 Created

{ "api_key": { "id": "key_p4t7xm2k", "name": "CLI", "token": "iron_live_a1b2c3d4e5f6...", "created_at": "2026-03-15T12:00:00Z" }, "user": { "id": "usr_w3n8vqx1", "first_name": "Alice", "last_name": "Smith", "email": "alice@example.com", "email_verified": false, "created_at": "2026-03-15T12:00:00Z" } }

A verification email is sent automatically. The returned token can be used immediately as a Bearer token to authenticate subsequent API requests.

Errors:

CodeStatusDescription
email_taken409An account with this email already exists.
validation_error422One or more fields failed validation.

Environment Variables

Environment variables let you store key-value configuration that is available inside your sandboxes.

List Environment Variables

GET /v1/env

Query parameters:

ParamTypeDefaultDescription
cursorstringPagination cursor from previous response
limitinteger50Results per page. Max 200.
curl https://api.iron.sh/v1/env \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

{ "data": [ { "id": "env_m4xk9wp2", "key": "NODE_ENV", "value": "production", "created_at": "2026-03-15T12:00:00Z", "updated_at": "2026-03-15T12:00:00Z" } ], "has_more": false, "cursor": null }

Get an Environment Variable

GET /v1/env/{key}
curl https://api.iron.sh/v1/env/NODE_ENV \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

{ "id": "env_m4xk9wp2", "key": "NODE_ENV", "value": "production", "created_at": "2026-03-15T12:00:00Z", "updated_at": "2026-03-15T12:00:00Z" }

Errors:

CodeStatusDescription
env_not_found404Environment variable not found.

Set an Environment Variable

PUT /v1/env/{key}

Creates or updates an environment variable. If a variable with the given key already exists, its value is replaced.

Request body:

FieldTypeRequiredDescription
valuestringyesThe value for the variable.
curl -X PUT https://api.iron.sh/v1/env/NODE_ENV \ -H "Authorization: Bearer $IRONS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"value": "production"}'

Response: 200 OK

{ "id": "env_m4xk9wp2", "key": "NODE_ENV", "value": "production", "created_at": "2026-03-15T12:00:00Z", "updated_at": "2026-03-15T12:00:00Z" }

Errors:

CodeStatusDescription
validation_error422One or more fields failed validation.

Delete an Environment Variable

DELETE /v1/env/{key}
curl -X DELETE https://api.iron.sh/v1/env/NODE_ENV \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 204 No Content

Errors:

CodeStatusDescription
env_not_found404Environment variable not found.

Agents

Agents are long-running AI coding agents backed by a dedicated VM. Each agent clones a repository and executes a prompt using the specified harness (e.g. claude).

Agent Status

statusDescription
provisioningThe agent’s VM is being created and configured.
runningThe agent is actively executing its prompt.
idleThe agent has finished its work and is waiting.

Create an Agent

POST /v1/agents

Request body:

FieldTypeRequiredDescription
namestringyesUnique name for the agent. Must be unique among active agents.
repostringyesGit repository URL to clone (e.g. https://github.com/org/repo).
branchstringnoBranch to check out. Defaults to the repository’s default branch.
harnessstringnoAgent harness to use. Default: claude.
promptstringyesThe prompt or task description for the agent to execute.
agent_argsstringnoAdditional arguments to pass to the agent harness.
curl -X POST https://api.iron.sh/v1/agents \ -H "Authorization: Bearer $IRONS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "fix-auth-bug", "repo": "https://github.com/org/repo", "branch": "main", "prompt": "Fix the authentication bug in src/auth.ts" }'

Response: 201 Created

{ "id": "agt_x9k2mf4p", "name": "fix-auth-bug", "repo": "https://github.com/org/repo", "branch": "main", "harness": "claude", "prompt": "Fix the authentication bug in src/auth.ts", "agent_args": null, "status": "provisioning", "vm_id": "vm_k3mf9xvw2p", "created_at": "2026-03-15T12:00:00Z", "updated_at": "2026-03-15T12:00:00Z" }

Errors:

CodeStatusDescription
agent_name_taken409An active agent with this name already exists.
validation_error422One or more fields failed validation.

List Agents

GET /v1/agents

Returns active agents (not destroyed).

Query parameters:

ParamTypeDefaultDescription
statusstringFilter by status: provisioning, running, idle
namestringFilter by exact name match
cursorstringPagination cursor from previous response
limitinteger20Results per page. Max 100.
curl https://api.iron.sh/v1/agents?status=running \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

{ "data": [ { "id": "agt_x9k2mf4p", "name": "fix-auth-bug", "repo": "https://github.com/org/repo", "branch": "main", "harness": "claude", "prompt": "Fix the authentication bug in src/auth.ts", "agent_args": null, "status": "running", "vm_id": "vm_k3mf9xvw2p", "created_at": "2026-03-15T12:00:00Z", "updated_at": "2026-03-15T12:01:00Z" } ], "has_more": false, "cursor": null }

Get an Agent

GET /v1/agents/{agent_id}
curl https://api.iron.sh/v1/agents/agt_x9k2mf4p \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 200 OK

Same shape as the create response.

Errors:

CodeStatusDescription
agent_not_found404Agent not found or has been destroyed.

Destroy an Agent

DELETE /v1/agents/{agent_id}

Destroys the agent and its backing VM.

curl -X DELETE https://api.iron.sh/v1/agents/agt_x9k2mf4p \ -H "Authorization: Bearer $IRONS_API_KEY"

Response: 204 No Content

Errors:

CodeStatusDescription
agent_not_found404Agent not found or has been destroyed.

Authentication

Request Device Code

POST /v1/auth/device/code
curl -X POST https://api.iron.sh/v1/auth/device/code

Response: 200 OK

{ "data": { "code": "ABCD-1234", "verification_uri": "https://app.iron.sh/activate", "expires_at": "2026-02-28T12:15:00Z" } }

Poll Device Authorization

GET /v1/auth/device/poll

Query parameters:

ParamTypeRequiredDescription
codestringyesThe device code from the code request
curl "https://api.iron.sh/v1/auth/device/poll?code=ABCD-1234"

Response: 200 OK

{ "data": { "status": "authorized", "token": "iron_live_a1b2c3d4e5f6..." } }
StatusMeaning
pendingUser hasn’t authorized yet. Continue polling.
authorizedAuthorization successful. token is present.
expiredCode expired. Request a new one.
Last updated on