Jobs Done
Cron-as-a-Service

Schedule webhooks. Ship faster.

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.

Create free account See how it works
Terminal
# 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}

Everything you need to ship

A focused feature set — no noise, no vendor lock-in.

Persistent cron jobs

Create, pause, resume, and delete cron jobs live — no redeploys needed. Standard 5-field cron expressions supported.

🔁

Automatic retries

Configure max attempts per job. Failed webhook calls are retried with exponential backoff via the Oban queue engine.

🔑

API key auth

Each user gets an isolated API key. All resources are strictly scoped — you only see your own jobs.

📬

One-off webhooks

Need a single fire-and-forget job? Use POST /api/enqueue or the CLI enqueue command.

📊

Job analytics

Track success, failure, and retry counts per cron job via GET /api/users/me/stats.

📖

OpenAPI spec

Full OpenAPI 3.0 spec at /api/openapi with SwaggerUI included. Integrate in minutes with any language.

Up and running in 3 steps

  1. 1

    Register and get your API key

    One POST /api/users call — or one CLI command.

    curl -X POST https://api.jobsdone.io/api/users -d '{"name":"My App"}' -H 'Content-Type: application/json'
  2. 2

    Create a cron job

    Pass your webhook URL and a cron expression. We handle the rest.

    curl -X POST .../api/crons -H 'X-API-Key: <key>' \
      -d '{"name":"ping","cron_expression":"* * * * *","webhook_url":"https://myapp.com/hook"}'
  3. 3

    Receive webhooks & check stats

    Your endpoint receives a POST with the JSON body on schedule. Monitor with GET /api/users/me/stats.

CLI & Automation

A CLI built for developers & agents

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.

Install

macOS — Apple Silicon & Intel
# 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

Key commands

jobs_done CLI
# 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.

Docs & Best Practices

Built for reliability

Zero infrastructure to manage. Jobs Done handles scheduling, retries, and delivery — you just write the webhook handler.

🔁 Automatic retries & idempotency

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.

Attempt 1immediately
Attempt 2+30 seconds
Attempt 3+2 minutes
Attempt Nexponential backoff

Idempotent enqueue

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.

Node.js SDK

TypeScript · jobsdone-sdk npm install jobsdone-sdk
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',
});

🔒 Webhook security

⚠️

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:

1

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.

2

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.

https://myapp.com/webhooks/a8f3c2e1d9b7/daily-report
ℹ️

Coming soon: HMAC request signing. Jobs Done will sign every outgoing request with a shared secret so your handler can cryptographically verify the origin.

Why Jobs Done?

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.

Real-world examples

📧

Retry-safe welcome emails

Enqueue with a stable logic_id like welcome-user-42. Call it on signup and on every deploy — you'll never send duplicates.

$ jobs_done jobs enqueue \
  --id "welcome-user-42" \
  --url ".../webhooks/welcome"
📊

Daily report emails

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.

$ jobs_done cron create \
  --name "daily-report" \
  --cron "0 9 * * *" \
  --url ".../webhooks/report"
🗄️

Scheduled data exports

Trigger a nightly data export to S3 or a data warehouse. If the export fails, automatic retries ensure it completes before morning.

$ jobs_done cron create \
  --name "nightly-export" \
  --cron "0 2 * * *" \
  --url ".../webhooks/export"

Simple pricing

No hidden fees. Cancel any time.

Free

$0

Forever

  • 5 cron jobs
  • 100 webhook calls / day
  • 3 retry attempts
  • API + CLI access
Get started

Pro

$9

per month

  • Unlimited cron jobs
  • Unlimited webhook calls
  • Up to 10 retry attempts
  • Priority support
  • Job history & analytics
Upgrade to Pro

Ready to schedule your first job?

No credit card required. Start in 60 seconds.