Docs / Search / LingCode Cloud / Functions
๐Ÿ“˜ Reference โ— Functions Updated 2026-06-11

Functions

TL;DR: Functions are server-side code you call by slug. Two kinds: seven builtins that are already live on every backend โ€” set any required secret and invoke, no deploy โ€” and custom functions you author in TypeScript and run in a sandboxed Deno runtime. Invoke either with lingcode.functions.invoke(slug, body?) or by POSTing to /api/cloud/be/<backend-id>/functions/<slug>. Use functions for what the browser can't safely do: hold a secret key, call a vendor API, run trusted logic.

A function exists for one reason: there are things the browser can't do safely. It can't hold a Stripe secret key. It can't be trusted to compute a price or grant access. It can't call a vendor API that needs a credential. Functions are the small slice of your app that runs on the server, behind your backend, where a secret stays a secret. This page covers both flavours โ€” the builtins that ship turned on, and the custom functions you write yourself โ€” and how to call them.

Why functions exist

Everything in the client SDK โ€” from('table').select(), auth, storage โ€” runs against a thin gateway with the public anon key, gatekept by row-level security. That covers most of an app. But some logic has to live somewhere the user can't see or tamper with:

You reach a function by its slug โ€” a short name. There are two ways to get one: use a builtin (already live, just set its secret) or write a custom function (your own TypeScript). Both are invoked exactly the same way.

How to invoke (both kinds)

From the SDK, call functions.invoke with the slug and an optional body. Like every SDK call it returns a Result โ€” { data, error } โ€” so you never have to wrap it in try/catch:

const { data, error } = await lingcode.functions.invoke('echo', {
  hello: 'world'
});
// data -> { hello: 'world', timestamp: '2026-06-11Tโ€ฆ' }

Or call it over REST โ€” handy from a server, a curl smoke test, or a non-JS client. POST to the function endpoint with an { input } body, authorized by the anon key or a signed-in user's token:

POST https://lingcode.dev/api/cloud/be/<backend-id>/functions/<slug>
Authorization: Bearer <anon-key-or-user-token>
Content-Type: application/json

{ "input": { "hello": "world" } }

unknown_function means the name is wrong

If an invoke returns unknown_function, the slug is misspelled or that function doesn't exist on this backend โ€” it does not mean functions are unavailable. Check the slug against the builtins below, or against the slug you gave your custom function. (For the one case where the runtime itself is down, see Availability โ€” that surfaces as 503 functions_runtime_unavailable, and only for custom functions.)

The seven builtins

These are live on every backend with no deploy step. For each one you only need to set its required secret (if any) in the Secrets vault, then invoke it by slug. Start with echo to confirm your wiring works.

SlugWhat it doesInputRequired secrets
echo Returns your input plus a timestamp. Use it to smoke-test that invoke works. anything none
send-email Sends email via LingCode's managed sender. { to, subject, html } none
elevenlabs-tts Text-to-speech. Returns base64 audio. { text, voice_id?, model_id? } โ†’ { audio_base64, content_type } ELEVENLABS_API_KEY
twilio-sms Sends an SMS via Twilio. { to, body, from?, messaging_service_sid? } TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, plus one of TWILIO_FROM or TWILIO_MESSAGING_SERVICE_SID
resend-byo Sends email via your own Resend account. { from, to, subject, html?, text? } RESEND_API_KEY
stripe-checkout Creates a Stripe Checkout Session. { price_id, success_url, cancel_url, mode?, quantity?, customer_email?, metadata? } โ†’ { id, url } STRIPE_SECRET_KEY
http-fetch Makes an outbound HTTPS request to an allow-listed host. { url, method?, headers?, body? } none of its own โ€” but header/body strings may reference vault secrets as {{SECRET_NAME}}

Smoke-test with echo

The very first thing to run on a new backend. If this returns your input back, invoke is wired and your URL + key are correct.

const { data } = await lingcode.functions.invoke('echo', { ping: 1 });
console.log(data); // { ping: 1, timestamp: '2026-06-11Tโ€ฆ' }

Create a Stripe Checkout Session

Set STRIPE_SECRET_KEY in the Secrets vault first โ€” it never touches the browser. Then call the builtin and redirect the user to the returned URL:

const { data, error } = await lingcode.functions.invoke('stripe-checkout', {
  price_id:    'price_123',
  success_url: 'https://yourapp.com/thanks',
  cancel_url:  'https://yourapp.com/pricing',
  mode:        'subscription'
});
if (error) throw error;
window.location.href = data.url; // hosted Stripe Checkout

http-fetch: secret-aware, host-restricted

http-fetch has no secret of its own, but any {{SECRET_NAME}} token in a header or body string is substituted from the vault server-side โ€” so you can call an API that needs a bearer token without the token ever reaching the client. The destination host must be on the backend's fetch-hosts allow-list; calls to hosts not on the list are refused. This is the deliberate, locked-down way to call third-party APIs without writing any code. See the tutorial Call external APIs from your backend.

Custom functions

When no builtin fits, write your own. You author custom functions in the Cloud console / IDE โ€” you give the function a slug and its TypeScript source (this is a console authoring step, not something an agent tool does for you). They run in a sandboxed Deno runtime, invoked by the same functions.invoke(slug, body?) call as the builtins.

The contract

Your source must export default a handler. Whatever you return becomes the invoke result's data. TypeScript is supported natively โ€” Deno runs it directly, no build step:

export default async function handler(input, ctx) {
  // ctx.secrets.MY_KEY  โ€” your vault secrets, server-side only
  // ctx.backendId       โ€” this backend's id
  // ctx.gateway         โ€” the backend's own data-API base URL
  return { ok: true };   // becomes the invoke result's `data`
}

The second argument ctx is your server-side context:

ctx = {
  secrets:   { /* every secret set in the vault, by name */ },
  backendId: string,
  gateway:   string   // call your own data API through this
}

A small custom function

Reads a secret from the vault and returns JSON. The secret never leaves the server:

export default async function handler(input, ctx) {
  const key = ctx.secrets.WEATHER_API_KEY;
  const city = input.city ?? 'NYC';
  const res = await fetch(
    `https://api.example.com/weather?city=${city}&key=${key}`
  );
  const json = await res.json();
  return { city, tempC: json.temp_c };
}

Invoke it from the client exactly like a builtin โ€” by its slug:

const { data, error } = await lingcode.functions.invoke('get-weather', {
  city: 'Tokyo'
});
if (error) throw error;
console.log(data.tempC);

The sandbox

Custom functions run in Deno with deny-by-default permissions. This is a feature, not a restriction to fight:

Limits

Limitfreepromax_pro
Timeout (wall-clock, SIGKILL past it)3s10s30s
Custom functions (maxFunctions)21050
Source sizeup to 256 KB
Memory128 MB

Functions are short-lived. Past the wall-clock timeout the process is SIGKILLed โ€” there's no graceful extension. Don't put anything that runs longer than ~30 seconds in a function.

Availability

Custom functions need the Deno runtime, which is installed and live in production โ€” custom functions work today. If a deployment ever lacks the runtime, custom invokes return 503 functions_runtime_unavailable while the builtins keep working (they don't depend on the Deno sandbox). So a 503 on a custom function is a runtime-availability signal; a builtin failing is something else. And remember โ€” unknown_function is always a wrong-slug error, never an availability one.

What functions are NOT for. No long-running processes, no background queues, no persistent WebSocket servers, and nothing over ~30 seconds โ€” those belong in a hosted Worker app, not a function. One honest specific: a Stripe webhook handler that needs raw-body signature verification is not one of the builtins and is awkward to express as a short custom function โ€” put it in your hosted app's own route (a Worker/SSR route) instead. The stripe-checkout builtin only creates Checkout Sessions; it does not receive webhooks.