App Functions — Design the Trigger & Execution Type
Decide what runs and when before you write any code.
Step 1 — Confirm the event contract
The doc-grounded event catalog — every trigger grouped Merchant vs Customer, its
sync/async type, and its documented payload.data shape — lives in
references/event-contexts.md. Use it to pick the trigger
and read the context shape; never assume a payload.
Sources of truth: salla_functions action=list_triggers (no app_id needed) for live
trigger names and categories; salla_functions action=get for a trigger's authoritative
.d.ts. Customer-event docs ship illustrative payloads — confirm those field names via
action=get or the schema doc before relying on them.
Gate: "Do you have the confirmed payload.data field names for this event?"
Step 2 — Choose the execution type
| Type | Timing | Blocks user? | Timeout | Return value effect |
|---|---|---|---|---|
| Asynchronous event | After the operation | No | 30 s | Fire-and-forget: logged, does not affect the flow. |
| Synchronous action | Before the operation | Yes | 5 s total | Blocking: can modify parameters or reject/block the operation. |
- Sync actions are exactly the
merchant_actionscategory —shipment.creatingandshipment.cancelling(confirm the category viasalla_functions action=list_triggersrather than the verb form). They intercept the lifecycle before it completes: erroring cancels the operation, succeeding can modify its data.shipment.creatingis the documented sync example and returns aShipment((context: Shipments): Promise<Shipment>), not a plainResp— it sets the shipment number/label. Builder mechanics → salla-app-functions-handler. - Async events (e.g.
order.created,product.added) run out-of-band; return a valid success/error result so it's recorded in logs.
Timeout budget
| Type | Total timeout | Per internal async call |
|---|---|---|
| Sync | 5 s hard limit, < 500 ms target | < 2 s, bound with AbortController |
| Async | 30 s | bound with AbortController |
The merchant is blocked during a sync action, so treat < 500 ms as the goal and 5 s as the
ceiling. Bounding each fetch / awaited I/O keeps one slow upstream from blowing the budget
(AbortController mechanics → salla-app-functions-handler). An overrun blocks (sync) or
drops (async) the run.
Gate: "Sync or async decided, and the timeout budget understood?"
Security & data hand-offs
When the handler touches tokens, merchant authentication, or outbound calls, route those out: token storage / OAuth / merchant access tokens → salla-app-auth; webhook signature verification & idempotency → salla-webhooks. Full hand-off list → references/event-contexts.md.
Next: write it in salla-app-functions-handler.