onvibe.run

← All docs

Cron Jobs

Run code on a schedule. The platform calls a path of your app on a cron schedule; your app handles it in its normal handler. Typical uses: send reminder emails, clean up stale rows, refresh a cache, send a daily digest.

There is no separate "cron handler" — a cron run is just an HTTP request to your app that carries an auth token and a marker header. Verify it with isCronRequest(req).

Two ways to define jobs

Add an onvibe.json file at the project root. It is reconciled on every deploy: jobs are created/updated, and jobs removed from the file are deleted.

{
  "crons": [
    {
      "name": "reminders",
      "schedule": "0 9 * * *",
      "path": "/cron/reminders",
      "timezone": "Europe/Madrid"
    }
  ]
}

2. Imperative — create_cron tool

For dynamic management. Jobs created this way are independent from onvibe.json (they are not removed by a deploy).

create_cron({ project_id, name, schedule, path, method?, timezone? })
list_crons({ project_id })
delete_cron({ project_id, name })
run_cron({ project_id, name })   // trigger once now, for testing

Handling the trigger in your app

Gate the cron logic with isCronRequest(req) so public traffic can't trigger it.

import { isCronRequest } from "./.onvibe/helpers.ts";

export default async function handler(req: Request): Promise<Response> {
  const url = new URL(req.url);
  if (url.pathname === "/cron/reminders" && isCronRequest(req)) {
    await sendReminders();           // scan DB, send emails, etc.
    return new Response("ok");
  }
  // ...rest of the app
}

isCronRequest(req) returns true only when the request carries the X-Onvibe-Cron header AND the correct APP_TOKEN bearer (set by the platform). cronName(req) returns the job name if you serve several jobs from one path.

Limits & semantics

Example: daily expiry reminders

{ "crons": [{ "name": "reminders", "schedule": "0 9 * * *", "path": "/cron/reminders", "timezone": "Europe/Madrid" }] }
import { isCronRequest } from "./.onvibe/helpers.ts";

async function handler(req: Request): Promise<Response> {
  const url = new URL(req.url);
  if (url.pathname === "/cron/reminders" && isCronRequest(req)) {
    const { rows } = await pool.query(
      "SELECT email, name FROM items WHERE expires_on = CURRENT_DATE + 3",
    );
    for (const r of rows) {
      // send an email to r.email (see onvibe://docs/email when available)
    }
    return new Response(`sent ${rows.length}`);
  }
  return new Response("not found", { status: 404 });
}
export default handler;

Notes

Read this page as Markdown (best for LLMs) · plain text
onvibe.run · home · all docs