Amba

Functions

Customer serverless functions for Amba — write a TypeScript handler, run it locally with hot reload, and ship it to your project's edge runtime.

Amba functions are small TypeScript HTTP handlers that run on Amba's edge runtime. Each function receives a Request and returns a Response. Use them for webhook handlers, custom mutation endpoints, queue consumers, and scheduled jobs.

Handler shape

Export a default object with an async fetch handler:

// functions/hello.ts
export default {
  async fetch(req: Request, env: Env, _ctx: ExecutionContext): Promise<Response> {
    const url = new URL(req.url);
    const name = url.searchParams.get('name') ?? 'world';
    return new Response(JSON.stringify({ greeting: `hello, ${name}` }), {
      headers: { 'content-type': 'application/json' },
    });
  },
};
 
interface Env {
  AMBA_API_URL: string;
  AMBA_PROJECT_ID: string;
  AMBA_INTERNAL_TOKEN: string;
  EDGE_HEADER_SIGNING_SECRET: string;
  AMBA_AI_GATEWAY_URL: string;
  STORAGE?: unknown; // object storage, present only when provisioned
  [key: string]: unknown; // your own secrets — added via `amba secrets set NAME value`
}

The runtime injects env for you at deploy time — you never construct it yourself. Standard Request / Response / Headers / URL / fetch / crypto are available. See Runtime for the full binding reference.

What you can do in a function

  • Custom HTTP endpoints — anything you'd put behind a server route: webhook receivers, signed-URL minters, server-only mutations.
  • Reads + writes against your collections — call into your project from the handler using env.AMBA_INTERNAL_TOKEN. Server context bypasses client-side scoping, so you can implement cross-user reads when you need them.
  • Queue consumers — bind a function to a queue with amba functions consume <queue> <function> and it receives one message per delivery.
  • Cron jobs — register a schedule with amba functions schedule <name> "<cron>" and the runtime invokes the function on that cadence.
  • Read secrets — set with amba secrets set NAME value, read with env.NAME inside the handler. Secrets are scoped per-project and never leak cross-tenant.

Who can call a function

Function URLs (https://<project>.fn.amba.host/<name>) accept server-to-server callers out of the box — your backend, a cron job, curl, and the default HTTP clients shipped with Python, Go, Node, and other server runtimes are all welcome. The runtime does not block requests based on a client's User-Agent, so a non-browser caller is never rejected just for looking automated.

By default a function still requires your project's X-Api-Key header, so only your own app reaches it. To accept calls from third-party webhook senders that can't attach a custom header (Stripe, RevenueCat, GitHub, Slack, …), deploy the function as public — then verify the webhook signature inside your handler. See Public functions.

Call a function from your app

You don't need to hand-roll a fetch against the function URL — the client SDK has Amba.functions.invoke(), which resolves the function URL and injects your project's client key (and the signed-in user's session token, when there is one) automatically. Forgetting those headers on a hand-rolled fetch is the usual footgun: the call lands unauthenticated and the function rejects it.

import { Amba } from '@layers/amba-web'; // or -expo / -react-native / -react
 
const result = await Amba.functions.invoke<{ ok: boolean }>('send_welcome_email', {
  to: 'user@example.com',
});
  • First arg is the deployed function name; second is a JSON-serializable body (omitted for GET).
  • A third options arg takes { method, headers, onTraceId }method defaults to "POST", and any headers you pass are merged on top of the injected auth headers.
  • The injected session token means the function runs in the end user's authenticated context. Anonymous (pre-sign-in) calls still carry the client key, which the runtime accepts for non-public functions.
  • The parsed JSON response is returned. A non-2xx response throws, surfacing the function's { error: { code, message } } envelope as the thrown error's code + message.

Correlate a call with server logs (onTraceId / error.traceId)

Every invoke carries a server-side trace id (the X-Amba-Request-Id response header). Pass options.onTraceId to capture it on every response — success or failure — and on a thrown error read error.traceId off the AmbaApiError. Either way, amba functions logs <name> --request-id <traceId> pulls that exact run's logs.

import { Amba, AmbaApiError } from '@layers/amba-web';
 
try {
  const result = await Amba.functions.invoke<{ ok: boolean }>(
    'send_welcome_email',
    { to: 'user@example.com' },
    { onTraceId: (id) => console.log('trace', id) },
  );
} catch (err) {
  if (err instanceof AmbaApiError) {
    // amba functions logs send_welcome_email --request-id <err.traceId>
    console.error(`failed (trace ${err.traceId}): ${err.message}`);
  }
}

onTraceId receives null when the server returned no trace id (e.g. a pre-auth rejection that doesn't stamp the header).

To see everything that happened from that request onward (the failing run plus the fallout after it), anchor the range instead of filtering: amba functions logs <name> --since-request-id <traceId> --tail.

From a server (or another deployed function), call the function URL directly with fetch and your server key / internal token — invoke() is the client-app convenience, not a requirement.

Three commands you'll use most

The full command list is on the CLI reference.

Limits

  • Bundle sizeamba functions deploy reports the bundle size and rejects deploys over the platform cap. Use --dry-run to triage size without uploading.
  • Per-function rate limits — optional, declared at deploy time with --rate-limit-window, --rate-limit-max, --rate-limit-key. The edge runtime enforces them pre-dispatch (the handler never runs for rate-limited requests).
  • Runtime stdlib — standard Request/Response/Headers/URL/ crypto/fetch are provided by the platform. Node-specific built-ins (fs, child_process, net) are not.

Next

On this page