Skip to content

HTTP API

Base URL: https://control-production-3ac7.up.railway.app

Every route here takes an API key, Authorization: Bearer <key>, unless it says it is public. Create a key under API keys in the dashboard. Request bodies are JSON of at most 1 MiB; a manifest travels through storage, never through the API. Money is a decimal string with six places ("0.004000"), but for a machine’s rate, which has four ("0.3000", US dollars an hour), and a payout, which has two ("25.00"). A refused request answers with {"detail": "<message>"}, and one that fails validation (422) with {"detail": [{"type": ..., "loc": [...], "msg": ...}]}. Lists are paged: GET /v1/jobs returns the newest 200 jobs and ?before=<last job id> the 200 before them; GET /v1/jobs/{job_id}/units returns 1,000 units in id order and ?after=<last unit id> the next 1,000; GET /v1/supply/earnings and GET /v1/supply/payouts return the newest 200 and ?before=<last id> the 200 before them. A submit that carries a client_token can be retried safely: the same token with the same spec returns the job it already created.

Besides the statuses each route lists: 401 without a valid key; 402 when the org’s credit cannot cover a job; 404 for an unknown job or template; 409 for a conflict (a template priced above price.max_per_unit, a client_token reused with a different spec); 413 for a body over 1 MiB; 422 for a manifest or location that cannot be used; 429 when the org’s open jobs already hold the most units it may have open; 503, with Retry-After, while the control plane is busy reading other manifests.

The /v1/supply routes are a supplier’s, with the same key, and GET /v1/supply/rates, the rates suggested to machines, is public. POST /v1/supply/tokens answers with a supply token, uf_supply_ and 40 hex digits, shown this once with the lines that install a machine with it, with the token in them and without it: the token enrols machines for a day, and opens no route here. An organization holds at most 20 supply tokens that have not expired or been revoked (409 for another), and a machine that is not the organization’s is a 404.

A response names its schema where the control plane declares one (every job, unit, result, template and supply route does), and the schemas follow the routes. Times are ISO 8601 strings.

GET /v1/status, public: no key

Public, no key. The status page reads it from the browser, on another origin, so it carries a CORS header.

Responses: 200 Successful Response.

GET /v1/jobs

Newest first, keyset paged by before. status (repeatable), template and q (part of the name, in any case) filter every page alike; limit is at most 200.

Name In Type Required Default Constraints
before query string or null no matches ^[A-Za-z0-9_.-]{1,64}$
status query array of calibrating, queued, running, paused, completed, cancelled, rejected or null no
template query string or null no 1 to 200 characters
q query string or null no 1 to 200 characters; matches ^[^\x00-\x1f\x7f]+$
limit query integer no 200 at least 1; at most 200

Responses: 200 Successful Response (array of Job); 422 Validation Error (HTTPValidationError).

POST /v1/jobs

Body (JSON, required): JobSpec.

Responses: 201 Successful Response (Job); 422 Validation Error (HTTPValidationError).

GET /v1/jobs/{job_id}

Name In Type Required Default Constraints
job_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$

Responses: 200 Successful Response (Job); 422 Validation Error (HTTPValidationError).

GET /v1/jobs/{job_id}/units

Up to 1000 units in id order after after, of one status, and whose id begins with prefix, each when given.

Name In Type Required Default Constraints
job_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$
status query pending, leased, done, failed or null no
after query string or null no matches ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$
prefix query string or null no matches ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$

Responses: 200 Successful Response (array of Unit); 422 Validation Error (HTTPValidationError).

POST /v1/jobs/{job_id}/accept

A paused job runs on at the new quote it shows in requote_usd. With a body naming the quote the buyer was shown ({“requote_usd”: “0.015000”}), a job whose quote is another is a 409 and nothing changes; a body that names none is refused.

Name In Type Required Default Constraints
job_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$

Body (JSON): AcceptQuote or null.

Responses: 200 Successful Response (Job); 422 Validation Error (HTTPValidationError).

POST /v1/jobs/{job_id}/cancel

Name In Type Required Default Constraints
job_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$

Responses: 200 Successful Response (Job); 422 Validation Error (HTTPValidationError).

GET /v1/internal/api-keys

Responses: 200 Successful Response (array of ApiKey); 422 Validation Error (HTTPValidationError).

POST /v1/internal/api-keys

Body (JSON, required): NewKey.

Responses: 200 Successful Response (NewApiKey); 422 Validation Error (HTTPValidationError).

DELETE /v1/internal/api-keys/{key_id}

Name In Type Required Default Constraints
key_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$

Responses: 200 Successful Response (Revoked); 422 Validation Error (HTTPValidationError).

GET /v1/supply/tokens

Your organization’s supply tokens, without the tokens themselves: each one’s name, first characters, when it was made, expires, was last used and was revoked.

Responses: 200 Successful Response (array of SupplyToken); 422 Validation Error (HTTPValidationError).

POST /v1/supply/tokens

Create a supply token, which adds machines to your organization for a day. This answer is the only place it is shown, with the lines that install a machine with it: one for Linux and one for Windows (through WSL2), which carry the token, and the same two without it, which ask for it when they run. A line typed with the token stays in that shell’s history for the day. Each machine it adds waits for you to confirm it.

Body (JSON, required): NewSupplyToken.

Responses: 201 Successful Response (CreatedSupplyToken); 422 Validation Error (HTTPValidationError).

DELETE /v1/supply/tokens/{token_id}

Revoke a supply token: it adds no machine from now on. The machines it added keep working.

Name In Type Required Default Constraints
token_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$

Responses: 200 Successful Response (Revoked); 422 Validation Error (HTTPValidationError).

GET /v1/supply/nodes

Your organization’s machines, oldest first: each one’s state, rate, trust and benchmarks.

Responses: 200 Successful Response (array of Machine); 422 Validation Error (HTTPValidationError).

GET /v1/supply/nodes/{node_id}

One of your organization’s machines, with why its trust moved lately, in words, newest first.

Name In Type Required Default Constraints
node_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$

Responses: 200 Successful Response (MachineDetail); 422 Validation Error (HTTPValidationError).

PATCH /v1/supply/nodes/{node_id}

Change a machine’s name, its rate (USD an hour), and whether it is private (your organization’s jobs only), paused (it finishes what it holds and takes nothing new) or runs other organizations’ own images.

Name In Type Required Default Constraints
node_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$

Body (JSON, required): MachinePatch.

Responses: 200 Successful Response (Machine); 422 Validation Error (HTTPValidationError).

DELETE /v1/supply/nodes/{node_id}

Remove a machine: it stops working at once, and the work it held goes to other machines. What it earned stays your organization’s, unless its trust had fallen under the trust it started at.

Name In Type Required Default Constraints
node_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$

Responses: 200 Successful Response (Removed); 422 Validation Error (HTTPValidationError).

POST /v1/supply/nodes/{node_id}/confirm

Confirm a machine added with one of your supply tokens. Until you do, it runs other organizations’ public jobs and none of yours, so that a machine added with a token that leaked never sees your work.

Name In Type Required Default Constraints
node_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$

Responses: 200 Successful Response (Machine); 422 Validation Error (HTTPValidationError).

GET /v1/supply/rates, public: no key

What a machine of each GPU class is suggested to ask, in USD an hour, and per GB of its GPU’s memory for a class the table does not name. Public: no API key.

Responses: 200 Successful Response (SuggestedRates).

GET /v1/supply/rules

The numbers of the supply side’s rules as this control plane is set: the most of a unit’s price a machine earns, the trust a machine starts at and is verified from, the hold of an unverified machine’s earnings, and when and from how much payouts run.

Responses: 200 Successful Response (SupplyRules); 422 Validation Error (HTTPValidationError).

POST /v1/supply/payouts/onboard

Set up payouts: a link to Stripe, where you give what Stripe needs to pay your organization (its country, for a payee abroad). Once that is done, the link opens your payouts dashboard at Stripe instead.

Body (JSON): OnboardRequest or null.

Responses: 200 Successful Response (OnboardLink); 422 Validation Error (HTTPValidationError).

GET /v1/supply/payouts/account

How your payout account stands at Stripe: whether its details are in, and whether it can be paid.

Responses: 200 Successful Response (PayoutAccount); 422 Validation Error (HTTPValidationError).

GET /v1/supply/payouts

Your payouts, newest first: the month each is for, its amount, and whether it is pending, paid (with Stripe’s transfer) or failed (with Stripe’s reason), and what of it was taken back. before pages: the last id of a page.

Name In Type Required Default Constraints
before query string or null no matches ^[A-Za-z0-9_.-]{1,64}$

Responses: 200 Successful Response (array of Payout); 422 Validation Error (HTTPValidationError).

GET /v1/supply/earnings

What your machines earned, unit by unit, newest first: the job as your machine was told it, the unit, the amount, and whether it is held, credit only, voided or paid out. before pages: the last id of a page.

Name In Type Required Default Constraints
before query string or null no matches ^[A-Za-z0-9_.-]{1,64}$

Responses: 200 Successful Response (array of Earning); 422 Validation Error (HTTPValidationError).

GET /v1/supply/earnings/daily

What your machines earned on each of the last days days (UTC; 1 to 366), and for how many units.

Name In Type Required Default Constraints
days query integer no 30 at least 1; at most 366

Responses: 200 Successful Response (array of EarningsDay); 422 Validation Error (HTTPValidationError).

GET /v1/supply/earnings/summary

Your earnings in sum: earned, unpaid (and of it what is held and what is credit only), paid out and voided; the payout minimum, the holds, and the day of the next payout.

Responses: 200 Successful Response (EarningsSummary); 422 Validation Error (HTTPValidationError).

GET /v1/account

The org’s balance and the credit free for new jobs, which sums what its open quoted jobs can still bill: a read that grows with the org’s jobs, so it takes a read slot like the job lists (Plan U1).

Responses: 200 Successful Response (Account); 422 Validation Error (HTTPValidationError).

GET /v1/account/ledger

Name In Type Required Default Constraints
before query string or null no matches ^[A-Za-z0-9_.-]{1,64}$

Responses: 200 Successful Response (array of LedgerEntry); 422 Validation Error (HTTPValidationError).

GET /v1/account/usage

What the org’s jobs cost this month, last month and on each of the last 30 days (UTC).

Responses: 200 Successful Response (Usage); 422 Validation Error (HTTPValidationError).

GET /v1/account/ledger/{entry_id}/receipt

A 307 to Stripe’s receipt for a card top-up (a ledger credit whose reference starts stripe:).

Name In Type Required Default Constraints
entry_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$

Responses: 307 Successful Response; 422 Validation Error (HTTPValidationError).

GET /v1/templates, public: no key

The catalogue, with each template’s price per unit, and no key: the prices are published anyway, and the public site builds its pricing page from this, so the build needs no secret. A node that sends its token gets each template’s full definition instead (image, command, bench inputs): the node agent’s answer, internal and outside this schema.

Responses: 200 Successful Response (array of Template); 422 Validation Error (HTTPValidationError).

POST /v1/uploads

Body (JSON, required): UploadRequest.

Responses: 200 Successful Response (JSON object); 422 Validation Error (HTTPValidationError).

GET /v1/jobs/{job_id}/results

Async, like the job reads: a page presigns up to 20,000 links, so it is built on a worker thread under _READS.

Name In Type Required Default Constraints
job_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$
after query string or null no matches ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$

Responses: 200 Successful Response (Manifest); 422 Validation Error (HTTPValidationError).

GET /v1/jobs/{job_id}/units/{unit_id}/artifacts/{name}

A 307 to the artifact’s presigned link, served as a download.

Name In Type Required Default Constraints
job_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$
unit_id path string yes matches ^[A-Za-z0-9_.-]{1,64}$
name path string yes at most 255 characters; matches ^[^/\\\x00]+$

Responses: 307 Successful Response; 422 Validation Error (HTTPValidationError).

POST /v1/billing/checkout

Async on purpose: the Stripe call can take seconds, so it runs under its own limiter rather than on a worker thread that heartbeats and reports need.

Body (JSON, required): CheckoutRequest.

Responses: 200 Successful Response (JSON object); 422 Validation Error (HTTPValidationError).

Field Type Required Default Constraints
id string yes
name string yes
status calibrating, queued, running, paused, completed, cancelled, rejected yes
template string or null yes
family string yes
pool public, own, verified, platform yes
quoted_price_usd string or null yes matches ^-?[0-9]+\.[0-9]{6}$
requote_usd string or null yes matches ^-?[0-9]+\.[0-9]{6}$
pause_reason above_max_per_unit, insufficient_credit or null yes
units_total integer yes
units UnitCounts yes
units_done_last_10m integer yes
cost_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
output string yes
created_at string yes
updated_at string yes

Unknown fields are refused.

Field Type Required Default Constraints
name string yes 1 to 200 characters
template string or null no at most 200 characters
image string or null no at most 500 characters
command array of string or null no at most 64 items; each at most 4096 characters
input string or null no at most 1000 characters
units integer or null no at least 1; at most 1000000
output string or null no at most 1000 characters
resources Resources no {"gpu":{},"cpu":4,"memory_gb":16,"scratch_gb":50}
unit UnitSpec no {"max_seconds":300,"max_attempts":3}
price PriceSpec no {}
network string no "egress-only" matches ^(egress-only|none)$
checkpoint string no "auto" matches ^(auto|off)$
pool public, own, verified, platform no "public"
client_token string or null no at most 64 characters; matches ^[A-Za-z0-9_-]+$
Field Type Required Default Constraints
unit_id string yes
status pending, leased, done, failed yes
attempts integer yes
lease_id string or null yes
artifacts array of UnitArtifact or null yes
seconds string or null yes matches ^-?[0-9]+\.[0-9]{6}$
price_usd string or null yes matches ^-?[0-9]+\.[0-9]{6}$
billed_at string or null yes
failure_reason string or null yes
log_tail string or null yes

Unknown fields are refused.

Field Type Required Default Constraints
requote_usd string yes matches ^[0-9]+\.[0-9]{6}$
Field Type Required Default Constraints
id string yes
name string yes
prefix string yes
created_at string yes
revoked_at string or null yes
last_used_at string or null yes
Field Type Required Default Constraints
name string no "default" at most 100 characters
Field Type Required Default Constraints
id string yes
key string yes
prefix string yes
name string yes
Field Type Required Default Constraints
revoked boolean yes
Field Type Required Default Constraints
id string yes
name string yes
prefix string yes
created_at string yes
expires_at string yes
revoked_at string or null yes
last_used_at string or null yes

Unknown fields are refused.

Field Type Required Default Constraints
name string no "default" at most 100 characters
Field Type Required Default Constraints
id string yes
name string yes
prefix string yes
token string yes
created_at string yes
expires_at string yes
install string yes
install_windows string yes
install_prompt string yes
install_windows_prompt string yes
Field Type Required Default Constraints
id string yes
name string yes
gpu_name string or null yes
gpu_class string or null yes
vram_gb string yes
cpu integer yes
memory_gb string yes
platform linux, wsl2 yes
network netns, none yes
checkpoint_capable boolean yes
status online, offline yes
last_seen_at string yes
created_at string yes
confirmed boolean yes
rate_usd_per_hour string yes matches ^[0-9]+\.[0-9]{4}$
private boolean yes
paused boolean yes
accept_byo boolean yes
trust integer yes
verified boolean yes
benchmarks array of MachineBenchmark yes
active_lease MachineLease or null yes
units_today integer yes
units_failed_today integer yes
earned_today_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
leases_lost_24h integer yes
start_trust integer yes
supply_token_id string or null yes
public_work boolean yes
public_work_reason paused, private, unbenchmarked, unjudged or null yes
Field Type Required Default Constraints
id string yes
name string yes
gpu_name string or null yes
gpu_class string or null yes
vram_gb string yes
cpu integer yes
memory_gb string yes
platform linux, wsl2 yes
network netns, none yes
checkpoint_capable boolean yes
status online, offline yes
last_seen_at string yes
created_at string yes
confirmed boolean yes
rate_usd_per_hour string yes matches ^[0-9]+\.[0-9]{4}$
private boolean yes
paused boolean yes
accept_byo boolean yes
trust integer yes
verified boolean yes
benchmarks array of MachineBenchmark yes
active_lease MachineLease or null yes
units_today integer yes
units_failed_today integer yes
earned_today_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
leases_lost_24h integer yes
start_trust integer yes
supply_token_id string or null yes
public_work boolean yes
public_work_reason paused, private, unbenchmarked, unjudged or null yes
recent_trust array of TrustEvent yes

Unknown fields are refused.

Field Type Required Default Constraints
name string or null no 1 to 64 characters
rate_usd_per_hour number or string or null no above 0; at most 1000; matches ^(?!^[-+.]*$)[+-]?0*\d*\.?\d{0,4}0*$
private boolean or null no
paused boolean or null no
accept_byo boolean or null no
Field Type Required Default Constraints
removed boolean yes
Field Type Required Default Constraints
rates array of SuggestedRate yes
per_vram_gb_usd string yes matches ^[0-9]+\.[0-9]{4}$
Field Type Required Default Constraints
supplier_max_share string yes matches ^-?[0-9]+\.[0-9]{6}$
start_trust integer yes
verified_trust integer yes
untrusted_hold_days integer yes
min_payout_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
payout_day integer yes
payout_hold_days integer yes
suggested_per_vram_gb_usd string yes matches ^[0-9]+\.[0-9]{4}$

Unknown fields are refused.

Field Type Required Default Constraints
country string no "US" matches ^[A-Z]{2}$
Field Type Required Default Constraints
url string yes
account_id string yes
Field Type Required Default Constraints
account_id string or null yes
country string or null yes
details_submitted boolean yes
payouts_enabled boolean yes
transfers_active boolean yes
Field Type Required Default Constraints
id string yes
period string yes
amount_usd string yes matches ^[0-9]+\.[0-9]{2}$
status pending, paid, failed yes
stripe_transfer_id string or null yes
failure string or null yes
created_at string yes
reversed_usd string yes matches ^[0-9]+\.[0-9]{2}$
Field Type Required Default Constraints
id string yes
node_id string yes
job_id string yes
unit_id string yes
amount_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
seconds string yes matches ^[0-9]+\.[0-9]{3}$
unit_price_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
rate_usd_per_hour string yes matches ^[0-9]+\.[0-9]{4}$
created_at string yes
held_until string or null yes
credit_only boolean yes
voided boolean yes
paid boolean yes
Field Type Required Default Constraints
day string yes
amount_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
units integer yes
Field Type Required Default Constraints
earned_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
unpaid_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
paid_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
voided_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
held_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
credit_only_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
min_payout_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
payout_hold_days integer yes
untrusted_hold_days integer yes
next_payout_on string yes
Field Type Required Default Constraints
org_id string yes
name string yes
balance_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
available_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
Field Type Required Default Constraints
id string yes
kind charge, credit yes
amount_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
job_id string or null yes
reference string yes
created_at string yes
Field Type Required Default Constraints
month string yes
spent_this_month_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
spent_last_month_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
units_this_month integer yes
days array of UsageDay yes
Field Type Required Default Constraints
id string yes
family string yes
resources object yes
unit_max_seconds integer yes
list_price_usd string yes matches ^[0-9]+\.[0-9]{6}$
unit TemplateUnit or null yes
nodes_online integer yes
Field Type Required Default Constraints
filename string yes 1 to 255 characters; matches ^[A-Za-z0-9][A-Za-z0-9._-]*$
bytes integer yes at least 1; at most 4294967296
kind manifest, input no "manifest"
Field Type Required Default Constraints
job_id string yes
units array of ResultUnit yes
next_after string or null yes
Field Type Required Default Constraints
amount_usd number or string yes at least 5; at most 10000; matches ^(?!^[-+.]*$)[+-]?0*\d*\.?\d{0,2}0*$
Field Type Required Default Constraints
pending integer yes
leased integer yes
done integer yes
failed integer yes

Unknown fields are refused.

Field Type Required Default Constraints
gpu GpuSpec no {}
cpu integer no 4 at least 1; at most 256
memory_gb number no 16 at least 0.0625; at most 4096
scratch_gb number no 50 at least 0; at most 16384

Unknown fields are refused.

Field Type Required Default Constraints
max_seconds integer no 300 at least 1; at most 86400
max_attempts integer no 3 at least 1; at most 10

Unknown fields are refused.

Field Type Required Default Constraints
max_per_unit number or string or null no above 0; at most 1000; matches ^(?!^[-+.]*$)[+-]?0*\d*\.?\d{0,6}0*$
Field Type Required Default Constraints
key string yes
sha256 string yes
bytes integer yes
Field Type Required Default Constraints
family string yes
claimed_units_per_hour string yes matches ^[0-9]+\.[0-9]{4}$
units_per_hour string yes matches ^[0-9]+\.[0-9]{4}$
cost_per_unit_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
list_price_usd string or null yes matches ^-?[0-9]+\.[0-9]{6}$
earns_per_unit_usd string or null yes matches ^-?[0-9]+\.[0-9]{6}$
offered_below_rate_usd_per_hour string or null yes matches ^[0-9]+\.[0-9]{4}$
Field Type Required Default Constraints
lease_id string yes
started_at string yes
units_leased integer yes
Field Type Required Default Constraints
at string yes
kind string yes
reason string yes
Field Type Required Default Constraints
gpu_class string yes
rate_usd_per_hour string yes matches ^[0-9]+\.[0-9]{4}$
Field Type Required Default Constraints
day string yes
spent_usd string yes matches ^-?[0-9]+\.[0-9]{6}$
units integer yes
Field Type Required Default Constraints
description string yes
Field Type Required Default Constraints
unit_id string yes
artifacts array of ResultArtifact yes

Unknown fields are refused.

Field Type Required Default Constraints
min_vram_gb number or null no at least 0; at most 1024
class string or null no at most 64 characters; matches ^[a-z0-9]+$
Field Type Required Default Constraints
name string yes
bytes integer yes
sha256 string yes
url string yes