Skip to content

Changelog

3 November 202631 changes

Platform 12 · Containers 4 · Functions 2 · Sandboxes 10 · Apps 1 · CI/CD 2

16 min read

NewerOlderFollow by RSS

Better Stack's monitors API over Uptime checks

Better Stack Uptime API calls for monitors (GET and POST /api/v2/monitors; GET, PATCH and DELETE /api/v2/monitors/{id}) run against Runtime Uptime checks at /compat/betterstack with a Runtime API key as the bearer token. Status and keyword monitors are mapped: URL, name, HTTP method, check frequency, request timeout, regions and required keyword. Any other field set in a request, including paused: true and follow_redirects: true, returns 400 with a message that names the field. Only a keyword monitor checks required_keyword, as on Better Stack; a keyword monitor requires it, and a monitor changed to status stops checking for it. A monitor's url can't be changed; delete the monitor and create a new one.

GitHub Codespaces API for Dev environments

The Codespaces endpoints of GitHub's REST API are served under /compat/github, so Octokit and other GitHub clients manage Dev environments by changing only their base URL and token (Authorization: token <key> or Bearer <key>). Supported: create in a repository (POST /repos/{owner}/{repo}/codespaces), list, list in a repository, get, update the display name, start, stop, delete, and machine types for a repository or a codespace. Lists are paginated with page and per_page (30 by default, at most 100), return the full count in total_count, and return a Link header to the next and last pages. The machine types basicLinux32gb, standardLinux32gb (the default), premiumLinux and largePremiumLinux create an environment with 2, 4, 8 or 16 vCPUs and 8, 16, 32 or 64 GiB of memory, billed by measured use. Stop pauses the environment with its memory kept. A field Dev environments does not support yet, such as devcontainer_path, returns 400 with its name.

Containers: Google Cloud Run Admin API v2

Containers now accept the Cloud Run Admin API v2 services methods at /compat/google-cloud-run: set the client's endpoint to https://<your API host>/compat/google-cloud-run and use a Runtime API key as the bearer token. services.create, services.get, services.list (paginated with pageSize and pageToken), services.patch and services.delete are supported; each service is a Container labeled with its project and location, and a service under another project or location returns 404. One container's image, command, args, env (name and value pairs), workingDir, one port, resources.limits.cpu (1, 2, 4 or 8) and resources.limits.memory (512Mi to 32Gi), scaling.minInstanceCount, scaling.maxInstanceCount and maxInstanceRequestConcurrency map to the Container's spec, with Cloud Run's defaults: a service scales to zero unless minInstanceCount is set. Any other field returns 400 with a message naming it. Create, patch and delete return their operation with done: true, so clients do not poll. services.patch replaces the whole template, so its body must include template.containers[0].image; updateMask and etag return 400. A service's name holds its Container ID, not the serviceId requested; serviceId follows Cloud Run's rule (1 to 49 lowercase letters, digits and hyphens, starting with a letter) and is the create's idempotency key for 24 hours, so a retried create returns the same service instead of creating a second one; once that service is deleted, a create with the same serviceId creates a new one. Revisions, traffic other than 100% to the latest revision, validateOnly, allowMissing and the IAM methods are not yet available.

Containers: flyctl and fly-go

flyctl and Fly's Go client (fly-go) now run against Runtime's Fly Machines API unchanged. These clients discard the path of FLY_FLAPS_BASE_URL and send /v1/apps/..., so the /compat/fly base URL from the earlier entry did not reach them. Requests whose User-Agent starts with flyctl/ or fly-go/, or that include flyctl's Fly-Client-Parent header, are now served Fly's API at the root of the API host. Set FLY_FLAPS_BASE_URL, FLY_API_BASE_URL and FLY_UIEX_BASE_URL to https://api.withruntime.com and FLY_API_TOKEN to a Runtime API key, so that no flyctl request is sent to Fly. fly machine run, list, stop, start and destroy are supported. GET /v1/apps/{app_name}, the organization lookup and the image lookup that fly machine run performs are supported. GET /v1/apps/{app_name}/machines/{machine_id}/wait returns 200 when the machine is in a requested state, at the requested version or instance_id if one is given, and 408 immediately when it is not, because a Container's state changes only through a request. from_event_id is accepted and ignored. GET /v1/apps/{app_name} returns 200 for any app name. A stop request now accepts id, timeout and signal: "SIGTERM"; any other signal returns 400. A machine's instance_id is a string, as Fly's clients expect. Other HTTP clients continue to use https://api.withruntime.com/compat/fly as their base URL.

Queues: SQS-compatible status codes for authentication and size errors

The SQS-compatible endpoint now returns 403 for AccessDenied and for every InvalidClientTokenId, and 413 for RequestEntityTooLarge; these errors previously returned 400 (and InvalidClientTokenId returned 400 or 403 depending on where the request was refused). AddPermission and RemovePermission are not supported and return 400 UnsupportedOperation: access to a queue comes from the access key's grant.

Functions: AWS Lambda Invoke

The AWS Lambda API on Runtime Functions now supports Invoke, so invoke in AWS's SDKs runs a function after you change only the endpoint and the keys. The payload is sent as a POST to the function's address (status.url). With InvocationType RequestResponse (the default), the call returns 200 with the function's response body. When the function returns a 4xx or 5xx status, the response also includes X-Amz-Function-Error: Unhandled. A function whose response is larger than 6 MB, whose connection closes before it responds, or that runs longer than 15 minutes also returns 200 with X-Amz-Function-Error: Unhandled, and an errorType of Function.ResponseSizeTooLarge, Runtime.ExitError or Sandbox.Timedout, so SDKs do not retry an invocation that may have run. When the function cannot accept the request, Invoke returns 429 TooManyRequestsException or 500 ServiceException. DryRun returns 204 without running the function, including for a function that has no address yet. Event is not yet supported and returns 400 InvalidParameterValueException. A function that has no address yet returns 409 ResourceConflictException. A payload larger than 6 MB returns 413 RequestTooLargeException. Concurrent invocations are limited per organization; past the limit, Invoke returns 429 TooManyRequestsException. Qualifier, LogType: Tail and ClientContext are not supported.

Browserbase session list filters on Browsers

GET /compat/browserbase/v1/sessions (sessions.list in Browserbase's SDK) accepts status (PENDING, RUNNING, COMPLETED or ERROR) and q in Browserbase's metadata query form, user_metadata['key']:'value', and returns only the sessions that match both. A session whose browser is still starting now reports PENDING instead of RUNNING. A q in any other form, including a nested path such as user_metadata['a']['b']:'value', returns 400: session metadata on Browsers holds only string values at the top level.

Browserbase's session debug URLs on Browsers

GET /compat/browserbase/v1/sessions/{id}/debug (sessions.debug in Browserbase's SDK) returns the session's wsUrl (its Chrome DevTools Protocol WebSocket URL) and, when the browser draws its screen, its live view as debuggerUrl and debuggerFullscreenUrl; otherwise those are empty. pages is always empty; the browser's pages are listed at its httpUrl (/json/list).

Queues: SQS-compatible error status codes

The SQS-compatible endpoint now returns the HTTP status Amazon SQS returns for each error. For example, DeleteMessage with an invalid receipt handle and CancelMessageMoveTask for a task that does not exist now return 404 instead of 400. Every operation and error is checked against AWS's published SQS API model.

Checkly's checks API over Uptime checks

Checkly API calls for API and URL checks (POST /v1/checks/api, POST /v1/checks/url, PUT on each, GET /v1/checks, GET and DELETE /v1/checks/{id}) run against Runtime Uptime checks at /compat/checkly with a Runtime API key as the bearer token. Frequency, locations, maximum response time, the URL, the method and one status-code assertion are mapped; any other field set in a request returns 400 with a message that names the field.

Balancers and Ports: target weights and failover

Each entry in spec.targets accepts weight (1 to 1,000, default 1) and backup (default false). When targets have different weights, each request (or, for a port, each connection) goes to a target with a probability of its weight over the sum of the weights; when weights are equal, it goes to the target with fewer requests in flight of two chosen at random. On a balancer, a backup target receives requests only while no other target is healthy and has capacity; on a port, it receives connections only while every other target's sandbox is stopped or deleted. Available in every SDK.

Apps, Functions and Containers: health checks while serving

healthPath is now also checked while a copy serves: every 5 seconds, each copy is sent a GET of the path, and a copy that fails 2 consecutive checks (no status under 500 within 2 seconds) receives no requests until it passes 2 consecutive checks. Previously the path was checked only before a copy took its first request. During a staged release that changes healthPath, the service's address checks only that each copy's port accepts a connection until the release completes. A healthPath that does not start with / is checked as /, as the check before the first request already does. A path with characters a URI path cannot contain, such as a space or #, is not sent: the check only confirms that the copy's port accepts a connection.

Containers: Fly Machines restart

POST /compat/fly/v1/apps/{app_name}/machines/{machine_id}/restart is now supported. It creates a new version of the machine's Container with the same settings, and that version's copy replaces the running one. The timeout query parameter is accepted. signal returns 400, because the restart replaces the copy instead of signaling its process. As with the other machine routes, a machine is found only under its own app.

Speed page: daily history charts and provider comparison

The speed page now charts each listed operation's median own time for each of the last 90 days, against its physical floor. Hover over a day to see its p95, p99 and sample count. When another provider has been measured the same way and Runtime is faster, the page also lists it beside the matching Runtime operation, comparing total times.

CI/CD: a job that fails because its machine ran out of disk says so in its reason

When a job's machine runs out of disk, the error is often never written to the job's log, because the log is on the same full disk. Such a job's reason was the log's last error, for example error: build failed, waiting for other jobs to finish.... The job's log now ends with a line that says the machine ran out of disk (error: No space left on device: ...), and its reason names that line.

Speed: browser create time and rival providers, measured the same way

browsers.create is now measured every five minutes. The time runs from POST /v1/browsers until the browser's CDP WebSocket answers Browser.getVersion, which is the point where Playwright or Puppeteer can connect. The CDP exchange carries no Server-Timing, so all of its time is counted as Runtime's own. speed.json also includes a rivals array. Each rival is timed from the same location as Runtime, through the provider's own public API, to the same outcome as the Runtime operation it is compared with (compares). Browserbase, Steel, Hyperbrowser and Browser Use are timed until CDP answers. E2B, Daytona and Vercel Sandbox are timed until the sandbox is running. Rivals return no Server-Timing, so each line reports total time only. A rival is listed only after it has been measured with its own API key; nothing is estimated. Each rival's history is available from speed/history.json?op=rivals.<name>.<operation> (speed).

Sites (beta): static websites served with no machine

A site is files and a route table (redirects, rewrites, headers, Markdown for agents, 404 pages) served by every front. POST /v2/sites creates one; :missing returns the files, by SHA-256, the site does not hold yet, :upload stores each, :release stages a release and :publish makes it live in one commit. :rollback publishes the previous release, also in one commit, and keeps the release it replaced so it can be published again. Both :publish and :rollback accept ifVersion and return 409 if another change came first. :releases returns the live release, the earlier ones and the ones rolled back from. A deleted site stops serving and keeps its releases; restoring it serves its live release again. npx withruntime sites deploy ./dist runs all of these for a folder and uploads only the files that changed. Every SDK, the CLI and the MCP tools include Sites. Usage is billed on the existing storage, operations and egress meters at their current rates.

Speed history by the hour and by the day

Each listed operation's hourly and daily p50, p95 and p99 (Runtime's own time, the network's part and the total), sample count and failure count are now kept indefinitely and returned by https://status.withruntime.com/speed/history.json?op=<id>&step=hour|day&from=&to=. from and to take a date (2026-11-03) or an ISO 8601 time and are rounded down to the step; by default a request returns the last 48 hours, or the last 365 days with step=day. A request returns at most 744 hourly or 3,660 daily points, and returns 400 for an unknown operation or an invalid range. Percentiles are computed from each hour's or day's own samples. Responses are cached for one minute (speed).

Containers: Fly Machines API

Containers now accept Fly's Machines REST API at /compat/fly/v1, so clients written for api.machines.dev run against Runtime after you change only the base URL and the token: use https://<your API host>/compat/fly as the base URL and a Runtime API key as the bearer token. For flyctl's Machines calls, set FLY_FLAPS_BASE_URL to the same base URL. Each machine is a Container with one copy, labeled with its app. Creating, showing, updating and deleting a machine, listing an app's or an organization's machines, starting, stopping and suspending a machine, and reading and writing its metadata in all six forms are supported. A machine's image, env, guest.cpus, guest.memory_mb, init.cmd, init.entrypoint, metadata, one service's internal_port, one mount and restart.policy (no or always) map to the Container's spec; any other config field returns 400 with a message naming it. As on Fly, an update replaces the machine's whole config, so a field it omits is removed; listing machines returns every machine, not one page; and a machine ID is found only under its own app, so a request under another app returns 404. auto_destroy: true returns 400. Restart, wait, events, versions, exec, signal, processes, leases, cordon and the memory routes are not yet available and return 404.

Sandboxes: E2B API

Sandboxes now accept E2B's REST API at /compat/e2b, so code that uses E2B's SDKs (e2b, @e2b/code-interpreter) can create and manage Runtime sandboxes after you change only the API URL and the API key: set E2B_API_URL to https://<your API host>/compat/e2b and E2B_API_KEY to a Runtime API key. Creating a sandbox from the base template with timeout, metadata and autoPause, getting and listing sandboxes (paginated by nextToken), setting the timeout, pausing, connecting (which resumes a paused sandbox) and killing are supported. Running commands and reading or writing files inside the sandbox through E2B's SDK are not yet available. A request that sets an unsupported field, such as envVars or another template, returns 400 with a message naming the field.

Browserbase's sessions API on Browsers

Browserbase's Node.js SDK (@browserbasehq/sdk) works with Runtime Browsers when BROWSERBASE_BASE_URL is set to https://<your API host>/compat/browserbase and BROWSERBASE_API_KEY to a Runtime API key. POST /v1/sessions returns a running session with its connectUrl (the browser's Chrome DevTools Protocol WebSocket URL), GET /v1/sessions/{id} and GET /v1/sessions read and list sessions (a list of more than 100,000 sessions returns 400), and POST /v1/sessions/{id} with status: "REQUEST_RELEASE" ends one. Fields and operations not yet supported (region, keepAlive, proxies, contexts, debug URLs, recordings) return 400 or 404 instead of being ignored.

Functions: AWS Lambda API

Functions now accept the AWS Lambda API, signed with AWS Signature Version 4, so code that uses AWS's SDKs (such as boto3) runs against Runtime Functions after you change only the endpoint and the keys. Create an access key pair with POST /v2/aws-access-keys, authenticated with a Runtime API key; it returns accessKeyId and secretAccessKey, reaches what that API key reaches, and stops working when that API key is revoked or expires. Set AWS_ENDPOINT_URL_LAMBDA to https://<your API host>, set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to the pair, and use a function's ID as FunctionName. GetFunction (FunctionName, MemorySize, Environment and LastModified), ListFunctions with Marker and MaxItems, and DeleteFunction are supported. Errors return Lambda's exception names, such as ResourceNotFoundException. A qualified function name or an ARN returns 400 InvalidParameterValueException. Invoke, CreateFunction, UpdateFunctionCode, UpdateFunctionConfiguration, versions and aliases are not yet available and return 404.

Notebooks: connect JupyterLab, VS Code or any Jupyter client

The URL that POST /v2/notebooks/{id}:open returns now also accepts its secret as a Jupyter token, sent as Authorization: token <secret> or ?token=<secret>. Jupyter clients use Jupyter Server's REST API (/api/kernels, /api/sessions, /api/contents) and the kernel WebSocket without changes, and share the kernel with cells run through :execute.

Firewalls

POST /v2/firewalls creates a named rule set that ports and balancers attach to with firewallId. Each rule blocks, allows or rate-limits HTTP requests by IP address or CIDR block, path, method or header; a rule that matches ports applies to raw TCP connections only. Rules are checked at write by the same parser and compiler every host enforces them with. A change to a firewall applies to every route attached to it one commit later, without a write to the routes. A rate limit counts each client across every route attached to the firewall. A route with firewallId takes no inline firewall; the request returns 400. A route attached to a deleted firewall refuses every visitor. Available in the API, the SDKs, the CLI and the MCP tools.

KV: Cloudflare Workers KV API

KV stores now accept Cloudflare's Workers KV REST API at /compat/cloudflare/client/v4, so code that uses Cloudflare's SDKs runs against Runtime KV after you change only the base URL and the API token: set baseURL to https://<your API host>/compat/cloudflare/client/v4, apiToken to a Runtime API key, and use a KV store's ID as the namespace ID. Reading, writing and deleting a value, and listing keys with prefix, limit and cursor, are supported. A request that sets expiration or metadata returns 400 with a message naming the unsupported parameter; bulk operations and namespace management are not yet available and return 404.

Browsers: capture a page with POST /v2/browsers/{id}:screenshot

Opens url in a new tab, waits for its load event, and returns the image as base64 with the page's final URL, title and HTTP status; without url, it captures the page the browser shows now. Set fullPage to capture the whole page, format to png or jpeg, and waitMs (up to 10000) to wait for late scripts. The capture runs inside the browser's own sandbox. Returns 409 (browser_not_running) when the browser is not running and 504 (page_timed_out) when the page does not load within 30 seconds. Available in every SDK as browsers.screenshot.

Balancers: health checks

A balancer's spec.health sets how each target is checked, with the fields of an AWS ALB target group: path, intervalSeconds, timeoutSeconds, healthyThreshold and unhealthyThreshold. A target that fails unhealthyThreshold consecutive checks receives no requests until it passes healthyThreshold consecutive checks. Available in every SDK.

A PUT link from POST /v1/sandboxes/{id}/files:link to a path under /workspace whose folder is owned by root (for example, a tarball extracted with sudo) returned 404 with This upload is not open in the sandbox. The upload now replaces the file atomically, as files_write does, and the new file is owned by the sandbox user. When the sandbox user cannot write the folder (outside /workspace), the link returns 403 permission_denied with the folder named, instead of 404.

GitHub Actions runners in every SDK

/v2/runners is now in the API reference and the OpenAPI document, and every SDK makes its calls as runners.settings, runners.enable, runners.disable, runners.jobs and runners.job. GET /v2/runners/jobs returns {"jobs": [...]}; GET /v1/actions/jobs still returns the array.

Sandboxes: lists and lookups include every sandbox of an organization being moved to Runtime 2.0

While an organization has sandboxes on both Runtime 1.0 and Runtime 2.0, GET /v1/sandboxes returns them all in one paginated list, in the same order and with the same fields as before. GET, exec, files and DELETE on a sandbox return from wherever it runs, and the console's Sandboxes page shows both. Before, a sandbox created on Runtime 2.0 might be missing from the list, and requests for it returned 404.

Plans: includedMicros, yearlyOnly and trialUsageMicros

GET /v1/plans returns three new fields on each plan: includedMicros, the usage included each month (null when the fee and bonusMicros are the plan's usage); yearlyOnly, whether the plan is billed yearly only (choosing such a plan monthly returns 409); and trialUsageMicros, the usage a trial includes ("0" for none). Every current plan returns null, false and "0". The TypeScript, Python, Go, Ruby and Java SDKs include the fields.

Other days.

Cut your cloud billby 75%.

No card to start. Billed by the second after.

Start free, no card