WARPMETALAPI documentation
Public API / version 2

Control a VPS with ordinary HTTP.

Discover live images, prepare and pay for a 30-day VPS, poll it to ready, and manage it with the one-time owner token. WarpMetal keeps the underlying compute provider and its credentials out of the public contract.

Base URL
https://api.warpmetal.com
Content type
application/json
Credential boundary

A wallet authorizes a specific x402 payment. It does not control the server. The ownerToken returned by order preparation controls status, renewal, and lifecycle operations. It is shown once; store it like a password and never put it in a URL, log, or client-side analytics event.

01

Headers and authentication

There is no account login and no reusable provider API key.

AuthorizationBearer <ownerToken>Required for checkout, task reads, renewal, and lifecycle operations.
Idempotency-Key8–160 charactersRequired for order creation and every mutating lifecycle request. Use a new value for each new action.
PAYMENT-SIGNATUREx402 v2 payloadAdded only after signing a live PAYMENT-REQUIRED challenge.
02

Plans and available operating systems

Never hard-code image names. Inventory can change.

GET/api/catalog

No authentication. Returns products[]. Choose a product by id, then choose an OS from that same product's operatingSystems[]. Submit the exactname value as osName when ordering or reloading. WarpMetal only publishes images withmonthlyPrice: 0 and sshKey: true.

curl --fail https://api.warpmetal.com/api/catalog | jq '
  .products[] |
  {planId: .id, priceUsd, termDays,
   operatingSystems: [.operatingSystems[] |
     {name, label, sshKey, cloudInit, monthlyPrice}]}'
# Select one exact OS name for the standard plan
OS_NAME=$(curl -fsS https://api.warpmetal.com/api/catalog |
  jq -r '.products[] | select(.id == "standard") |
    .operatingSystems[] |
    select(.monthlyPrice == 0 and .sshKey == true) |
    .name' | head -n 1)

HTTP 503 means fresh catalog inventory is unavailable. Pause ordering and reload requests instead of guessing an OS name.

03

Prepare an order

Preparation does not charge a wallet or provision a server.

POST/api/orders

Required body fields are planId,hostname, osName, and an OpenSSHsshPublicKey. email is optional and only enables notices; it is not an account or recovery method.

curl -i -X POST https://api.warpmetal.com/api/orders \
  -H 'content-type: application/json' \
  -H 'idempotency-key: order-<unique-value>' \
  --data '{
    "planId": "standard",
    "hostname": "agent-workspace",
    "osName": "<exact products[].operatingSystems[].name>",
    "sshPublicKey": "ssh-ed25519 <public-key-data> agent@example"
  }'

HTTP 201 returns task and the one-timeownerToken. An exact idempotent replay returns the same response for 24 hours; the same key with different JSON returns HTTP 409.

04

Pay the x402 challenge

The live 402 is authoritative for price, asset, network, and recipient.

POST/api/checkout/{planId}
curl -i -X POST https://api.warpmetal.com/api/checkout/standard \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer <ownerToken>' \
  --data '{"taskId":"task_..."}'
  1. HTTP 402: sign the PAYMENT-REQUIRED header and retry the exact method, URL, content type, and body with PAYMENT-SIGNATURE.
  2. HTTP 202 with payment_pending: wait for Retry-After, then retry the exact request with the exact same signature.
  3. A signed HTTP 402 definitively rejected that signature. Read the new challenge and create one replacement authorization.
  4. HTTP 409 manual_review: payment may be final. Never pay again.
  5. HTTP 202 provisioning: payment is final; poll the task.
05

Poll the task and connect with SSH

The task is the durable view of purchase and provisioning state.

GET/api/tasks/{taskId}
curl -fsS https://api.warpmetal.com/api/tasks/task_... \
  -H 'authorization: Bearer <ownerToken>'

Follow pollAfterSeconds. Continue while state isprepared, payment_pending,paid, or provisioning. When it isready, use publicIp with the private key matching the submitted public key. SSH usernames are image-specific; this API does not publish or guess one.

Terminal states are expired,cancellation_pending, cancelled, andfailed. For manual_review, stop automation and do not pay or mutate the resource again.

06

Lifecycle operation model

Power, reload, and network mutations are durable asynchronous operations.

GET/api/operations/{operationId}

A mutating lifecycle request returns HTTP 202, aLocation header, and an operation in statequeued. Poll with the same owner token until state is succeeded, failed, ormanual_review. Do not infer success from HTTP 202.

curl -fsS https://api.warpmetal.com/api/operations/op_... \
  -H 'authorization: Bearer <ownerToken>'

Replaying the same action with the same Idempotency-Key returns the same operation. Reusing that key for different content returns HTTP 409.

07

Power control

Available only while the task is ready.

POST/api/tasks/{taskId}/power
curl -i -X POST https://api.warpmetal.com/api/tasks/task_.../power \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer <ownerToken>' \
  -H 'idempotency-key: power-<unique-value>' \
  --data '{"action":"reboot"}'

Allowed actions: boot, reboot, and shutdown.

08

Destructive OS reload

Reload erases the server. It is not a reboot.

POST/api/tasks/{taskId}/reload

The task must be ready. Sendconfirm: "ERASE". The optionalhostname, osName, andsshPublicKey fields replace those values; omitted fields keep their current value. A replacement OS must be an exact live free OS name from the task plan inGET /api/catalog.

curl -i -X POST https://api.warpmetal.com/api/tasks/task_.../reload \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer <ownerToken>' \
  -H 'idempotency-key: reload-<unique-value>' \
  --data '{
    "confirm": "ERASE",
    "hostname": "fresh-workspace",
    "osName": "<exact live OS name>",
    "sshPublicKey": "ssh-ed25519 <new-public-key-data> agent@example"
  }'

Poll the returned operation. On succeeded, poll the task again to read the updated hostname, OS, and SSH fingerprint. If the operation becomesmanual_review, the provider outcome is ambiguous: do not submit another reload.

09

Private networks

Networks are scoped to the owner token and US capacity.

GET/api/networks?taskId={taskId}
curl -fsS 'https://api.warpmetal.com/api/networks?taskId=task_...' \
  -H 'authorization: Bearer <ownerToken>'
POST/api/networks
curl -i -X POST https://api.warpmetal.com/api/networks \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer <ownerToken>' \
  -H 'idempotency-key: network-create-<unique-value>' \
  --data '{"taskId":"task_...","name":"agent-lan"}'

HTTP 409 means owner or platform network capacity is reached.

POST/api/tasks/{taskId}/network
curl -i -X POST https://api.warpmetal.com/api/tasks/task_.../network \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer <ownerToken>' \
  -H 'idempotency-key: network-attach-<unique-value>' \
  --data '{"networkId":"net_...","action":"attach"}'

Allowed actions: attach and detach. Poll the returned operation.

10

Renew for another 30 days

Renewal is explicit and requires a new x402 payment.

POST/api/checkout/{planId}/renew
curl -i -X POST https://api.warpmetal.com/api/checkout/standard/renew \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer <ownerToken>' \
  --data '{"taskId":"task_..."}'

The task must be ready or expired and still have its instance. Handle 402 and payment-pending retries exactly like initial checkout. HTTP 200 meanstermEndsAt was extended by 30 days. There is no public destroy/cancel endpoint; an unrenewed instance is cancelled by maintenance after its term ends.

11

Errors, retries, and limits

All API errors use a stable JSON envelope.

{
  "error": {
    "code": "stable_machine_code",
    "message": "Human-readable explanation."
  }
}
400Invalid JSON, hostname, OS, public key, action, or missing idempotency key. Fix the request.
402Payment required, or a supplied signature was definitively rejected. Follow the returned challenge.
404The resource and owner-token pair was not found. Do not loop.
409State/idempotency conflict or manual review. Read the code; never pay again for manual review.
429Rate limited. Wait for the Retry-After header.
503A dependency or payment outcome is unavailable. For a signed payment attempt, preserve and retry the exact request.