Skip to content

Triggers

A trigger decides how your function runs. A function can be reached in three ways:

Trigger How it fires Input arrives as
Manual You run it on demand (from the dashboard, or however you manage your functions). ctx.req
HTTP Someone calls a public URL (/api/fn/{slug}). ctx.req
Event A change happens in your data (a row is inserted, updated, or deleted). ctx.event

You can attach more than one trigger to the same function. Read whichever input applies:

const input = ctx.req ?? ctx.event ?? {};

Manual triggers

Manual runs are the simplest — you invoke the active version yourself and pass an optional payload. The payload becomes ctx.req.

index.js
export async function handler(ctx) {
  const { name = "world" } = ctx.req ?? {};
  return { greeting: `Hello, ${name}!` };
}

Running it with { "name": "Ada" } returns { "greeting": "Hello, Ada!" }.

Manual runs are ideal for testing while you build, for one-off maintenance tasks, and for jobs you kick off by hand.


HTTP triggers

An HTTP trigger gives your function a public URL that your app can call. You pick a slug, and your function becomes reachable at:

POST /api/fn/{slug}

The endpoint accepts GET, POST, PUT, PATCH, and DELETE.

Authentication

HTTP triggers are called by your app users (consumers), using the same Bearer token they use for the rest of the AppAmbit API. The app is derived from that token, so a token can only ever reach its own app's functions.

Header Value
Authorization Bearer {CONSUMER_TOKEN}
Content-Type application/json

See Consumers for how to obtain a consumer token.

What your function receives

For HTTP triggers, ctx.req is the incoming request:

ctx.req
{
  "method": "POST",
  "slug": "my-endpoint",
  "query":   { /* query-string parameters */ },
  "headers": { /* request headers */ },
  "body":    { /* parsed JSON body, or form fields */ }
}

The authenticated caller also rides along as ctx.consumer ({ id }) so you know who is calling.

Sensitive headers are stripped

Before your function sees the request, AppAmbit removes the cookie, authorization, and internal auth headers. Don't rely on reading the caller's raw token — use ctx.consumer.id instead.

Shaping the response

By default, whatever you return is sent back as JSON with a 200 status:

export async function handler(ctx) {
  return { ok: true }; // → 200, body {"ok":true}
}

To control the status code or headers, return an object with a body (and optional status / headers):

export async function handler(ctx) {
  const { id } = ctx.req.body ?? {};
  if (!id) {
    return { status: 400, body: { error: "id is required" } };
  }
  return {
    status: 201,
    headers: { "X-Custom": "yes" },
    body: { created: id },
  };
}

Status codes you might see

Beyond your own responses, the platform maps certain conditions to HTTP statuses:

Status Meaning
200 Success (or your custom status).
401 The caller wasn't authenticated.
402 Your plan doesn't include Cloud Code (when plan enforcement is on).
404 No enabled HTTP trigger matches that slug.
429 You've hit the invocation rate limit — slow down and retry.
500 Your function threw an error or failed.
503 The function has no active version to run.
504 Your function ran past its timeout.

Every response includes an X-Request-Id header you can use to look up the exact invocation and its logs.

Calling it

You can test an HTTP trigger with any API client (curl, Postman, your app) — it's a normal authenticated AppAmbit API request:

  1. Get a consumer token for your app — see Consumers.
  2. POST (or GET/PUT/PATCH/DELETE) to /api/fn/{slug} with the Authorization: Bearer header. The app is derived from the token, so no app key is needed.
  3. Read the response — your return value (or the body/status you shaped above), plus an X-Request-Id header.
  4. Trace the run — pass that X-Request-Id to the logs to see exactly what your function did on this call.
curl
curl -i -X POST https://api.appambit.com/api/fn/hello \
  -H "Authorization: Bearer {CONSUMER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Ada" }'

Testing without deploying

You don't need an HTTP trigger to try a function — use a manual run (see above, or the dashboard "Run" button) to execute the latest version and inspect its output and logs first, then wire up the HTTP trigger once it behaves.


Event triggers

An event trigger runs your function automatically when your data changes — for example, whenever a row is inserted into a table, or an entry is updated in a CMS collection.

An event trigger is configured with:

  • a source — your app database (db) or your CMS (cms),
  • the table or collection to watch,
  • the operations to react to — any of insert, update, delete.

When it fires, the details of the change arrive as ctx.event:

index.js
export async function handler(ctx) {
  const change = ctx.event ?? {};
  ctx.log("data changed", change);
  // react to the change — send a notification, update a summary, etc.
  return { handled: true };
}

Great for keeping things in sync

Event triggers shine for reactions you don't want your app to wait on: sending a push when an order row is inserted, recomputing a leaderboard when scores change, or notifying a channel when new content is published.


What's next

  • Configuration & Limits


    Set environment variables and secrets, adjust memory and timeout, and understand quotas.

    View Guide ➔

  • Examples & Tips


    See HTTP and event functions end to end.

    View Guide ➔