Skip to Content
Agent computeREST: agent lifecycle
Raw

Aetherfy agent lifecycle API

Base URL https://agents.aetherfy.com/api/v1, bearer authentication, and the shared error envelope are described on the Agent REST API index. {agent} accepts a UUID or a name throughout.

Creating an Aetherfy agent

POST /api/v1/agents → 201

curl -s -X POST https://agents.aetherfy.com/api/v1/agents \ -H "Authorization: Bearer $AETHERFY_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name":"reporter","runtime":"python3.12","memory_mb":512,"agent_type":"job"}'
FieldTypeDefaultNotes
namestringRequired. 1–64 characters, unique per account
descriptionstring | nullnullHuman-readable
agent_typeenumserviceservice or job
runtimeenumpython3.11See the runtime list below
memory_mbinteger256Must be within your plan’s maximum
idle_timeout_minutesinteger5Within your plan’s maximum
keep_alivebooleanfalseAlways-on. Counts as usage
entrypointstring | nullnulle.g. main.py, index.js
database_collectionstring | nullnullCollection this agent declares
model_namestring | nullnullFree-form
spawn_enabledbooleanfalseAllow this agent to spawn type: job agents
allowed_workersstring[][]Names this agent may spawn. Empty means no restriction
workspace_namestring | nullnullWorkspace to place the agent in
tierenumfreeAccepted but authoritative plan comes from your subscription

Runtimes: python3.11, python3.12, python3.13, node20, node22, node20-ts, node22-ts, bun, dockerfile.

Creating an agent does not deploy it — it reserves the name and the configuration. See Deployments.

Your agent quota is not checked here. The quota counts deployed agents, and a freshly created agent is a draft, so you can keep as many drafts as you like on any plan — including building a replacement for an agent that is currently serving traffic, before you take the old one down. It is checked when you first deploy an agent, and when you restore one from the archive.

Which agents hold a slot follows from that. A deployed agent holds one, and stopping it does not give it back: a stopped agent is paused, which keeps it deployed. Archiving or deleting an agent releases its slot. Drafts never held one.

The per-agent caps are checked here — memory, idle timeout, always-on and the dockerfile runtime are all validated against your plan before the record is written, and an over-cap create is refused with PLAN_LIMIT_EXCEEDED.

Checking the quota at deploy rather than at create is not merely a deferral, and the deploy-time check is not redundant with anything: an agent created under your limit can reach its first deploy after a downgrade, or after another agent took the last slot.

CodeHTTPMeaning
AGENT_NAME_TAKEN409Another agent on this account already has that name
WORKSPACE_NOT_FOUND404workspace_name does not resolve
PLAN_LIMIT_EXCEEDED403Memory, idle timeout, always-on or dockerfile runtime exceeds your plan. Not agent count — that is checked at deploy
AGENT_COLLECTION_REGION_MISMATCH400database_collection lives in regions this agent could not reach
SERVICE_UNAVAILABLE503Your plan could not be read, so no limit could be checked. Transient — retry

Listing and reading Aetherfy agents

GET /api/v1/agents → 200, an array of agent objects. GET /api/v1/agents/{agent} → 200, one agent object.

curl -s https://agents.aetherfy.com/api/v1/agents/reporter \ -H "Authorization: Bearer $AETHERFY_API_KEY"

The agent object carries the creation fields above plus:

FieldTypeNotes
iduuid
user_iduuid
statusenumSee the status table below
parent_agent_iduuid | nullSet on a spawned worker
regionsstring[]Regions the agent currently occupies
pending_regionsstring[]Regions a change is still moving into
regions_total / regions_readyintegerConvergence counters
is_degradedbooleanSome regions are not serving
degraded_reasonstring | nullWhy, when is_degraded is true
failure_codestring | nullWhy the agent is failed, when nothing else on the record says. Branch on this
failure_messagestring | nullThe same reason as prose, for display. Wording may change between releases
cron_schedulestring | nullThe 5-field UTC cron expression, when a schedule is set
cron_next_run_attimestamp | nullNext scheduled fire
cron_pausedbooleanWhether the schedule is paused
cron_last_run_attimestamp | null
cron_last_statusstring | null
cron_last_reasonstring | nullWhy the last occurrence did not fire, when it did not
created_at / updated_attimestamp

failure_code is set only where the reason cannot be recovered from anything else. Today it carries one value, app_lost_on_provider: the compute plane no longer has an app for the agent. Your code, your secrets and the agent’s address are all kept, and afy deploy <agent> brings it back. A null failure_code is not a claim that the agent is healthy — an agent whose build did not compile has null here and explains itself through its deployment’s error instead.

failure_code is separate from is_degraded on purpose. is_degraded means the agent is serving and something about it is wrong; a failed agent is not serving at all, so the two never describe the same condition.

The cron_* fields describe a scheduled task. cron names the expression format only.

Aetherfy agent statuses

StatusMeaning
pendingCreated, nothing built yet
buildingA deployment is building
deployingBuilt, machines coming up
runningServing
failedThe last deployment failed
pausedYou stopped it — see stop below
stoppedAetherfy stopped it because the account was suspended
usage_pausedAetherfy paused it because a spend limit was reached
suspendedAccount-level suspension
archivedTorn down, configuration and code retained
deleting / deletedTerminal

paused and stopped are different states with different causes, and the distinction matters when you are diagnosing an agent that is not serving. paused is something you did and can undo with start. stopped means the account was suspended — settle it and Aetherfy returns the agent to running on its own. See Billing and spend caps.

Updating an Aetherfy agent

PATCH /api/v1/agents/{agent} → 200. Every field is optional; omitted fields are untouched. Setting workspace_name to null moves the agent out of any workspace.

curl -s -X PATCH https://agents.aetherfy.com/api/v1/agents/reporter \ -H "Authorization: Bearer $AETHERFY_API_KEY" \ -H "Content-Type: application/json" \ -d '{"memory_mb":1024,"keep_alive":true}'

Configuration changes here take effect on the next deploy. To change what is running now, deploy again.

CodeHTTPMeaning
AGENT_NOT_FOUND404
AGENT_TOGGLE_RATE_LIMITED429Always-on was toggled too rapidly
PLAN_LIMIT_EXCEEDED403The new configuration exceeds your plan
AGENT_COLLECTION_REGION_MISMATCH400The declared collection’s regions are unreachable from the agent’s
WORKSPACE_NOT_FOUND404The target workspace_name does not resolve
AGENT_DEPLOYMENT_OUTSIDE_NEW_WORKSPACE_SCOPE400The agent’s live deployment sits outside the target workspace’s region set. Carries a violations array naming the deployment version, its regions and the cap
SOFT_CAP_EXCEEDED / DUNNING_FROZEN403Configuration changes are frozen — see Billing

Stopping and starting an Aetherfy agent

POST /api/v1/agents/{agent}/stop → 202 {"status": "paused", "machines": "stopping", "agent_id": "…"} POST /api/v1/agents/{agent}/start → 202 {"status": "running", "agent_id": "…"}

curl -s -X POST https://agents.aetherfy.com/api/v1/agents/reporter/stop \ -H "Authorization: Bearer $AETHERFY_API_KEY"

Stop moves the agent to paused — note the endpoint is named for the verb and the resulting status is paused, not stopped. The agent keeps its slot against your plan’s agent count, its configuration and its code. Start brings the same machines back without rebuilding.

The pause is in force the moment the call returns: the status is paused, billing for machine uptime stops at that instant, and a deploy or rollback against the agent is already refused. The machines field reports the remaining work — the machines wind down in the background, and the machine states you see under GET /api/v1/agents/{agent}/status catch up afterwards rather than immediately.

Nothing you can do with the agent waits on that. start works straight away, even on machines still shown as stopping, and the pause is already reflected everywhere it matters. Treat the machine states as a view that trails, not as the pause itself.

Because a paused agent still holds its quota slot, you cannot pause your way under an agent limit. Archive instead.

CodeHTTPMeaning
AGENT_ALREADY_PAUSED409Already paused
AGENT_NOT_PAUSED409start on an agent that was not paused
AGENT_ALREADY_ARCHIVED409Restore it first
AGENT_HAS_PENDING_DEPLOYMENTS409Wait for the build to finish or fail
AGENT_NOT_PAUSEABLE_SYSTEM_STATE409Aetherfy owns the current state, e.g. usage_paused
AGENT_OPERATION_IN_PROGRESS409A worker holds the agent. Transient — retry
AGENT_NO_MACHINES400Nothing to start; deploy first
AGENT_PAUSE_FAILED / AGENT_RESUME_FAILED503The machine host was unreachable. The status is unchanged — retry

AGENT_OPERATION_IN_PROGRESS is the only 409 here that is safe to retry blindly; the others describe a state you have to change first.

Archiving and restoring an Aetherfy agent

POST /api/v1/agents/{agent}/archive → 202 {"status": "archiving", …} POST /api/v1/agents/{agent}/restore → 202 {"status": "restoring", …}

Archiving tears the agent’s infrastructure down and releases its quota slot, keeping its configuration and stored code. It is the way to get under your agent limit without deleting anything.

Restoring rebuilds it — and re-checks quota at that moment, because other agents may have taken the slot meanwhile. An archived agent is therefore not guaranteed to come back if you have filled your plan since.

CodeHTTPMeaning
AGENT_ALREADY_ARCHIVED409
AGENT_NOT_ARCHIVED409restore on an agent that was not archived
AGENT_NOT_ARCHIVABLE_SYSTEM_STATE409Aetherfy owns the current state
AGENT_HAS_PENDING_DEPLOYMENTS409
AGENT_HAS_WORKER_DEPENDENTS409Another agent lists this one in spawn.workers. Carries dependents
PLAN_LIMIT_EXCEEDED403On restore: no quota slot free any more

Deleting an Aetherfy agent

DELETE /api/v1/agents/{agent} → 202 {"status": "deleting", "agent_id": "…"}

Deletion is permanent and asynchronous: the agent moves to deleting and a worker tears down machines and stored code. It is refused while something still depends on the agent.

CodeHTTPMeaning
AGENT_HAS_PENDING_DEPLOYMENTS409Carries pending_deployments. Wait for active or failed
AGENT_HAS_WORKER_DEPENDENTS409Carries dependents — the agents naming this one in spawn.workers

Deleting is not how you free a quota slot temporarily. Archive does that reversibly.

Reading live Aetherfy machine status

GET /api/v1/agents/{agent}/status → 200

curl -s https://agents.aetherfy.com/api/v1/agents/reporter/status \ -H "Authorization: Bearer $AETHERFY_API_KEY"
{ "agent_id": "6f1c2b7e-0a2d-4f8e-9c31-2b0d5a7e4411", "name": "reporter", "status": "running", "url": "https://reporter-k3m7x2.aetherfy.dev", "machines": [ { "id": "1857a3d4f21e08", "region": "iad", "state": "started", "source": "live", "health": "passing", "last_check": "2026-08-19T09:12:44Z", "instance_id": "01J9…" } ] }

This route differs from GET /agents/{agent} in one important way: it queries the machine host directly, so machines[].state is real-time rather than whatever Aetherfy last recorded.

Read source before trusting state. It is "live" when that machine was in the host’s response, and "cached" when Aetherfy fell back to its own last-known value because the host read failed. A cached reading can be up to about a minute stale. If your automation waits for a machine to reach a state, require source == "live" — otherwise a stale reading can satisfy the wait before the state is actually true.

url is null until the agent has machines. Destroyed machines are omitted.

Exporting an Aetherfy agent’s aetherfy.yaml

GET /api/v1/agents/{agent}/yaml → 200, Content-Type: application/yaml

curl -s https://agents.aetherfy.com/api/v1/agents/reporter/yaml \ -H "Authorization: Bearer $AETHERFY_API_KEY" \ -o aetherfy.yaml

The response body is YAML, not JSON. It is the declarative subset of the agent’s current configuration — the same content the dashboard’s download button produces — so it round-trips: write it into a project directory and deploy, and you get the agent back. See the aetherfy.yaml reference.

Returns 404 AGENT_NOT_FOUND for an agent being deleted.

Last updated on