Hosted functions
Run your own TypeScript behind the same gateway, key and metering.
A hosted function is code you write, deployed to upAPI and invoked exactly like
a marketplace operation: a POST to its slug with your API key. It runs in a
V8 isolate — not a container — so cold starts are milliseconds rather than
seconds.
This is the escape hatch for the glue you would otherwise host yourself: reshape an operation's output, join two calls into one round trip, or wrap a private API of your own so the rest of your system only ever talks to upAPI.
Hosted functions require a paid plan
The Free tier's allowance is zero, and the gateway refuses to run a function with 403 FORBIDDEN
when your plan includes no compute.
| Plan | Hosted functions |
|---|---|
| Free | Not included |
| Starter | 3 |
| Pro | 15 |
| Scale | Unlimited |
The execution context
Your function receives its validated input and a ctx object with two
capabilities.
ctx.fetch makes outbound HTTP requests. Every request passes an SSRF guard
that resolves the target first and refuses private, loopback and link-local
addresses — including through a redirect or a DNS record that changes between
the check and the connection. A blocked request fails with NETWORK_DENIED.
Each invocation may make at most 20 outbound requests, at most 5 of them concurrently, and each is capped at 30 seconds.
ctx.secrets holds the secrets you attached to the function. They are
encrypted at rest with AES-256-GCM and only decrypted inside the isolate for the
duration of a call, so they are never part of your deployed code and never
appear in the dashboard after you save them.
Limits
| Limit | Value |
|---|---|
| Source size | 256 KB |
| Execution timeout | Your plan's maximum, or lower if you set one |
| Memory | 64 MB, 128 MB or 256 MB, by plan |
| Response size | 1 MB |
| Outbound requests | 20 per invocation, 5 concurrent |
A function may declare a timeout below its plan's ceiling but never above it —
the effective limit is whichever is smaller. Exceeding memory returns
MEMORY_EXCEEDED: the request asked for more than the plan allows, so retrying
it unchanged cannot help.
Returning more than 1 MB fails with INVALID_OUTPUT. If you are producing large
results, paginate or return a reference rather than the payload.
Failures here look different from the rest of the gateway
A hosted function's errors reach you as an edge-safe 4xx rather than the code's usual status —
422 for MEMORY_EXCEEDED, INVALID_OUTPUT and OPERATION_ERROR, 408 for
OPERATION_TIMEOUT — with the original in X-Upapi-Execution-Status. The body is also
{"error": "MEMORY_EXCEEDED", …} with error as a string, not the usual { code, message }
object. See Errors.
Metering
Hosted functions consume the same monthly units as any other call, plus compute
seconds against your plan's allowance. Responses carry X-Compute-Used and
X-Compute-Remaining so you can watch that budget from your client.
Exhausting the compute allowance returns 429 QUOTA_EXCEEDED and carries no
Retry-After. The monthly unit quota and a trial's unit budget use that code
too, so read the message to tell which budget is gone — compute is the only one
that stops functions while marketplace operations keep working.
Hosted functions are never served from cache and never routed through the
proxy pool — ctx.fetch egresses directly. If you
need a specific egress IP, make the request through a marketplace operation that
supports proxying.
Managing them
Create, edit and deploy functions from Dashboard → Functions. Slugs are lowercase and may contain letters, digits, dots and hyphens, and must start with a letter or digit.