Documentation

Overview

Use the service

Billing

Reference

Use the service

Managed services

Provision PostgreSQL + PgBouncer, MLflow, LiteLLM or Valkey / Redis in five size tiers with 1 to 8 replicas; obtain credentials and manage your instance from the panel or API.

All four services are live and self-service through your managed services or POST /managed-services/instances. Web app hosting is coming; see Web apps, below. Setup requires an active account with available credit or monthly invoicing capacity.

Services and prices

ServicePlanTier-1 base priceIncluded
PostgreSQL + PgBouncerpostgres.plan€49.00 per workspace-monthAn isolated database and role, transaction pooling with 4 backend connections, and TLS with sslmode=verify-full.
MLflowmlflow.plan€39.00 per workspace-monthAn isolated experiment and artifact prefix through the control-plane tracking gateway, authenticated with your Browsergrid API key.
LiteLLMlitellm.plan€29.00 per workspace-monthAn OpenAI-compatible gateway binding for /v1/models, /v1/chat/completions and /v1/embeddings, authenticated with your Browsergrid API key.
Valkey / Redisredis.plan€15.00 per workspace-monthA dedicated ACL user bg_r_<id> and isolated key and pub/sub prefix bg:<id>:*, with dangerous and administrative commands blocked.

Rate card 2026-10-14.commercial-1 prorates each plan per active millisecond of its UTC calendar month. Requests, status reads, credential downloads and lifecycle API calls have no separate fee. An active service accrues plan charges even while idle; suspend or retire it to stop future accrual. See Pricing units and Credit and billing.

Provision and download credentials

Use Bash with curl, jq and uuidgen, and set BROWSERGRID_API_KEY as in the Quickstart. Change SERVICE to postgres, redis, mlflow or litellm. Names are 1 to 100 characters, and the optional note is at most 2,000 characters; neither should contain secrets.

SERVICE=postgres # postgres, redis, mlflow or litellm
SERVICE_REQUEST_ID=$(uuidgen)
SERVICE_REQUEST=$(jq -n --arg requestId "$SERVICE_REQUEST_ID" --arg service "$SERVICE" \
  '{requestId: $requestId, service: $service, name: ("example-" + $service), note: "Application workspace"}')
SERVICE_INSTANCE=$(curl -fsS https://grid-lab.zyxio.xyz/managed-services/instances \
  -H "x-api-key: $BROWSERGRID_API_KEY" \
  -H "content-type: application/json" \
  -d "$SERVICE_REQUEST")
INSTANCE_ID=$(printf '%s' "$SERVICE_INSTANCE" | jq -er '.id')
printf '%s\n' "$SERVICE_INSTANCE" | jq '{id, service, state, requestedAction, statusNote}'

Omitting profile selects the private platform. Keep SERVICE_REQUEST_ID and the same body when retrying a request after a connection failure: the same request returns the existing instance. Use a new UUID for a new instance.

A 201 response means the instance is ready; 202 means it is not ready. Poll its status until setup completes. If it becomes blocked, read statusNote and open your managed services.

while :; do
  SERVICE_INSTANCE=$(curl -fsS "https://grid-lab.zyxio.xyz/managed-services/instances/$INSTANCE_ID" \
    -H "x-api-key: $BROWSERGRID_API_KEY") || break
  printf '%s\n' "$SERVICE_INSTANCE" | jq '{state, requestedAction, statusNote}'
  SERVICE_STATE=$(printf '%s' "$SERVICE_INSTANCE" | jq -r '.state')
  case "$SERVICE_STATE" in
    ready|blocked|suspended|retired) break ;;
  esac
  sleep 2
done

Once state is ready and requestedAction is none, download the credentials. The subshell saves them with private file permissions; move the file into your application's secret store.

printf '%s' "$SERVICE_INSTANCE" | jq -e '.state == "ready" and .requestedAction == "none"' >/dev/null && (
  umask 077
  curl -fsS -X POST "https://grid-lab.zyxio.xyz/managed-services/instances/$INSTANCE_ID/credentials" \
    -H "x-api-key: $BROWSERGRID_API_KEY" \
    -o "managed-service-$INSTANCE_ID.json"
)

The private platform and awow-azure are separate profiles. Self-service examples use the default private platform. The Azure profile requires its own deployment and qualification; selecting it does not move data between platforms.

Connect

Read the instance's binding for its endpoint, authentication, network access, configuration, limitations and verification time. Instance status and lists contain no passwords. Credential downloads are audited and require both account ownership and an access grant for the calling identity.

PostgreSQL + PgBouncer

Use the downloaded database, username, password and CA certificate with sslmode=verify-full. The Tier-1 pool uses transaction mode and 4 backend connections. Session-dependent operations such as session locks and LISTEN need a separately supported configuration. Pooling bounds connections; it does not distribute writes between servers.

MLflow

Use the downloaded HTTPS endpoint as your tracking URI and your Browsergrid API key as its bearer token. The control-plane tracking gateway scopes access to the instance's experiment and artifact prefix. Follow the binding's instructions for its experiment and supported tracking operations.

LiteLLM

Use the downloaded HTTPS endpoint as the gateway base and your Browsergrid API key as its bearer token. The supported OpenAI-compatible routes are /v1/models, /v1/chat/completions and /v1/embeddings; only approved upstream models are available. The gateway plan and upstream model consumption are separate charges.

Valkey / Redis

Use the downloaded endpoint, named ACL username and password with a Redis client. Prefix every key and pub/sub channel with the returned keyPrefix; access outside it is denied. Administrative and dangerous commands are blocked. Follow the binding's memory and durability limitations; do not assume a cache is a durable database.

Connect from an analytical job

Select "networkProfile": "managed-services" to allow outbound HTTPS on port 443 and in-cluster TCP access to managed PostgreSQL + PgBouncer on port 5432 and Valkey / Redis on port 6379. Service credentials are still required. PostgreSQL and Redis endpoints are private; run these clients inside a job with that profile.

This example uses the PostgreSQL instance and credentials file created above. The prebuilt Python runtime includes psycopg. Credentials travel in the job's environment, so use your own instance's file and do not print it or commit it to source control.

SERVICE_CHECK_CODE='import json, os, tempfile
import psycopg
c = json.loads(os.environ["SERVICE_CREDENTIALS"])
with tempfile.NamedTemporaryFile(mode="w") as ca:
    ca.write(c["caCertificate"])
    ca.flush()
    with psycopg.connect(c["endpoint"], dbname=c["database"], user=c["username"], password=c["password"], sslmode="verify-full", sslrootcert=ca.name) as conn:
        print(conn.execute("select 6 * 7").fetchone()[0])'
jq -n --slurpfile credentials "managed-service-$INSTANCE_ID.json" \
  --arg code "$SERVICE_CHECK_CODE" --arg key "service-check-$(uuidgen)" \
  '{image: "registry.grid.zyxio.xyz/zyxioxyz/browsergrid-compute-python-3.12@sha256:5ca0336a5d50df4e398a635cf8766ebcd13ab681c064c3cf59577bbf87c5644c",
    command: ["python", "-c", $code],
    resources: {cpu: {request: "1", limit: "1"}, memory: {request: "1Gi", limit: "1Gi"},
      ephemeralStorage: {request: "256Mi", limit: "1Gi"}},
    runningDeadlineSeconds: 60,
    capabilities: {networkProfile: "managed-services"},
    env: {SERVICE_CREDENTIALS: ($credentials[0] | tojson)}, labels: {}, idempotencyKey: $key}' |
  curl -fsS https://grid-lab.zyxio.xyz/jobs \
    -H "x-api-key: $BROWSERGRID_API_KEY" \
    -H "content-type: application/json" --data-binary @-

Poll the returned job ID and read its logs as in the Quickstart. The job pays the usual CPU and memory charges in addition to the managed service plan. For Valkey / Redis, the same runtime includes redis; authenticate with the delivered username and password and use its keyPrefix on every key and channel.

Sizes and replicas

Each service comes in five size tiers, tiny, starter, standard, pro and scale, and takes 1 to 8 replicas. Ask for both in the instance's config, beside the service's other settings, for example "config": {"tier": "starter", "replicas": 2} in the request body above. The request records the tier and replica count you ask for.

standard is the Tier-1 base plan priced under Services and prices. The other tiers' prices are proposed, tiny from €2.00 to €3.50 per month depending on the service, and no rate card carries them yet: until one does, an instance of any tier is billed at its service's Tier-1 base price, prorated per active millisecond.

A PATCH replaces an instance's whole config. To resize, read the current config, change tier, replicas or both, and send all of it back:

SERVICE_CONFIG=$(curl -fsS "https://grid-lab.zyxio.xyz/managed-services/instances/$INSTANCE_ID" \
  -H "x-api-key: $BROWSERGRID_API_KEY" | jq -c '.config + {tier: "starter", replicas: 3}')
jq -n --argjson config "$SERVICE_CONFIG" '{config: $config}' |
  curl -fsS -X PATCH "https://grid-lab.zyxio.xyz/managed-services/instances/$INSTANCE_ID" \
    -H "x-api-key: $BROWSERGRID_API_KEY" \
    -H "content-type: application/json" --data-binary @-

The response is the instance with its new revision. On a ready instance, a changed config requests a resize: poll the instance as under Provision and download credentials until requestedAction is none. Fulfillment depends on the service and profile, and more replicas do not promise automatic failover: the instance's recorded limitations and qualification define what it supports.

Web apps

Web app hosting is coming: it is not offered yet, and no rate card prices it. A web app will be a webapp instance that serves one linux/amd64 container image, pinned by its @sha256: digest, on its port (default 3000), with the same tiers and replicas, for example "config": {"image": "<repository>@sha256:<64 hex>", "port": 3000, "tier": "tiny", "replicas": 2}. Its binding will hold the web app's HTTPS endpoint.

Manage an instance

Lifecycle changes require the latest positive integer revision, the requested action and a non-empty note. This example rotates credentials; set SERVICE_ACTION to the action you intend to request.

ActionAllowed stateEffect when complete
rotatereadyRefresh access or credentials; download credentials again before reconnecting.
suspendreadyDisable service access and stop active plan accrual.
resumesuspendedRestore service access and resume plan accrual; download credentials again.
retireready or suspendedEnd access and stop plan accrual permanently. Retirement does not promise data deletion.
SERVICE_ACTION=rotate # rotate, suspend, resume or retire
SERVICE_INSTANCE=$(curl -fsS "https://grid-lab.zyxio.xyz/managed-services/instances/$INSTANCE_ID" \
  -H "x-api-key: $BROWSERGRID_API_KEY")
SERVICE_REVISION=$(printf '%s' "$SERVICE_INSTANCE" | jq -er '.revision')
jq -n --argjson revision "$SERVICE_REVISION" --arg action "$SERVICE_ACTION" \
  '{revision: $revision, action: $action, note: ("Requested " + $action + " from the command line")}' |
  curl -fsS "https://grid-lab.zyxio.xyz/managed-services/instances/$INSTANCE_ID/actions" \
    -H "x-api-key: $BROWSERGRID_API_KEY" \
    -H "content-type: application/json" --data-binary @-

A 200 response records the action and returns the latest instance; it does not guarantee completion. Poll GET /managed-services/instances/{instanceId} until requestedAction is none and the state is the expected one. Before another action, read the latest revision. A 409 service_changed means another update won the race; reload and reassess before resubmitting. A 409 service_busy means setup or an action is still pending.

The API also accepts resize and restore requests, but automated fulfillment depends on the service and profile. They are not general self-service capacity or restore guarantees. The instance's recorded limitations and qualification define what it supports; being ready does not promise automatic failover. To change a tier or replica count, send a new config as under Sizes and replicas, above.

Reference

GET /managed-services/instances, POST /managed-services/instances, GET /managed-services/instances/{instanceId}, POST /managed-services/instances/{instanceId}/credentials, POST /managed-services/instances/{instanceId}/actions.