$GPUFARM IS LIVE
GPUFarm
Developers · API

REST API reference

Every endpoint below is live on this deployment at https://robingpu.farm/v1, serving Robinhood Chain (chain 4663). JSON in, JSON out. Create jobs, fund their escrow from your own wallet, tail logs and download verified results.

Authentication#

Create a key in Dashboard → API keys and send it as a bearer token. Keys look like gf_live_… on mainnet and gf_test_… on testnet and local chains; this deployment accepts gf_live_… keys only. The full key is shown once — GPUFarm stores only its SHA-256.

shell
curl https://robingpu.farm/v1/jobs \
  -H "Authorization: Bearer $GPUFARM_API_KEY"
ScopeGrants
jobs:createCreate and cancel jobs
jobs:readRead jobs, logs and metrics
artifacts:readDownload artifacts and results
billing:readRead billing history
Keys are server-side secrets. Endpoints that create or change state (POST) send no CORS headers, so browsers can't call them cross-origin. Jobs a key creates are escrowed from the key owner's primary wallet.

Conventions#

TopicRule
Money (USD)Integer micro-dollars in …MicroUsd fields: 1 USD = 1,000,000. Never floats.
Token amountsBase units as decimal strings (they can exceed 2^53): "maxPayment": "1250000".
TimeISO-8601 UTC strings. Absent values are null, never omitted.
PaginationList responses are { object: "list", data, nextCursor }; pass ?cursor= to continue.
Request idsEvery response carries X-Request-Id (send your own to correlate). Quote it in support requests.
IdempotencySend Idempotency-Key on POST /v1/jobs; a retry with the same key and body returns the original job.
VersionResponses carry GPUFarm-Version: 2026-10-01.
PrivacyResponses never include host IPs, exact locations, machine usernames or LAN details — regions are coarse.

Endpoints#

GET

/v1

public · key optional
What this API serves: version, network (chain id, whether values are real, the key prefix it accepts), scopes, rate limits and the endpoint list. Useful as a health check.
shell
curl https://robingpu.farm/v1
GET

/v1/capacity

public · key optional
Live, benchmark-verified capacity grouped per farm (or single machine) and GPU class — the same data as the marketplace. An API key is optional (it raises your rate limit); a key that is sent must be valid.
QueryExampleMeaning
modelrtx-4090GPU class id
minVram24Minimum VRAM per GPU, GB
maxPrice0.60Max USD per GPU-hour
farmnorthgridFarm slug
regioneurope-west or EuropeA region key (us-east, us-west, us-central, canada, …) or region group
minUptime99Minimum 30-day uptime %
workloadinferenceinference, image_generation, video, rendering, batch, fine_tuning, development, custom
cuda12.2Minimum CUDA version
availabilityavailableOnly offers with idle GPUs now
tierAMinimum benchmark tier (S, A, B, C)
sortprice_ascavailable · price_asc · price_desc · vram · uptime · count
limit501–500, default 200
shell
curl "https://robingpu.farm/v1/capacity?model=rtx-4090&availability=available&sort=price_asc"
200 · example response (abridged)
{
  "object": "list",
  "chainId": 4663,
  "generatedAt": "2026-10-01T12:00:00.000Z",
  "data": [{
    "id": "farm:6b1d…:rtx-4090:europe-west",
    "kind": "farm",
    "farm": { "slug": "northgrid", "name": "NorthGrid" },
    "provider": "NorthGrid",
    "gpu": { "classId": "rtx-4090", "label": "RTX 4090", "model": "NVIDIA GeForce RTX 4090", "vendor": "nvidia",
             "family": "consumer", "vramBytes": 25757220864, "cudaVersion": "12.4", "driverVersion": "550.54.15" },
    "count": 8, "available": 6, "busy": 2,
    "maxAvailablePerMachine": 4, "maxPerMachine": 4, "machines": 2,
    "combinedVramBytes": 206057766912,
    "benchmarkTier": "A",
    "uptimePct": 99.2,
    "region": { "key": "europe-west", "label": "Europe West", "group": "Europe" },
    "price": { "perGpuHourMicroUsd": 460000, "maxPerGpuHourMicroUsd": 460000, "minBillingSeconds": 60 },
    "queue": 0,
    "status": "AVAILABLE",
    "workloads": null,
    "simulated": false
  }],
  "nextCursor": null
}
GET

/v1/pricing

public · key optional
Live per-class prices (min / median / max per GPU-hour over online, priced GPUs), the platform fee, minimum billing units, the formula and the accepted payment assets.
shell
curl https://robingpu.farm/v1/pricing
200 · example response (abridged)
{
  "object": "pricing",
  "chainId": 4663,
  "currency": "USD",
  "unit": "micro-USD per GPU-hour (1 USD = 1,000,000)",
  "platformFeeBps": 500,
  "minBillingSeconds": { "min": 60, "max": 60 },
  "paymentAssets": [
    { "kind": "eth", "token": "0x0000000000000000000000000000000000000000", "symbol": "ETH", "decimals": 18 },
    { "kind": "stable", "token": "0x…", "symbol": "USDG", "decimals": 6 }
  ],
  "classes": [{
    "classId": "h100-80gb", "label": "H100 80GB", "family": "datacenter", "vramBytes": 85520809984,
    "gpusOnline": 4, "gpusBusy": 1, "gpusAvailable": 3, "gpusPriced": 4,
    "minPerGpuHourMicroUsd": 2790000, "medianPerGpuHourMicroUsd": 2840000, "maxPerGpuHourMicroUsd": 2900000
  }]
}
POST

/v1/jobs

scope: jobs:create
Creates a job from a spec: runs the workload policy, prices it against live capacity, locks the escrow terms and returns the job, the estimate and the transactions that fund the escrow from your wallet. Nothing is charged until you fund it. Unknown fields are rejected so a typo never silently drops a setting.
FieldTypeNotes
imagestringRequired. Container image, e.g. pytorch/pytorch:2.5.1-cuda12.4-cudnn9-runtime. Pin a digest with image@sha256:… or imageDigest.
commandstring[]The container's full argv: command[0] is the executable and replaces the image's ENTRYPOINT (and CMD); the rest are its arguments, passed as-is with no shell — use ["sh", "-c", "…"] for pipes or variables. Omit it (or send []) to run the image's own ENTRYPOINT/CMD. ≤ 128 arguments, ≤ 32 KB total.
gpuobjectRequired. count 1–16 (one machine), minimumVramGb or minimumVramBytes, optional modelAllowlist of class ids.
workloadTypestringDefault custom. One of inference, image_generation, video, rendering, batch, fine_tuning, development, custom.
maxRuntimeSecondsint60–604800. Default 3600. The container is stopped at this limit.
maxPricePerGpuHournumber | stringUSD cap, e.g. 0.65 (or maxPricePerGpuHourMicroUsd). Default: the highest current price among offers that fit the whole job.
estRuntimeobject{ minSeconds, maxSeconds } for the estimate range.
paymentTokenstring"eth" or "stable" (USDG).
envobject≤ 32 non-secret variables. Names that look like secrets are rejected — hosts can see env.
networkPolicyobjectDefault { "mode": "none" }. { "mode": "allowlist", "allow": ["huggingface.co"] } for public DNS names only.
inputsarray[{ artifactId, mountName }] — files you uploaded, mounted read-only at /input/<mountName>.
outputRulesarrayDefault [{ "path": "/output", "maxBytes": 1073741824 }]; up to 5 GiB per rule.
regionPreferencestringCoarse region key; a preference, not a guarantee.
deterministicbooleanDeclare the output reproducible (enables result verification where a verifier exists).
cpuCores, ramBytesintOptional container limits.
titlestring≤ 120 characters.
request
curl https://robingpu.farm/v1/jobs \
  -H "Authorization: Bearer $GPUFARM_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: render-batch-0042" \
  -d '{
    "workloadType": "inference",
    "image": "pytorch/pytorch:2.5.1-cuda12.4-cudnn9-runtime",
    "command": ["python", "-c", "import torch; print(torch.cuda.get_device_name(0))"],
    "gpu": { "count": 1, "minimumVramGb": 24 },
    "maxRuntimeSeconds": 900,
    "maxPricePerGpuHour": 0.65,
    "paymentToken": "stable"
  }'
201 · example response (abridged)
{
  "object": "job.created",
  "job": { "object": "job", "id": "9b2f…", "status": "CREATED", "verificationLevel": null,
           "pricing": { "maxPricePerGpuHourMicroUsd": 650000, "minBillingSeconds": 60, "platformFeeBps": 500,
                        "estimateLowMicroUsd": 11376, "estimateHighMicroUsd": 170625, "maxCostMicroUsd": 170625 },
           "payment": { "token": "0x…", "symbol": "USDG", "decimals": 6, "maxPayment": "170625", "escrowJobKey": "0x…" },
           "links": { "dashboard": "https://robingpu.farm/job/9b2f…", "logs": "https://robingpu.farm/v1/jobs/9b2f…/logs", "funding": "https://robingpu.farm/v1/jobs/9b2f…/funding" } },
  "estimate": { "lowMicroUsd": 11376, "highMicroUsd": 170625, "assumptions": ["…"], "matchedClasses": ["…"] },
  "policy": { "verdict": "allowed", "findings": [] },
  "funding": { "object": "funding", "signer": "0x…", "calls": [ { "title": "Approve USDG for the escrow", "to": "0x…", "data": "0x…", "value": "0" },
                                                               { "title": "Fund escrow", "to": "0x…", "data": "0x…", "value": "0" } ] },
  "fundingUnavailable": null,
  "defaults": [],
  "idempotentReplay": false
}

Fund the job by sending each call in funding.calls from the signer wallet (skip an approve when your allowance already covers it), then confirm the transaction. GPUFarm reads the JobFunded event from the chain itself — it never trusts a client's claim — and the job moves to FUNDED → QUEUED. The SDK does all of this with a viem wallet.

GET

/v1/jobs

scope: jobs:read
Your jobs, newest first. status takes a comma-separated list (CREATED, FUNDED, QUEUED, MATCHING, …); limit 1–100 (default 20); cursor from the previous page.
shell
curl "https://robingpu.farm/v1/jobs?status=RUNNING,QUEUED&limit=20" \
  -H "Authorization: Bearer $GPUFARM_API_KEY"
GET

/v1/jobs/:id

scope: jobs:read
Status, the assignment (farm, GPU, region, price — never a host's IP or location), verification level, host vs server result hash, final cost, artifacts and the escrow receipt with onchain transaction hashes.
shell
curl https://robingpu.farm/v1/jobs/$JOB_ID \
  -H "Authorization: Bearer $GPUFARM_API_KEY"
200 · fields you'll use most (abridged)
{
  "object": "job", "id": "9b2f…", "status": "COMPLETED",
  "verificationLevel": "EXECUTION_VERIFIED",
  "assignment": { "gpu": { "model": "NVIDIA GeForce RTX 4090", "modelClass": "rtx-4090", "count": 1 },
                  "farm": { "slug": "northgrid", "name": "NorthGrid" }, "region": "europe-west",
                  "pricePerGpuHourMicroUsd": 460000, "startedAt": "…", "finishedAt": "…", "exitCode": 0 },
  "cost": { "billableGpuSeconds": 360, "computeMicroUsd": 46000, "feeMicroUsd": 2300, "totalMicroUsd": 48300, "finalPayment": "48300" },
  "result": { "hostHash": "4f1c…", "serverHash": "4f1c…", "hashesMatch": true, "outputArtifactId": "c3a9…", "logArtifactId": "71de…" },
  "receipt": { "jobKey": "0x…", "status": "completed", "amount": "48300", "computeSeconds": 360, "resultHash": "0x4f1c…",
               "challengeEndsAt": "…", "transactions": { "fund": "0x…", "completion": "0x…", "release": null, "refund": null } },
  "artifacts": [{ "id": "c3a9…", "kind": "output", "filename": "output.tar", "sizeBytes": 10240, "sha256": "4f1c…" }]
}
GET

/v1/jobs/:id/logs

scope: jobs:read
Log lines the host streamed, oldest first. Tail a running job by polling with the returned nextCursor (it stays put when nothing new arrived). limit 1–1000 (default 500); stream = stdout | stderr | system.
shell
curl "https://robingpu.farm/v1/jobs/$JOB_ID/logs?cursor=0&limit=500" \
  -H "Authorization: Bearer $GPUFARM_API_KEY"
200
{ "object": "list", "jobStatus": "RUNNING", "nextCursor": "1842",
  "data": [{ "id": 1841, "assignmentId": "…", "seq": 12, "stream": "stdout", "line": "step 120/400 loss=0.412", "at": "…" }] }
GET

/v1/jobs/:id/funding

scope: jobs:create
The calls that fund this job's escrow from the customer wallet ({ to, data, value }): approve + createJob for the stablecoin, createJob with value for ETH. Send them in order from signer.
shell
curl https://robingpu.farm/v1/jobs/$JOB_ID/funding \
  -H "Authorization: Bearer $GPUFARM_API_KEY"
POST

/v1/jobs/:id/fund-confirm

scope: jobs:create
After your createJob transaction is mined, send its hash. GPUFarm fetches the receipt and its JobFunded event from the chain (the hash is only a pointer — nothing in the request is trusted), checks customer, token, amount and job hash, and queues the job. Returns 202 with Retry-After while the transaction is still pending; idempotent.
shell
curl -X POST https://robingpu.farm/v1/jobs/$JOB_ID/fund-confirm \
  -H "Authorization: Bearer $GPUFARM_API_KEY" -H "Content-Type: application/json" \
  -d '{"txHash": "0x…"}'
200
{ "object": "funding.confirmation", "status": "confirmed", "message": "…", "job": { "id": "9b2f…", "status": "QUEUED", … } }
POST

/v1/jobs/:id/cancel

scope: jobs:create
Cancel before a host accepts the job. A CREATED job is simply canceled; a funded/queued job is canceled and its escrow refund is authorized (claim it from your wallet). Running jobs return 409.
shell
curl -X POST https://robingpu.farm/v1/jobs/$JOB_ID/cancel \
  -H "Authorization: Bearer $GPUFARM_API_KEY" -H "Content-Type: application/json" \
  -d '{"reason": "requirements changed"}'
GET

/v1/artifacts/:id

scope: artifacts:read
Download an input you uploaded or an output/log of one of your jobs. Default: a 302 to a signed URL valid for 120 seconds, with X-Artifact-Sha256 and X-Artifact-Size headers. With ?format=json (or Accept: application/json): metadata plus the signed URL.
shell
curl -L -o output.tar https://robingpu.farm/v1/artifacts/$ARTIFACT_ID \
  -H "Authorization: Bearer $GPUFARM_API_KEY"

# verify what you downloaded against the job's result hash
sha256sum output.tar
GET

/v1/billing

scope: billing:read
One row per funded job — farm, GPU, duration, compute cost, fee, total, escrowed, paid, refunded and the onchain transactions — plus month-to-date totals. limit 1–200 (default 50).
shell
curl "https://robingpu.farm/v1/billing?limit=50" \
  -H "Authorization: Bearer $GPUFARM_API_KEY"

Errors#

Every error has the same shape and an HTTP status that matches its code.

error body
{ "error": { "code": "validation_error", "message": "gpu.count: At most 16 GPUs (all on one machine in V1)", "requestId": "req_…", "details": [ … ] } }
CodeHTTPWhen
invalid_request400A parameter is malformed (bad cursor, status, id…).
invalid_json400The body isn't valid JSON.
validation_error422The job spec failed validation; details lists each field.
policy_rejected422The workload policy refused the job (banned image, mining/cracking signatures, privilege request, LAN egress…).
missing_api_key401No Authorization header.
invalid_api_key401Malformed or unknown key.
revoked_api_key401The key was revoked in the dashboard.
wrong_environment401A gf_test_ key on mainnet or a gf_live_ key on a test network.
insufficient_scope403The key lacks the scope this endpoint needs.
account_suspended403The account behind the key is suspended.
forbidden403Not allowed (e.g. someone else's job).
not_found404No such job/artifact on your account (never reveals other accounts' ids).
method_not_allowed405Wrong HTTP method for this path.
conflict409State conflict — e.g. canceling a running job, or an Idempotency-Key reused with a different body.
gone410The artifact expired.
payload_too_large413Request body over 256 KiB.
rate_limited429Too many requests; wait for Retry-After seconds.
internal500Server error. Quote the request id.
unavailable503Database, storage, chain RPC or contracts unavailable on this deployment.

Rate limits#

Limits are per API key (anonymous calls to public endpoints are limited per hashed client address — IPs are never stored). Responses carry X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; a 429 adds Retry-After.

BucketLimit
Any endpoint, per key300 requests / 60 s
Public endpoints without a key60 requests / 60 s
POST /v1/jobs30 jobs / 60 s
POST /v1/jobs/:id/fund-confirm30 requests / 60 s
GET /v1/artifacts/:id120 downloads / 60 s