Documentation

Overview

Use the service

Billing

Reference

Reference

POST /jobs

Submit an analytical job: a container image, a command and the resources it may use.

Syntax

POST https://grid-lab.zyxio.xyz/jobs
x-api-key: <key>
content-type: application/json

{"image": "<image>", "command": [...], "args": [...], "resources": {...}, "runningDeadlineSeconds": <s>,
 "retries": <n>, "priority": <n>, "capabilities": {"networkProfile": "none"}, "env": {}, "labels": {},
 "idempotencyKey": "<your key>"}

Request

NameWhereRequiredMeaning
x-api-keyheaderyes, or AuthorizationYour API key, or Authorization: Bearer <token> from Zyxio sign-in.
imagebodyyesA linux/amd64 image in an admitted repository on registry.grid.zyxio.xyz. Use a prebuilt runtime below or your custom image pinned by @sha256:.... A tag is resolved to a digest at admission.
commandbodyyes1 to 128 strings; replaces the image's entry point.
argsbodynoUp to 128 strings. Default [].
resourcesbodyyescpu, memory and ephemeralStorage, each with request and limit (request no more than limit). CPU 250m to 8; memory 256Mi to 16Gi; scratch 256Mi to 32Gi.
runningDeadlineSecondsbodyyes1 to 21,600: the longest one attempt may run.
retriesbodyno0 to 3 automatic replays of an attempt we lose because the machine it ran on ran short of resources (PLATFORM_EVICTED). An attempt that ends for any other reason is final; retry it yourself with POST /jobs/{jobId}/retry. Default 0.
prioritybodyno0 to 10; higher runs sooner. Default 0.
capabilitiesbodyyesAn object containing networkProfile: none, public-https or managed-services; see below.
envbodyyesUp to 100 variables; names like MY_VAR. Names starting AWS_, AZURE_, BROWSERGRID_, COMPUTE_ or GOOGLE_, and the system names HOME, HOSTNAME, PATH, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT, are reserved.
labelsbodyyesUp to 20 lower-case key and value pairs.
idempotencyKeybodyyes1 to 128 characters. The same key with the same body returns the existing job.

Any other field is refused; fields for capabilities that are not offered yet are refused with 422.

Network profiles

ProfileNetwork access
noneNo network egress.
public-httpsOutbound HTTPS on TCP port 443 to the public internet.
managed-servicesOutbound HTTPS on TCP port 443, plus in-cluster TCP access to managed PostgreSQL + PgBouncer on port 5432 and managed Valkey / Redis on port 6379.

The managed-services profile permits those service connections; you still need the instance's credentials. It does not grant general access to internal addresses. See Managed services.

Ready-to-use runtimes

These four prebuilt runtimes can be submitted immediately using the complete digest-pinned image reference.

Python 3.12

Includes polars, pyarrow, duckdb, pandas, psycopg, asyncpg, sqlalchemy, redis, httpx, pydantic, boto3, openai, mlflow-skinny, beautifulsoup4 and lxml.

registry.grid.zyxio.xyz/zyxioxyz/browsergrid-compute-python-3.12@sha256:5ca0336a5d50df4e398a635cf8766ebcd13ab681c064c3cf59577bbf87c5644c

Node.js 22

A prebuilt Node.js 22 runtime for JavaScript jobs.

registry.grid.zyxio.xyz/zyxioxyz/browsergrid-compute-node-22@sha256:e3e739db5f101a0bda9ce4427b4bdf96cf8f0febd47c685032c6ca6e09d1fde8

Alpine 3.21

Includes curl, jq and bash for shell jobs.

registry.grid.zyxio.xyz/zyxioxyz/browsergrid-compute-alpine-3.21@sha256:f6134bff601557bd19d05c5505ce9a349a518035943a66ef045b9d7f5521ff00

Site-QA

Includes playwright-core, a zero-trust authenticated crawler, jev visual and sitemap evaluation, and SARIF 2.1.0 and JUnit XML reporting.

registry.grid.zyxio.xyz/zyxioxyz/browsergrid-compute-site-qa@sha256:ef201048e6670458dbcd1c59c1694caed90dfdcdefa8e64dd4e496f09abd1179

Custom images

Custom linux/amd64 images pushed under zyxioxyz/* or tenants/* on registry.grid.zyxio.xyz are admitted by @sha256:... digest. Push access to the registry uses separate credentials. Images outside admitted repository prefixes are refused.

Response

202 Accepted with the new job's record, phase: "ACCEPTED". 200 OK with the existing record when you resend an idempotencyKey with the same body. The record's fields are on GET /jobs/{jobId}.

Errors

StatusBodyWhenWhat to do
400{"error": "INVALID_JOB_REQUEST"}A field is missing, out of bounds or unknown.Fix the body.
400{"error": "INVALID_IMAGE"}The image is not in an admitted repository, does not exist, or has no linux/amd64 image.Use an admitted image.
401{"error": "unauthorized"}No credential, or a key that is revoked, expired, wrong, or of a suspended account.Send a valid key.
503{"error": "accounting_unavailable"}Your key or Zyxio sign-in could not be checked because the account database did not answer in time. Nothing was done.Retry shortly; the same request is safe to resend.
402{"error": "insufficient_credit", "requiredMicros": ..., "availableMicros": ...}Your account is metered, credit enforcement is on, and the job's reservation exceeds your available credit (with monthly invoicing: what your monthly limit and the unpaid-usage ceiling leave; nothing while invoicing is paused or an invoice is past due).Top up, raise your monthly limit or pay the past-due invoice, or ask for less time or smaller resources.
402{"error": "daily_cap_exceeded", ...}The key's daily cap would be exceeded.Raise the cap, or wait for 00:00 UTC.
403{"error": "forbidden"}A valid Zyxio sign-in token whose identity has no account here, or whose account is suspended.Ask Zyxio to link your sign-in to your account, or use a key.
403{"error": "account_suspended"}Credit enforcement is on and the account a Zyxio-internal credential is billed to is suspended. Nothing was admitted. (A suspended customer's own keys and sign-in are refused before this, with 401 and 403 forbidden.)Ask Zyxio.
409{"error": "IDEMPOTENCY_CONFLICT"}You reused an idempotencyKey with a different body.Use a new key for a new job.
422{"error": "CAPABILITY_NOT_AVAILABLE", "capability": "..."}You asked for a capability that is not offered yet.Leave the field out.
503{"error": "COMPUTE_UNAVAILABLE"}Job tracking is not ready, or a dependency did not answer in time. Nothing was admitted.Retry after the retry-after seconds with the same idempotencyKey.

Example

curl -fsS https://grid-lab.zyxio.xyz/jobs \
  -H "x-api-key: $BROWSERGRID_API_KEY" \
  -H "content-type: application/json" \
  -d '{"image": "registry.grid.zyxio.xyz/zyxioxyz/browsergrid-compute-python-3.12@sha256:5ca0336a5d50df4e398a635cf8766ebcd13ab681c064c3cf59577bbf87c5644c",
       "command": ["python", "-c", "print(6 * 7)"],
       "resources": {"cpu": {"request": "2", "limit": "2"}, "memory": {"request": "4Gi", "limit": "4Gi"},
                     "ephemeralStorage": {"request": "256Mi", "limit": "1Gi"}},
       "runningDeadlineSeconds": 3600, "retries": 1,
       "capabilities": {"networkProfile": "none"}, "env": {}, "labels": {"run": "demo"},
       "idempotencyKey": "demo-2026-10-10-1"}'
{
  "jobId": "cj_0123456789abcdef0123456789abcdef",
  "attempt": 0,
  "imageDigest": "registry.grid.zyxio.xyz/zyxioxyz/browsergrid-compute-python-3.12@sha256:5ca0336a5d50df4e398a635cf8766ebcd13ab681c064c3cf59577bbf87c5644c",
  "phase": "ACCEPTED",
  "phaseTimestamps": {"ACCEPTED": "2026-10-10T12:00:00.000Z"},
  "executor": null,
  "attempts": [],
  "termination": null,
  "logsTruncated": false,
  "logs": {"available": false, "artifactId": null, "byteLength": null, "contentType": null},
  "artifacts": []
}

Billing

At submission the job reserves one attempt's longest cost, on the CPU and memory you request: (vCPU × €0.04 + GiB × €0.0064) per hour × runningDeadlineSeconds, whatever retries you set. The example reserves (2 × 40,000 + 4 × 6,400) µ€ × 1 hour = 105,600 µ€ (€0.1056).

One attempt is all a submission can be billed for: a replay follows only an eviction, which is free, and every billed reason ends the job. So the attempts before the billed one leave the reservation untouched, the billed one is charged against it, and what it does not use returns to your available credit when the job finishes. retries changes neither what is held nor what the job can cost.

Each attempt is charged for the time from its container's start until it finishes, up to runningDeadlineSeconds, rounded once to the micro-euro, when its termination.reason is one you caused: WORKLOAD_SUCCEEDED, WORKLOAD_FAILED, PLATFORM_OOM (your container went over its own memory limit), RUNNING_DEADLINE_EXCEEDED (your own deadline) or CANCELLED. Every other reason is a failure on our side and free, and so are queueing, start-up and our replays. Resending the same idempotencyKey reserves nothing. No attempt is ever charged more than the reservation set aside for it. Attempts are settled by a periodic pass over the grid's records, so a charge, and the return of what the job did not use to your available credit, appears up to one settlement interval (30 seconds) after the attempt or the job finishes.

See also

Analytical jobs, GET /jobs/{jobId}, GET /jobs/{jobId}/logs, POST /jobs/{jobId}/cancel.