Quick Start: Push (HTTP)
Chronos sends HTTP requests to your endpoint when a job is due. No long-lived worker process needed.
Prerequisites
Section titled “Prerequisites”- Node.js 20 or later
- A Chronos account (sign up free)
- An API key (create one in the dashboard under Settings → API Keys)
- A publicly reachable HTTPS endpoint (or a tunnel for local dev)
- For the Node.js tabs,
@chronos.sh/sdk0.2.0 or later, installed with the package manager from step 1 - For the Go tabs, Go 1.26 or later
-
Install Express
Terminal window pnpm add expressTerminal window npm install expressTerminal window yarn add express -
Write your handler
server.mjs import express from 'express';const app = express();app.use(express.json());app.post('/hooks/chronos', (req, res) => {const { handler, payload, job_id, attempt } = req.body;if (handler !== 'hello') {console.warn(`Unknown handler: ${handler}`);return res.sendStatus(400);}console.log(`Job ${job_id} running (attempt ${attempt})`);res.sendStatus(200);});app.listen(3000, () => console.log('Listening on :3000'));Return 200 for success, 4xx for permanent failures, 5xx for transient failures you want retried.
-
Start the server
Terminal window node server.mjsYour server is now listening on port 3000.
-
Create a job
In a second terminal, create a one-off job with push delivery:
Terminal window curl -X POST https://api.chronos.sh/v1/jobs \-H "Authorization: Bearer chrns_your_api_key" \-H "Content-Type: application/json" \-d '{"name": "My first job","handler": "hello","delivery": {"type": "push","http": {"url": "https://your-server.com/hooks/chronos","method": "POST"}}}'create-job.mjs import { Chronos } from '@chronos.sh/sdk';const chronos = new Chronos({ apiKey: process.env.CHRONOS_API_KEY });await chronos.jobs.create({name: 'My first job',handler: 'hello',delivery: {type: 'push',http: { url: 'https://your-server.com/hooks/chronos', method: 'POST' },},});Terminal window CHRONOS_API_KEY=chrns_your_api_key node create-job.mjscreate-job.go package mainimport ("context""log""os"chronos "chronos.sh/go")func main() {client, err := chronos.NewClient(os.Getenv("CHRONOS_API_KEY"))if err != nil {log.Fatal(err)}_, err = client.Jobs.Create(context.Background(), chronos.JobCreateParams{Name: "My first job",Handler: new("hello"),Delivery: &chronos.Delivery{Type: chronos.DeliveryTypePush,HTTP: &chronos.HTTPDelivery{URL: "https://your-server.com/hooks/chronos", Method: "POST"},},})if err != nil {log.Fatal(err)}}Terminal window go mod init hello && go get chronos.sh/goCHRONOS_API_KEY=chrns_your_api_key go run create-job.goChronos sends an HTTP request to your endpoint. You should see:
Job a8f3e2b1-... running (attempt 1)
What just happened
Section titled “What just happened”- You created a one-off job with push delivery
- Chronos sent an HTTP POST to your endpoint
- Your handler processed the request and returned 200
- Chronos recorded the execution as
completed
If your endpoint had returned 5xx or timed out, Chronos would have retried up to 3 times with exponential backoff.
Make it recurring
Section titled “Make it recurring”Create a schedule with push delivery and your server receives jobs automatically:
curl -X POST https://api.chronos.sh/v1/schedules \ -H "Authorization: Bearer chrns_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Hello every 10 minutes", "handler": "hello", "interval": { "value": 10, "unit": "minute" }, "delivery": { "type": "push", "http": { "url": "https://your-server.com/hooks/chronos", "method": "POST" } } }'import { Chronos } from '@chronos.sh/sdk';
const chronos = new Chronos({ apiKey: process.env.CHRONOS_API_KEY });
const schedule = await chronos.schedules.create({ name: 'Hello every 10 minutes', handler: 'hello', interval: { value: 10, unit: 'minute' }, delivery: { type: 'push', http: { url: 'https://your-server.com/hooks/chronos', method: 'POST' }, },});console.log(schedule.id);CHRONOS_API_KEY=chrns_your_api_key node create-schedule.mjspackage main
import ( "context" "fmt" "log" "os"
chronos "chronos.sh/go")
func main() { client, err := chronos.NewClient(os.Getenv("CHRONOS_API_KEY")) if err != nil { log.Fatal(err) } schedule, err := client.Schedules.Create(context.Background(), chronos.ScheduleCreateParams{ Name: "Hello every 10 minutes", Handler: new("hello"), Interval: &chronos.Interval{Value: 10, Unit: chronos.IntervalUnitMinute}, Delivery: &chronos.Delivery{ Type: chronos.DeliveryTypePush, HTTP: &chronos.HTTPDelivery{URL: "https://your-server.com/hooks/chronos", Method: "POST"}, }, }) if err != nil { log.Fatal(err) } fmt.Println(schedule.ID)}CHRONOS_API_KEY=chrns_your_api_key go run create-schedule.goYour running server now receives a new request every 10 minutes. To stop it, archive the schedule:
curl -X POST https://api.chronos.sh/v1/schedules/SCHEDULE_ID/archive \ -H "Authorization: Bearer chrns_your_api_key"import { Chronos } from '@chronos.sh/sdk';
const chronos = new Chronos({ apiKey: process.env.CHRONOS_API_KEY });
await chronos.schedules.archive(process.argv[2]);CHRONOS_API_KEY=chrns_your_api_key node archive-schedule.mjs SCHEDULE_IDpackage main
import ( "context" "log" "os"
chronos "chronos.sh/go")
func main() { client, err := chronos.NewClient(os.Getenv("CHRONOS_API_KEY")) if err != nil { log.Fatal(err) } if _, err := client.Schedules.Archive(context.Background(), os.Args[1]); err != nil { log.Fatal(err) }}CHRONOS_API_KEY=chrns_your_api_key go run archive-schedule.go SCHEDULE_IDNext steps
Section titled “Next steps” Signature Verification Verify that requests actually come from Chronos
Push Delivery Response rules, custom headers, debugging tips
API Reference Full endpoint documentation