Skip to main content
On the edge gateway every API runs as its own Worker: a standard fetch handler in JavaScript, executed close to the consumer. The gateway authenticates and meters consumers, then calls your Worker; your code does whatever the API does — forward to your servers, compute an answer, read a database, call several upstreams. There is no SDK to import; the same code runs unchanged in the standard Workers tooling (wrangler dev).
The Worker tab is available for APIs served by the edge gateway. Each API is either in template mode, where the Worker is generated from the template, or in code mode, where you own the files. APIs moved from the classic gateway with endpoint-specific targets start in code mode with generated code that reproduces their classic behaviour.

Template or code

  • Template (default): the Worker is generated from the template. Saving creates a preview on its own URL; Deploy to production in the bar on the Worker tab serves it to your consumers. View generated code shows exactly what runs.
  • Code: Edit code stores the generated files as yours. From then on nothing is regenerated. Deploy preview puts your files on their own URL; Deploy to production (in the editor, the bar or Promote on the Deployments tab) serves them to your consumers. Back to template deletes them and generates the Worker again, as a preview too.
  • From the CLI or GitHub: deploying files with jojapi deploy (or from GitHub) to an API in template mode switches it to code mode. The files become a preview deployment; production keeps serving the template’s deployment until you promote them (jojapi deploy --prod does both at once). Back to template restores the template.
Every save is a deployment: an immutable snapshot with its own URL, which you can promote, roll back to or share as a pinned version.

Files

Limits: 64 files, 1 MiB per file, 6 MiB per API, folders up to 3 deep, lower-case paths. Relative imports must point at files of the API; npm packages are bundled on your side before upload (the CLI does this for you). node:* and cloudflare:* modules are available (nodejs_compat). Outgoing traffic is HTTP and HTTPS through fetch(); raw TCP sockets (connect() from cloudflare:sockets, and database drivers built on them) are not available, so reach a database through an HTTP API.
Exceptions in your code answer the consumer with a gateway 500 Server Error and are recorded under Runtime errors.

The contract with the gateway

The gateway speaks to your Worker with HTTP headers only. Anything a consumer sends under x-jojapi-* is dropped before your Worker sees the request, so these values are trustworthy.

Request headers your Worker receives

The consumer’s own headers (minus hop-by-hop ones) arrive as they were sent; the API key never does. The body streams through unread.

Response headers your Worker may set

Every x-jojapi-* header is stripped before the consumer sees the response; the gateway adds the usage and quota headers itself.

Billing

Metered billable objects read their units from the usage sources configured in Billable objects (a response header, a header key or a JSON field, each with a default). Where no source is configured, the x-jojapi-usage header applies. Platform rules stay the same: a 5xx bills nothing, a fixed amount is a ceiling, values are non-negative integers, and streaming responses (text/event-stream) report usage in-band as described in Adjusting usage.

Variables

Named values bound to the Worker as env.NAME: upstream API keys, tokens, a proxy URL. Secret variables are encrypted at rest and never shown again; plain ones are visible. Names use capital letters, digits and underscores.

Storage and queues

Managed storage and queues created for your API alone and bound to its Worker: They are added and removed on the Worker tab under Bindings, or from the CLI with jojapi resources add <kind> <BINDING> (kv, d1, r2, queue, or do --class Counter) and jojapi resources remove <BINDING>, as previews like every other save. A removed key-value store, database or queue is deleted with its data once no active deployment uses it any more; object storage must be empty by then (see Removing storage). A binding name is unique across variables and storage. A resource can also be used by other APIs — your own, or another account’s after it accepts — without copying it: see Shared resources.

Console logging and limits

  • Console logging (Worker tab → Errors & logs): captures what your Worker writes with console.* and the stack of uncaught exceptions. It is separate from the request log, which records every request anyway. It stays on until you switch it off, and each request then costs a little more to process: the cost appears under Compute usage as Console logging (per invocation) and Console log lines (per stored line). The last 500 lines are kept.
  • Limits: a request may use up to 30 seconds of CPU time and 50 outgoing requests, with an upstream call of at most 90 seconds. The platform raises these per API when an API needs more; write to support.

Compute usage

The Worker tab (Usage) shows what the Worker and its storage used at the edge over the last days — requests, CPU time, key-value, SQL, object storage, stateful object and queue operations, storage, console logging — next to the included allowance and a list-price estimate. It is informational: nothing is charged for compute today, and any future charge would be announced in advance.

Runtime errors

Whatever goes wrong inside or behind your Worker forms one stream per API, grouped by kind and message: unreachable origins and timeouts (the generated code reports them), exceptions and bad outcomes (CPU or memory limits), 5xx answers, and everything your code reports through x-jojapi-error. Each issue shows how often it happened, when it was first and last seen, and its recent occurrences with request ids that link back to the request log. Platform-side refusals (invalid key, quota, rate limit) are not runtime errors; they stay in the request log.

Proxies and the egress relay

IP-address hosts and non-standard ports are reached automatically through the platform’s egress relay. To send a request through your own HTTP, HTTPS or SOCKS5 proxy, set the header x-jojapi-relay-proxy: <proxy URL> on your fetch(); keep the URL in a secret variable. The template’s Proxy field does exactly this. The relay forwards your method, headers and body as they are: it sets Host, drops hop-by-hop headers and the platform’s own, and adds nothing. Put proxy credentials in the URL (http://user:pass@host:port), not in a header. Redirects are not followed (a 3xx comes back to your Worker), and a request gives up after 90 seconds.

Browser impersonation

Some sites answer differently depending on what the client’s TLS handshake and HTTP/2 connection look like. Set x-jojapi-relay-impersonate: <profile> on a fetch() and the relay makes that request with a real browser’s identity: its TLS handshake, HTTP/2 settings and default headers. It works with or without a proxy.
  • Profiles: chrome, chrome_android, edge, firefox, safari and safari_ios follow the newest version the platform has, or pin one such as chrome146, firefox144 or safari184. An unknown profile answers 400.
  • Headers: yours replace the profile’s same-named ones in place, so set your own user-agent, cookies or accept-language when you need them. The profile keeps accept-encoding, and the body reaches your Worker already decoded.
  • The response carries x-jojapi-relay-impersonate with the exact profile used.
  • Without the header, requests keep the default client (HTTP/1.1).
  • Failures of your own proxy are named in the relay’s 502 answer, for example Proxy Tunnel Refused (407).

Local development

Your Worker runs under wrangler dev (the standard Workers development server) like any other. Send the contract headers yourself while testing:
Variables become a .dev.vars file, resources their local wrangler equivalents. The jojapi CLI (jojapi pull, jojapi deploy, jojapi dev) does this for you and bundles npm dependencies before upload. jojapi deploy creates a preview deployment and prints its URL; jojapi deploy --prod (or jojapi promote <id>) serves it in production.