Handle functions
The small pieces of work your app runs on AppHandle's servers, and who is allowed to call them.
A handle function is a small piece of work your app can run on AppHandle's servers instead of in the visitor's browser. You do not build one yourself: you describe what the app needs to do, and the builder writes it. The app's saved records, email, AI and private work all go through one.
What a handle function is for
A page in your app runs in the visitor's browser, and most of what an app does with data belongs on the server: the page asks a function, and the function decides which records that person may see. A service may also refuse requests that come from a browser. A key must stay out of the browser, where a visitor could find it. Some work is simply too heavy to run while someone waits. A handle function does those jobs on AppHandle's servers, where the visitor cannot see what it does or what it holds.
Asking for one
Ask the builder in the chat, the same way you ask for anything else. Say what the app needs to reach or work out, and it writes the function, gives it a name, and tells you when it is ready. You never paste a key into your app's pages, and you never write the function yourself.
Where they live
Open your app, select the Settings tab, then Handle functions. The list shows each function your app has, with its name, a short description, and a badge saying who can call it. Beside each one:
- The play control, Test, opens a box where you give it example values and select Run test to see what comes back.
- The activity control, Show metrics, reports how many times it has run, how many of those failed, how long it took in total, and when it last ran.
- The pencil, Edit, opens the function so you can read what it does and change who can call it.
- The bin, Delete, removes it, after asking you to confirm.
The values a function uses
A function often needs a credential: a key or token that lets it reach another service. Those live in the app's Settings → Secrets, never in the function's own settings and never in the app's pages. Connect an outside API shows how a key is added, and Who can use a key you store answers who may use it once it is there.
Who can call it
Open a function and look at Who can call it. There are three choices, and the panel always shows which one is in force under Currently published as:
- Only me and my editors — only you and the people you invited to edit the app. Use it for admin and internal work.
- Anyone signed in to this app — the people who signed in to your app, plus you and your editors. Use it for anything that belongs to one person.
- Anyone using this app — anyone who can open the app, including visitors who have not signed in. You pay for every call, so choose it only when the app is acting on its own behalf.
If a function is set to Anyone signed in to this app and your app has no sign-in, a Check warning appears beside it: only you and your editors can call it until the app has sign-in or you let anyone use it. See Give your app its own sign-in. A function left open to anyone on a private app is narrowed the same way.
Running on its own
A function does not have to wait for someone to use the app. It can run on a schedule — every hour, every morning, every Monday — which is how you get a daily summary, a regular sync, or a reminder that sends itself.
Ask for it the way you ask for anything else:
Email me a summary of yesterday's orders every morning at eight.
Then open the function in Settings → Handle functions and look at Runs on a schedule. Choose how often it runs — every 5, 15 or 30 minutes, every hour, every 6 hours, every day, every week, every month — and for the slower ones the day and the hour as well. There is nothing to type. If the builder set a schedule these controls do not offer, it shows as Custom with the expression it chose, and stays that way unless you pick one of the listed ones.
A few things worth knowing:
- The times are UTC. That is the clock the platform runs on, so "every day at 09:00" means 09:00 UTC, which may be a different hour where you are. Tell the builder the hour you want and check the schedule it set.
- Runs are spread, so 09:00 means around 09:00. The platform moves each schedule slightly so that every app asking for the same time does not start at once — an hourly function always stays inside its hour. The function's row shows the real next run.
- A scheduled run is billed by how long it runs. A short run costs a fraction of a cent; every five minutes is a far larger bill than once a day. Choose the slowest interval that does the job.
- Each run finishes the job by itself. Nothing is waiting for the result, so the function has to send the message, write the file, or update the record itself rather than hand data back to a page.
- You can see that it is alive. The function shows its next run and its last run under its name, and an issue appears in Issues if runs start being refused or failing.
- Turning it off with the Function is on switch beside the schedule stops both the schedule and any call from the app. Choosing No schedule stops only the schedule; the app still calls the function when it needs it.
If the month's included usage and your balance both run out, scheduled functions stop and resume by themselves once you add credits or the allowance renews — see When you run out of credit.
Calls that come in, streams, and files
A handle function normally runs for your app's page. Three related shapes are available when the work needs them:
- A call from outside. A function can be given a stable address
(
https://<app-id>.<your-domain>/api/hooks/<name>) so a service you control can call it. Each call is signed with a secret shown once when the address is created; a public address is possible for a truly public action. The function sees the incoming request, so it can check the event. For a service you control, use the AppHandle signature. For a provider with its own signature (Stripe, Paystack, WhatsApp), use the webhook option: the function checks the provider's signature with the provider secret you stored in Settings, and it can echo a GET verification challenge as plain text. - A stream. The page can open a stream and receive progress or new messages as the function produces them, instead of waiting for one answer or asking again every few seconds. A stream is one run and is capped at five minutes; the page reconnects if it needs longer.
- Files. A function can accept a file (up to 25 MB) and return a file — for example to resize a photo or produce a PDF. For a signed-in person's own files, use the per-person file space: they upload through the app, and only they and your app's team can open the result.
Your agent sets these up when the app needs them; you do not write code.
Reusing code across functions
Your app's functions can share code. The agent puts shared modules, templates
or fixtures in a ___backend/ folder at the app root, and each function imports
them. The folder is part of the app: it is saved with the app, exported with it,
and follows the app's history. External packages are still declared on the
function, so the platform installs and serves them the same way.
Small functions can stay self-contained; when the logic grows, the agent moves
it into ___backend/ and the function becomes a thin entry that imports it.
The same five-minute limit, billing and permissions apply.
What a call costs
Each run is metered by its running time, in seconds, rounded up with a minimum of one second, and drawn from your monthly included usage first, then from your balance. A light run costs a fraction of a cent; a long one costs more, up to five minutes of running time. The builder sets how long a function may take. Plans and limits lists the fixed daily allowance your app gets, which is there to stop a runaway app draining your balance.