REST API reference
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.
curl https://robingpu.farm/v1/jobs \
-H "Authorization: Bearer $GPUFARM_API_KEY"| Scope | Grants |
|---|---|
jobs:create | Create and cancel jobs |
jobs:read | Read jobs, logs and metrics |
artifacts:read | Download artifacts and results |
billing:read | Read billing history |
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#
| Topic | Rule |
|---|---|
| Money (USD) | Integer micro-dollars in …MicroUsd fields: 1 USD = 1,000,000. Never floats. |
| Token amounts | Base units as decimal strings (they can exceed 2^53): "maxPayment": "1250000". |
| Time | ISO-8601 UTC strings. Absent values are null, never omitted. |
| Pagination | List responses are { object: "list", data, nextCursor }; pass ?cursor= to continue. |
| Request ids | Every response carries X-Request-Id (send your own to correlate). Quote it in support requests. |
| Idempotency | Send Idempotency-Key on POST /v1/jobs; a retry with the same key and body returns the original job. |
| Version | Responses carry GPUFarm-Version: 2026-10-01. |
| Privacy | Responses never include host IPs, exact locations, machine usernames or LAN details — regions are coarse. |
Endpoints#
curl https://robingpu.farm/v1| Query | Example | Meaning |
|---|---|---|
model | rtx-4090 | GPU class id |
minVram | 24 | Minimum VRAM per GPU, GB |
maxPrice | 0.60 | Max USD per GPU-hour |
farm | northgrid | Farm slug |
region | europe-west or Europe | A region key (us-east, us-west, us-central, canada, …) or region group |
minUptime | 99 | Minimum 30-day uptime % |
workload | inference | inference, image_generation, video, rendering, batch, fine_tuning, development, custom |
cuda | 12.2 | Minimum CUDA version |
availability | available | Only offers with idle GPUs now |
tier | A | Minimum benchmark tier (S, A, B, C) |
sort | price_asc | available · price_asc · price_desc · vram · uptime · count |
limit | 50 | 1–500, default 200 |
curl "https://robingpu.farm/v1/capacity?model=rtx-4090&availability=available&sort=price_asc"{
"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
}curl https://robingpu.farm/v1/pricing{
"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
}]
}| Field | Type | Notes |
|---|---|---|
image | string | Required. Container image, e.g. pytorch/pytorch:2.5.1-cuda12.4-cudnn9-runtime. Pin a digest with image@sha256:… or imageDigest. |
command | string[] | 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. |
gpu | object | Required. count 1–16 (one machine), minimumVramGb or minimumVramBytes, optional modelAllowlist of class ids. |
workloadType | string | Default custom. One of inference, image_generation, video, rendering, batch, fine_tuning, development, custom. |
maxRuntimeSeconds | int | 60–604800. Default 3600. The container is stopped at this limit. |
maxPricePerGpuHour | number | string | USD cap, e.g. 0.65 (or maxPricePerGpuHourMicroUsd). Default: the highest current price among offers that fit the whole job. |
estRuntime | object | { minSeconds, maxSeconds } for the estimate range. |
paymentToken | string | "eth" or "stable" (USDG). |
env | object | ≤ 32 non-secret variables. Names that look like secrets are rejected — hosts can see env. |
networkPolicy | object | Default { "mode": "none" }. { "mode": "allowlist", "allow": ["huggingface.co"] } for public DNS names only. |
inputs | array | [{ artifactId, mountName }] — files you uploaded, mounted read-only at /input/<mountName>. |
outputRules | array | Default [{ "path": "/output", "maxBytes": 1073741824 }]; up to 5 GiB per rule. |
regionPreference | string | Coarse region key; a preference, not a guarantee. |
deterministic | boolean | Declare the output reproducible (enables result verification where a verifier exists). |
cpuCores, ramBytes | int | Optional container limits. |
title | string | ≤ 120 characters. |
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"
}'{
"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.
status takes a comma-separated list (CREATED, FUNDED, QUEUED, MATCHING, …); limit 1–100 (default 20); cursor from the previous page.curl "https://robingpu.farm/v1/jobs?status=RUNNING,QUEUED&limit=20" \
-H "Authorization: Bearer $GPUFARM_API_KEY"curl https://robingpu.farm/v1/jobs/$JOB_ID \
-H "Authorization: Bearer $GPUFARM_API_KEY"{
"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…" }]
}nextCursor (it stays put when nothing new arrived). limit 1–1000 (default 500); stream = stdout | stderr | system.curl "https://robingpu.farm/v1/jobs/$JOB_ID/logs?cursor=0&limit=500" \
-H "Authorization: Bearer $GPUFARM_API_KEY"{ "object": "list", "jobStatus": "RUNNING", "nextCursor": "1842",
"data": [{ "id": 1841, "assignmentId": "…", "seq": 12, "stream": "stdout", "line": "step 120/400 loss=0.412", "at": "…" }] }{ to, data, value }): approve + createJob for the stablecoin, createJob with value for ETH. Send them in order from signer.curl https://robingpu.farm/v1/jobs/$JOB_ID/funding \
-H "Authorization: Bearer $GPUFARM_API_KEY"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.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…"}'{ "object": "funding.confirmation", "status": "confirmed", "message": "…", "job": { "id": "9b2f…", "status": "QUEUED", … } }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.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"}'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.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.tarlimit 1–200 (default 50).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": { "code": "validation_error", "message": "gpu.count: At most 16 GPUs (all on one machine in V1)", "requestId": "req_…", "details": [ … ] } }| Code | HTTP | When |
|---|---|---|
invalid_request | 400 | A parameter is malformed (bad cursor, status, id…). |
invalid_json | 400 | The body isn't valid JSON. |
validation_error | 422 | The job spec failed validation; details lists each field. |
policy_rejected | 422 | The workload policy refused the job (banned image, mining/cracking signatures, privilege request, LAN egress…). |
missing_api_key | 401 | No Authorization header. |
invalid_api_key | 401 | Malformed or unknown key. |
revoked_api_key | 401 | The key was revoked in the dashboard. |
wrong_environment | 401 | A gf_test_ key on mainnet or a gf_live_ key on a test network. |
insufficient_scope | 403 | The key lacks the scope this endpoint needs. |
account_suspended | 403 | The account behind the key is suspended. |
forbidden | 403 | Not allowed (e.g. someone else's job). |
not_found | 404 | No such job/artifact on your account (never reveals other accounts' ids). |
method_not_allowed | 405 | Wrong HTTP method for this path. |
conflict | 409 | State conflict — e.g. canceling a running job, or an Idempotency-Key reused with a different body. |
gone | 410 | The artifact expired. |
payload_too_large | 413 | Request body over 256 KiB. |
rate_limited | 429 | Too many requests; wait for Retry-After seconds. |
internal | 500 | Server error. Quote the request id. |
unavailable | 503 | Database, 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.
| Bucket | Limit |
|---|---|
| Any endpoint, per key | 300 requests / 60 s |
| Public endpoints without a key | 60 requests / 60 s |
| POST /v1/jobs | 30 jobs / 60 s |
| POST /v1/jobs/:id/fund-confirm | 30 requests / 60 s |
| GET /v1/artifacts/:id | 120 downloads / 60 s |