MonkeyTasks
A durable task scheduler with recurring schedules, webhook authentication, and instant status tracking. Define tasks with execution config and cron schedules, fire them on-demand or let the scheduler handle it, and track every run.
Concepts
| Concept | Description |
|---|---|
| Task | A named definition that owns its webhook config, schedules, and execution settings. Create once, run many times. |
| TaskRun | A single execution of a task. Created by a schedule firing, an on-demand run, or a retry. |
| Schedule | A cron expression on a task. When it fires, MonkeyTasks automatically creates a new run. |
Quick Start
typescript
// Create a task
const task = await monkey.tasks.create({
name: 'weekly-report',
execution: {
url: 'https://api.myapp.com/hooks/report',
auth: { type: 'hmac', secret: 'whsec_abc123...' },
payload: { reportType: 'weekly' },
timeout: 60,
maxRetries: 3,
},
schedules: [
{ title: 'Every Monday at 9am', cron: '0 9 * * MON', timezone: 'America/New_York' },
],
})
// Fire immediately
const run = await task.runNow()
console.log(run.id) // "run_01JDXYZ..."
console.log(run.status) // "queued"Task Management
typescript
// List all tasks
const tasks = await monkey.tasks.list()
// Filter by group, status, or tag
const reporting = await monkey.tasks.list({ group: 'reporting' })
const paused = await monkey.tasks.list({ status: 'paused' })
// Look up by ID or name
const task = await monkey.tasks.lookup('weekly-report')
// Update
await monkey.tasks.update('weekly-report', {
description: 'Updated description',
execution: { timeout: 120 },
})
// Pause / resume all schedules
await task.pause()
await task.resume()
// Remove (cancels pending runs)
await monkey.tasks.remove('weekly-report')Run Tasks
With delay
Delays accept seconds, duration strings, or absolute timestamps.
typescript
// Seconds
await task.runNow({ delay: 300 })
// Duration string — supports 's', 'm', 'h', 'd'
await task.runNow({ delay: '30m' })
// Absolute timestamp (prefix with @)
await task.runNow({ delay: '@2026-03-20T09:00:00Z' })Note: Delays under 15 minutes use SQS native delay. Longer delays are persisted and enqueued when the time arrives.
With custom payload
typescript
// Override the default payload for this run
await task.runNow({ payload: { userId: '123', format: 'csv' } })Batch run
Run up to 10 tasks in a single call.
typescript
const runs = await task.runBatch([
{ payload: { userId: '1' } },
{ payload: { userId: '2' } },
{ payload: { userId: '3' } },
])Schedules (Cron)
Schedules are defined directly on the task. When a schedule fires, MonkeyTasks creates a run using the task's execution config.
typescript
// Create a task with schedules
const task = await monkey.tasks.create({
name: 'daily-report',
schedules: [
{ title: 'Every weekday at 9am', cron: '0 9 * * MON-FRI', timezone: 'America/New_York' },
{ title: 'Sunday recap', cron: '0 18 * * SUN' },
],
execution: {
url: 'https://api.myapp.com/hooks/report',
allowOverlap: false,
},
})
// Update schedules via task update
await monkey.tasks.update('daily-report', {
schedules: [
{ title: 'Every weekday at 10am', cron: '0 10 * * MON-FRI', timezone: 'America/New_York' },
],
})
// Pause all schedules
await task.pause()
// Resume
await task.resume()Cron format
Standard 5-field cron with optional timezone (defaults to UTC). Minimum interval is 1 minute.
| Expression | Meaning |
|---|---|
| 0 9 * * MON | Every Monday at 9am |
| */15 * * * * | Every 15 minutes |
| 0 0 1 * * | First day of every month at midnight |
Run Lifecycle
scheduled→queued→processing→completed
→failed→(retry up to maxRetries)→dead_letter
any state→cancelled
Run History
typescript
// List recent runs
const history = await task.listHistory(25)
// Filter by status
const failures = await task.listHistory(50, { status: 'failed' })
// Get a specific run
const run = await task.getRun('run_01JDXYZ...')
// {
// id: 'run_01JDXYZ...',
// taskId: 'task_abc...',
// taskName: 'weekly-report',
// trigger: 'schedule',
// scheduleTitle: 'Every Monday at 9am',
// status: 'completed',
// result: { statusCode: 200 },
// startedAt: 1710345601000,
// completedAt: 1710345603000,
// }
// Cancel a pending run
await task.cancel('run_01JDXYZ...')
// Retry a dead-lettered run
await task.retry('run_01JDXYZ...')Webhook Authentication
Three auth modes, configured in the task's execution block.
| Mode | Header sent |
|---|---|
| HMAC (recommended) | X-MonkeyHub-Signature: sha256=<HMAC-SHA256(timestamp.body, secret)> |
| Bearer token | Authorization: Bearer <token> |
| Custom header | <name>: <value> |
Verifying webhooks
typescript
import { verifyWebhook } from '@monkeyhub/sdk'
const isValid = verifyWebhook({
signature: req.headers['x-monkeyhub-signature'],
timestamp: req.headers['x-monkeyhub-timestamp'],
body: req.body,
secret: process.env.MONKEYHUB_WEBHOOK_SECRET,
})API Routes
| Method | Route | Description |
|---|---|---|
| POST | /api/tasks | Create a task |
| GET | /api/tasks | List tasks |
| GET | /api/tasks/:idOrName | Get a task by ID or name |
| PUT | /api/tasks/:idOrName | Update a task |
| DELETE | /api/tasks/:idOrName | Remove a task |
| POST | /api/tasks/:idOrName/pause | Pause task |
| POST | /api/tasks/:idOrName/resume | Resume task |
| POST | /api/tasks/:idOrName/run | Fire a run |
| POST | /api/tasks/:idOrName/run/batch | Fire a batch (max 10) |
| GET | /api/tasks/:idOrName/runs | List runs |
| GET | /api/tasks/:idOrName/runs/:runId | Get a specific run |
| POST | /api/tasks/:idOrName/runs/:runId/cancel | Cancel a run |
| POST | /api/tasks/:idOrName/runs/:runId/retry | Retry a dead-letter run |
| POST | /api/tasks/:idOrName/auth/rotate | Rotate webhook auth |
Limits
| Baby Monkey | Chimp | Mandrill | Silverback | |
|---|---|---|---|---|
| Tasks/sec | 5 | 10 | 50 | 500 |
| Max batch run | 10 | 10 | 10 | 10 |
| Max retries | 10 | 10 | 10 | 10 |
| Webhook timeout | 300s | 300s | 300s | 300s |
| Run retention (terminal) | 30 days | 30 days | 30 days | 30 days |
| Min cron interval | 1 min | 1 min | 1 min | 1 min |