Scheduled Jobs

The bext SDK scheduler runs recurring jobs for a PRISM app. You register a named entry with a cron/schedule, and on each cadence the scheduler POSTs a handler you own. It is reached over the loopback SDK at http://127.0.0.1/__bext/sdk/scheduler/*, authenticated by the X-Bext-App-Id header (see SDK Overview).

Tip

This is the recommended way to run cron-style work. Do not use system crontab when the scheduler will do — see Prefer the scheduler over system cron.

Endpoints

Method Path Purpose
POST /__bext/sdk/scheduler/register Create or update a schedule entry
GET /__bext/sdk/scheduler/list List this app's schedule entries
POST /__bext/sdk/scheduler/cancel Cancel an entry

Register

POST http://127.0.0.1/__bext/sdk/scheduler/register
X-Bext-App-Id: <app-id>
Content-Type: application/json

Body fields:

Field Required Notes
name yes Unique entry name for this app
schedule / cron yes The cadence — a cron expression (validated on register)
kind no Entry kind
command / handler_url / task yes (one of) What to run on cadence
payload no Passed to the target
cwd no Working directory (for command entries)
timeout_secs no Per-run timeout
enabled no Set false to register a disabled entry

The cron expression is validated at register time — an invalid expression is rejected.

For a PRISM app the usual target is handler_url: on each cadence the scheduler POSTs your handler URL. Register the handler as one of your app's own routes.

// register a daily report handler
await fetch("http://127.0.0.1/__bext/sdk/scheduler/register", {
  method: "POST",
  headers: {
    "X-Bext-App-Id": "<app-id>",
    "content-type": "application/json",
  },
  body: JSON.stringify({
    name: "daily-report",
    cron: "0 6 * * *",
    handler_url: "https://<app>.inklura.fr/api/cron/daily-report?key=<secret>",
  }),
});

List

GET http://127.0.0.1/__bext/sdk/scheduler/list
X-Bext-App-Id: <app-id>

Returns this app's registered entries.

Cancel

POST http://127.0.0.1/__bext/sdk/scheduler/cancel
X-Bext-App-Id: <app-id>
Content-Type: application/json

{ "name": "daily-report" }

Authenticating scheduled HTTP hits

The scheduler POSTs your handler_url from the platform, so your handler route must decide for itself whether to trust the call. The common convention is a shared secret carried in the query string: register the cron route with ?key=<secret> and have the handler check that key before doing any work.

// src/app/api/cron/daily-report/route.ts
export async function POST(req: Request) {
  const key = new URL(req.url).searchParams.get("key");
  if (key !== process.env.CRON_SECRET) {
    return new Response("forbidden", { status: 403 });
  }
  // …run the job…
  return new Response("ok");
}

Real PRISM apps register cron routes this way — for example daily-report, pacing-watchdog, flight-end, and monthly-billing.

Warning

The secret is in the URL, so treat it like any URL secret: keep it out of logs, rotate it if leaked, and always run cron routes over HTTPS on your public vhost.

Prefer the scheduler over system cron

Platform convention: don't use system cron — use the bext scheduler (or the queue). The scheduler is managed per app, validated, listable, and cancellable through the SDK; a system crontab entry is invisible to the platform and outlives the app it was meant for.

Long-running scheduled work

The scheduler's job is to fire on cadence, not to run long. If the work a schedule kicks off is heavy or slow, have the handler enqueue onto the queue or hand off to the warm task-executor rather than blocking the cron hit — see SDK → Tasks.

Related: workflow automation (company-manager)

Separately from the bext scheduler, the company-manager backend declares a workflow-scheduled BullMQ queue (alongside workflow-execution, workflow-node, and workflow-webhook) that drives time-based steps in its own workflow-automation engine. That is platform-internal and not the same surface as the app-facing scheduler here — see Events Overview.

See also