Use Cases
Common patterns for web apps that need background processing.
Async Processing
Offload slow tasks from your request-response cycle. Return immediately to users while work happens in the background.
Email Sequences
Schedule follow-up emails without managing queues or workers.
// Schedule welcome email 24 hours after signup import { Runlater } from "runlater-js" const rl = new Runlater(process.env.RUNLATER_KEY) await rl.delay("https://myapp.com/api/send-welcome", { name: "welcome-email", delay: "24h" })
Report Generation
Generate PDFs or exports without timing out. Email when ready.
// Return immediately, process in background import { Runlater } from "runlater-js" const rl = new Runlater(process.env.RUNLATER_KEY) await rl.delay("https://myapp.com/api/reports/generate", { body: { reportId, userId }, delay: "1h" }) return Response.json({ status: "processing" })
Webhook Relay
Acknowledge webhooks fast, process reliably later.
// Stripe webhook - return 200 immediately export async function POST(req) { const event = await req.json(); await fetch('https://runlater.eu/api/v1/tasks', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, body: JSON.stringify({ url: 'https://myapp.com/api/process-stripe', body: JSON.stringify(event) }) }); return Response.json({ received: true }); }
Inbound Endpoints
Receive webhooks from external services like Stripe, GitHub, or Shopify. Runlater stores every event, forwards it to your app with retries, and lets you replay failures from the dashboard. No webhook handler code needed — just point the service at your Runlater inbound URL.
Stripe Webhook Receiver
Point Stripe at your Runlater endpoint. Every event is stored, forwarded to your app with retries, and replayable.
1. Create an endpoint in the dashboard with your forward URL(s):
https://myapp.com/api/stripe/process
2. Copy the inbound URL and paste it in Stripe's webhook settings:
https://runlater.eu/in/ep_abc123...
3. That's it. Runlater handles retries, stores every event, and you can replay failures from the dashboard.
GitHub Deploy Hooks
Trigger deploys or post-merge workflows from GitHub push events. Events are serialized so deploys never overlap.
Create an endpoint named github-deploys. Events from the same endpoint are serialized, so pushes are processed one at a time.
Forward URLs:
https://myapp.com/api/deploy
Add the inbound URL as a GitHub webhook on your repo → Settings → Webhooks.
Shopify Order Processing
Receive order webhooks reliably. Never miss an order even if your server is temporarily down.
Runlater stores the raw payload and retries delivery up to 5 times with exponential backoff. If your app was down during a webhook, just hit Replay in the dashboard.
Lanes
Use the lane
parameter to serialize execution.
Tasks in the same lane run one at a time within your organization — each task waits for the previous one to finish before starting.
Tasks without a lane (or in different lanes) run in parallel as normal.
Payment Processing
Process charges one at a time per user to prevent double-billing or race conditions.
// Each user gets their own lane — charges never overlap import { Runlater } from "runlater-js" const rl = new Runlater(process.env.RUNLATER_KEY) await rl.send("https://myapp.com/api/charge", { body: { userId, amount }, lane: `payments-user-${userId}` })
Sequential API Calls
Call a rate-limited third-party API without overwhelming it. One request finishes before the next starts.
// All Shopify sync tasks run one at a time import { Runlater } from "runlater-js" const rl = new Runlater(process.env.RUNLATER_KEY) await rl.send("https://myapp.com/api/sync-product", { body: { productId }, lane: "shopify-sync" })
Recurring Schedules
Replace server cron jobs with managed, observable scheduling via the
/schedules
API.
Subscription Renewals
Process recurring billing daily at 6 AM UTC.
// Process recurring billing daily at 6 AM UTC import { Runlater } from "runlater-js" const rl = new Runlater(process.env.RUNLATER_KEY) await rl.cron("subscription-renewals", { url: "https://myapp.com/api/billing/renewals", schedule: "0 6 * * *" })
Database Cleanup
Clean up old sessions every night at 2 AM.
// Clean up old sessions every night at 2 AM import { Runlater } from "runlater-js" const rl = new Runlater(process.env.RUNLATER_KEY) await rl.cron("db-cleanup", { url: "https://myapp.com/api/maintenance/cleanup", schedule: "0 2 * * *" })
Health Checks
Monitor external APIs every 15 minutes.
// Monitor external APIs every 15 minutes import { Runlater } from "runlater-js" const rl = new Runlater(process.env.RUNLATER_KEY) await rl.cron("health-check", { url: "https://myapp.com/api/health/stripe", schedule: "*/15 * * * *" })
Why Runlater?
Just HTTP endpoints. Works with any stack, any platform.
Recurring schedules and delayed tasks in one simple API.
Receive webhooks with retries, replay, and full event history. No code needed.
Automatic exponential backoff. No retry logic to build.
Your data stays in Europe. GDPR-friendly by design.
Alternatives comparison
| Alternative | Limitation |
|---|---|
| setTimeout/setInterval | Doesn't survive restarts, no visibility |
| Database polling | You're building task infrastructure |
| SQS/RabbitMQ | Overkill - workers, DLQs, monitoring |
| Vercel/CloudFlare cron | No one-time tasks, no retries, platform lock-in |
| DIY webhook handler | You build retries, storage, replay, idempotency |