Guides
GuideAccount Functions & Webhooks

Account Functions & Webhooks

Site functions belong to one site. Account functions belong to you — they can reach across all your sites (read one site’s orders, write another’s CRM) and are managed in the Automations section of your dashboard.

Inside an account function, ctx.sites gives you each of your sites’ tables, files, users, and exposed methods — so two sites that never knew about each other can work together.

Six ways they run

Open a function and you get tabs: Code, Runs (every run, what started it, its log), Triggers, Access and Settings. Everything below is set on the function’s own Triggers tab — Automations → All triggers only lists them across the account.

  • On a schedule — say it in plain English (“every weekday at 8am”) or pick a preset or a cron expression; as many schedules as you like.
  • Webhook — each function can get secret URLs; anything that POSTs to one runs the function with the request body as the event. Perfect for payment providers, form services, CI, or any external tool that “calls you back”.
  • Event (when something happens) Beta — a row added, changed or deleted in a base (narrowed to which base, which table, only when a field changes, only rows where…), a file in Drive, a flow or agent run, a site event, a payment, a connector, or your own event raised from code or the chat. The function receives { event, config }.
  • Incoming mail (email address) — a unique email address that runs the function with the parsed email as input. See Email Triggers (Mailhooks).
  • Called by an automation or another function — automations can target account functions; functions can chain (ctx.functions.run).
  • Called from your published app — see below.

Calling from your published app

Your app’s pages can invoke an account function with functions.invokeAccount('name', params). Because account functions are powerful (they can span sites), this is off by default — you must switch it on per function, in two steps:

  1. Grant the site: the function’s grants must include the site that calls it.
  2. Set who may call it: give the function execute access rules — for example “signed-in members”. No rules = no app access.

The signed-in member’s identity is checked against your rules automatically, and the function receives it as params._appUser. Account functions read global environment variables — your account-level secrets (ctx.env.get('NAME') or {{NAME}} in ctx.fetch). These are deliberately separate from each site's env vars: site functions see only site values, account functions see only global values — no silent fallback between them.

An account function is not a site function

It has no ctx.tables and no logged-in user, because it belongs to your account rather than to one site. Reach a site's data through ctx.sites['Site Name'].tables (granted sites only). If you're unsure what a function can see, have it return Object.keys(ctx) once — the AI can do this for you.

Calling a slow API (an AI model, a big import)? Two limits must both allow it: the request's own timeout and the function's timeout, which defaults to 10 seconds. Raise the function timeout for anything AI-related, or the call is cut off mid-flight.

Listing mailboxes: whose do you get?

ctx.email.accounts() answers “what may the person calling right now send through”. If a member is signed in you get only the mailboxes they connected — that isolation is the point, so one customer can never send as another. An empty list therefore means this member has none, not that you have none; the reply's scope tells you which it was. When your own code wants your account's shared mailboxes anyway — an admin screen, an ops function — ask for them explicitly with ctx.service.email.accounts(). It never returns a member's private mailbox.

Site function or account function?

Most logic belongs to a single site — write that as a backend function (code) or a data function (declarative). Reach for an account function only when the work spans sites or an external service needs a URL to call.

SituationUse
Logic for one site, called by its pagesSite function (backend or data)
External service needs a URL to callAccount function + webhook
Work spanning two or more of your sitesAccount function (ctx.sites)

Call AI from a function

ctx.ai.generate runs one AI call with the account owner’s models: the platform models (billed as AI credits, like chat) or the owner’s own provider keys from Your AI (billed nothing here). One call, no tools, 60-second limit, up to 4,096 output tokens, quick low-effort thinking by default.

const { text } = await ctx.ai.generate({ prompt: 'Summarise in one line: ' + params.body, maxOutputTokens: 200 });

const r = await ctx.ai.generate({
  system: 'Reply with one word: billing, bug, or other.',
  messages: [{ role: 'user', content: params.ticket }],
  model: 'byoai:gpt-5.4@key:…',   // one of your own keys (Your AI); leave out for the platform model
  effort: 'low',                   // 'low' | 'medium' | 'high'
});
// r = { text, model, usage: { inputTokens, outputTokens }, credits, ownKey }

When the owner’s monthly AI credits are used up, platform-model calls fail with a message that says so; catch it and fall back.

Use built-in connectors

ctx.connections.list() and ctx.connections.call(credential, tool, args) run a saved service credential’s tools (Slack, Google, GitHub, Stripe…) from code. The secret stays server-side. See built-in connectors.

Quotas & requirements

Running functions requires a paid plan. Account functions execute in the same sandboxed engine as project backend functions and draw from the same monthly execution quota and concurrency limit — there is no separate account-function allowance, so heavy cross-site automation counts against the same budget as your sites’ own functions.