Skip to main content
After this guide, a URL you paste into any system that sends HTTP requests wakes your agent, and code you wrote checks and shapes each event first. A trigger never runs handler code of yours and can’t control the HTTP response; when you need either, handle a webhook instead. Verified against lua-cli 3.33.0. Before you begin
  • A project created with lua init and signed in with lua auth configure (Install and sign in).
  • The sender’s payload shape and how it authenticates (a shared header or a body signature).
1

Create the trigger and copy its URL

lua triggers create registers the trigger and prints ✅ Trigger "order-created" created, the URL under 🔗 Trigger URL (paste it anywhere):, and a curl line that fires it. The token in the URL is the only credential; treat the URL like an API key.
Pasted as it is, the URL already works (Type: URL in lua triggers list): every POST body becomes a message to the agent, prefixed with [Trigger: order-created] and any --instruction. The turn runs as you, the creator, with your tools and data, unless transform returns another userId; no end user receives anything unless the model calls a tool that sends a message.
2

Shape events in code

defineTrigger has no execute. Up to four slots run on the platform per delivery, in order: verify (401 when false), filter (200 and dropped when false), transform (the event becomes the message), and tool (one tool, no model turn). The slots share a 15-second budget and can read env().
src/triggers/order-created.trigger.ts
The type argument types ctx.body in every slot. A sender that signs its payload is verified over ctx.rawBody, the exact bytes received. Store the token with lua env production -k SHOP_WEBHOOK_TOKEN -v <token>.
3

Register it and compile

Add the trigger to LuaAgent.triggers; unreferenced triggers aren’t compiled. The file below is the quickstart’s; if yours differs, add only the highlighted lines to your own LuaAgent.
src/index.ts
lua compile checks the slots.
Output
lua compile fails when no slot is set and warns when both tool and transform are declared: the tool wins.
4

Push and release the version

lua push trigger uploads the compiled slots as a version of the trigger with that name and links the lua.skill.yaml row to the trigger from Step 1 by name: one trigger, one URL (the server refuses a duplicate name). Without Step 1, the push creates the trigger and lua triggers list prints its URL. lua deploy trigger then creates and promotes an agent version scoped to this trigger, so the slots are live at once and lua triggers list shows Type: SDK.
To release it with other changes instead, skip the deploy: lua push all --ci --force, then lua version create --ci -m "Add order-created trigger", which prints ✓ Created v<n> (staged). Run `lua version promote v<n>` to deploy., then lua version promote <n> (<n> or v<n>, no confirmation; in a script n=$(lua version list --limit 1 --json --ci | jq -r '.[0].version')) (Release an agent to production).
5

Paste the URL and fire it

There is no lua test trigger, so this request is the first test. Give the sender the URL, or send one event yourself with the header verify expects.
The response is 200 with { "status": "accepted", "executionId": "…" } once the slots pass; the turn runs afterwards. A wrong x-shop-token answers 401; a type other than order.created answers 200 and is dropped.
6

Verify

Every delivery is a row in the trigger’s log for 90 days, newest first, with status, duration, payload, reply, and tools used.
Your event shows as COMPLETED with the reply text once the turn finishes, or ACCEPTED (in flight) while it runs; a bad token shows as REJECTED (verify failed → 401) and a filtered event as SKIPPED (filtered out). --json returns the rows as data.

Options you may need

Run one tool instead of a model turn

Replace transform with tool: { name: 'lookup_order', input: (ctx) => ({ orderId: ctx.body.data.orderNumber }) }: name is a string literal naming a tool in one of the agent’s skills, and input maps the event to its arguments. No message is sent; the result goes on the log row. To start a workflow run instead, return { startWorkflow } from transform (LuaTrigger reference).

Rotate a leaked token

lua triggers rotate-token --trigger order-created prints a replacement URL and the old one stops working at once; lua triggers deactivate --trigger order-created pauses deliveries without changing the URL.

If it isn’t working

The header the slot compares isn’t what the sender sends (keys are lowercase in ctx.headers), or SHOP_WEBHOOK_TOKEN isn’t set in production. Set it with lua env production -k SHOP_WEBHOOK_TOKEN -v <token>; slots read it on the next delivery.
transform returned nothing, a slot threw or ran over its budget (the sender got 500), or the turn or tool failed after the 200. Lua never redelivers, so the sender must send again; use filter, not an empty transform, to skip an event.
The URL is wrong or its token was rotated. lua triggers list prints the current URL; a request that matches no trigger is not recorded.

Next steps

LuaTrigger reference

The context object, every slot, statuses, and startWorkflow fields.

lua triggers reference

create, list, logs, activate, rotate-token, delete.

Handle a webhook

When you need your own handler and response.

Integration events

Route events from a connected SaaS to a trigger.