Webhooks & schedules
Accept external POSTs and fire workflows on a cron — registered as JSON manifests under .appbricx/backend/, synced into platform Postgres so the ticker and public hook router can find them.
Webhooks
Manifest
// .appbricx/backend/webhooks/lead-intake.json
{
"id": "lead-intake",
"name": "lead-intake",
"workflow": "on-lead-created",
"secret_ref": "WEBHOOK_SECRET",
"enabled": true
}Put the secret value in project env / vault under the name WEBHOOK_SECRET — never in the JSON file. Declare the name in secrets.refs.json.
Call it
curl -sS -X POST "$ORIGIN/hooks/$PROJECT_ID/lead-intake" \
-H "content-type: application/json" \
-H "x-appbricx-webhook-secret: $WEBHOOK_SECRET" \
-d '{"email":"demo@example.com","source":"stripe"}'
# → { "ok": true, "runId": "…" }- Public route (no browser JWT). Rate limited (~60/min/project).
- Payload lands on
ctx.trigger.payload.body(plus headers metadata). - Prefer
runtime.upsert_webhook; editorcreate_filealso syncs disk → DB.
Internal flow
- Caddy routes
/hooks/*→ API. - Load webhook from
app_runtime_webhooks(fallback: JSON file). - Compare secret header to env value for
secret_ref. enqueueWorkflowRunwithtriggerType: "webhook".
Schedules (cron)
Manifest
// .appbricx/backend/schedules/nightly-lead-digest.json
{
"id": "nightly-lead-digest",
"cron": "0 21 * * *",
"timezone": "UTC",
"workflow": "nightly-digest",
"enabled": true
}- Five-field cron (
min hour dom month dow). - Prefer
runtime.upsert_schedulesonext_run_atis computed in DB immediately. - Writing the JSON via the agent also registers the row (disk → DB sync). Unchanged specs preserve
next_run_atso editor polls do not delay fires.
List schedules (session JWT — editor)
GET /projects/:projectId/backend/schedules
Authorization: Bearer <platform session>Syncs from disk first, then returns ticker state (next_run_at, enabled, cron).
Demo tip
For a social clip, temporarily set */1 * * * *, invoke the workflow with runtime.workflows.invoke / Backend → Test, then show the nightly cron in the file tree.
Internal flow
- Process boot starts the schedule ticker (~15s tick).
- Due rows in
app_runtime_schedulesare leased and enqueue the named workflow withtriggerType: "cron". next_run_atadvances to the next cron occurrence.
Email digests need a connected Resend / SendGrid / Gmail integration before
ctx.messages.email succeeds. Until then, log the count and publish a topic (see saas-leads nightly-digest pack).Related: Workflows · Topics & CDC