Jobs Done is a reliable job scheduler. Register once, get an API key, and start firing cron-triggered HTTP callbacks in minutes — no infrastructure required.
# Register and get your API key
$ jobs_done user register "My App"
Name: My App
API Key: jd_sk_8f3e...c21a
# Schedule a daily cron job
$ jobs_done cron create \
--name "daily-report" \
--cron "0 9 * * *" \
--url "https://myapp.com/webhooks/daily"
{"id": 1, "name": "daily-report", "active": true}
A focused feature set — no noise, no vendor lock-in.
Create, pause, resume, and delete cron jobs live — no redeploys needed. Standard 5-field cron expressions supported.
Configure max attempts per job. Failed webhook calls are retried with exponential backoff via the Oban queue engine.
Each user gets an isolated API key. All resources are strictly scoped — you only see your own jobs.
Need a single fire-and-forget job? Use POST /api/enqueue
or the CLI enqueue command.
Track success, failure, and retry counts per cron job via
GET /api/users/me/stats.
Full OpenAPI 3.0 spec at /api/openapi with
SwaggerUI included. Integrate in minutes with any language.
One POST /api/users call — or one CLI command.
Pass your webhook URL and a cron expression. We handle the rest.
Your endpoint receives a POST with the JSON body on schedule.
Monitor with GET /api/users/me/stats.
The jobs_done CLI gives you full control from your terminal, CI pipeline, or LLM agent. JSON output everywhere — pipe it, parse it, automate it.
# Apple Silicon (arm64)
$ curl -fsSL https://github.com/your-org/jobs-done/releases/latest/download/jobs_done-darwin-arm64 \
-o /usr/local/bin/jobs_done && chmod +x /usr/local/bin/jobs_done
# Intel (amd64)
$ curl -fsSL https://github.com/your-org/jobs-done/releases/latest/download/jobs_done-darwin-amd64 \
-o /usr/local/bin/jobs_done && chmod +x /usr/local/bin/jobs_done
$ jobs_done --version
jobs_done v1.0.0
# Register and get your API key
$ jobs_done user register "My App"
Name: My App
API Key: jd_sk_8f3e...c21a
# Schedule a daily cron (fires at 09:00 UTC every day)
$ jobs_done cron create \
--name "daily-report" \
--cron "0 9 * * *" \
--url "https://myapp.com/webhooks/daily"
{"id": 1, "name": "daily-report", "cron_expression": "0 9 * * *", "active": true}
# List all your cron jobs
$ jobs_done jobs list
[{"id":1,"name":"daily-report","active":true,"next_run":"2026-03-27T09:00:00Z"}]
# Enqueue a one-off job (idempotent — safe to call multiple times)
$ jobs_done jobs enqueue \
--id "send-welcome-email-user-123" \
--url "https://myapp.com/webhooks/welcome"
{"logic_id": "send-welcome-email-user-123", "status": "scheduled"}
LLM & agent-friendly
Every command outputs clean JSON — perfect for piping into jq, scripting in CI, or driving from an AI agent. Pass --output json to suppress any decorative output. The CLI is stateless and reads JOBSDONE_API_KEY from the environment — no interactive prompts in automation mode.
Zero infrastructure to manage. Jobs Done handles scheduling, retries, and delivery — you just write the webhook handler.
If your webhook returns a non-2xx status code, Jobs Done automatically retries the delivery using exponential backoff — powered by Oban's battle-tested queue engine. Your jobs run even if your server has a blip.
POST the same logic_id twice and you get the existing job back — not a duplicate. Safe to call on every deploy or from retry loops in your own code.
import { createClient } from 'jobsdone-sdk';
const client = createClient({
apiKey: process.env.JOBSDONE_API_KEY,
});
// Idempotent — safe to call on every deploy
await client.enqueue({
logicId: `welcome-email-user-${userId}`,
description: 'Send welcome email',
});
// Schedule a recurring report
await client.crons.create({
name: 'daily-report',
cronExpression: '0 9 * * *',
webhookUrl: 'https://myapp.com/webhooks/daily',
});
Restrict who can call your webhook
Jobs Done fires an HTTP POST to your webhook URL when a job triggers. Anyone who discovers that URL could trigger it directly — bypassing your schedule entirely.
Protect your endpoints with one or both of these approaches:
Allowlist Jobs Done's origin
Configure your server or CDN firewall to only accept POST requests from Jobs Done's IP range or domain (api.jobsdone.io). Requests from any other origin are rejected before they reach your handler.
Embed a shared secret in the URL path
Include an unguessable token in your webhook URL. Only Jobs Done (and you) know the full path.
Coming soon: HMAC request signing. Jobs Done will sign every outgoing request with a shared secret so your handler can cryptographically verify the origin.
Zero infrastructure
No cron daemons, no worker processes, no Redis. One API call and you're done.
Oban-backed reliability
Built on Oban — the most battle-tested job queue in the Elixir ecosystem. Persistent, transactional, and observable.
Connection pooling for high volume
Connection pooling for high volume. Scales to thousands of concurrent jobs efficiently.
OpenAPI-first
Full OpenAPI 3.0 spec ships with the server. SDKs are generated from it — Node.js available today, Python and Ruby coming soon.
Enqueue with a stable logic_id like welcome-user-42. Call it on signup and on every deploy — you'll never send duplicates.
Fire a webhook every morning at 09:00 UTC. Your handler queries the DB, renders the report, and sends it — Jobs Done handles the clock.
Trigger a nightly data export to S3 or a data warehouse. If the export fails, automatic retries ensure it completes before morning.
No hidden fees. Cancel any time.
Free
$0
Forever
Pro
$9
per month
No credit card required. Start in 60 seconds.