How to Schedule API Calls From Vercel, Netlify, and Cloudflare Workers

Frontend platforms are incredible for shipping fast. But when you need to do something later — send an email in 30 minutes, process a payment retry tomorrow, clean up expired data weekly — you hit a wall.

Vercel, Netlify, and Cloudflare Workers don’t give you cron jobs. They don’t give you persistent background workers. And their serverless functions have tight timeout limits.

Here’s how to add scheduled and delayed API calls to any frontend platform without leaving your stack.

The Frontend Platform Limitation

You’ve built your app on Next.js + Vercel. Everything is serverless. Then product says:

“Can we send a follow-up email 2 hours after signup?”

Your options: 1. Vercel Cron Jobs — limited to once per minute on Pro, once per day on Hobby. Can’t schedule arbitrary delays. 2. External scheduler (AWS EventBridge, Google Cloud Scheduler) — now you’re managing a second cloud platform with IAM roles and deployment pipelines. 3. Database polling — write a “scheduled_tasks” table and poll it. But… from where? You don’t have a server. 4. Third-party queue — set up Redis + BullMQ on Railway or Upstash. Now you’re managing queue infrastructure.

Or you add one line of code.

One Fetch Call, Any Delay

// /app/api/signup/route.ts (Next.js App Router)
export async function POST(request: Request) {
  const { email, name } = await request.json();
  
  // Create the user immediately
  await db.users.create({ email, name });
  
  // Send welcome email in 2 hours (7200 seconds)
  await fetch(
    `https://zeplo.to/https://your-app.vercel.app/api/jobs/welcome-email?_delay=7200&_retry=3&_token=${process.env.ZEPLO_TOKEN}`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email, name }),
    }
  );
  
  return Response.json({ success: true });
}
// /app/api/jobs/welcome-email/route.ts
export async function POST(request: Request) {
  const { email, name } = await request.json();
  await sendEmail({ to: email, template: 'welcome', data: { name } });
  return Response.json({ sent: true });
}

That’s it. No queue infrastructure. No cron configuration. Zeplo holds the request for 2 hours, then POSTs to your endpoint. If it fails, it retries 3 times with exponential backoff.

Recurring Jobs With Cron Syntax

Need daily, hourly, or weekly jobs? Use _cron:

// Set up a daily cleanup job (runs at 3am UTC every day)
// Call this once from an admin endpoint or during deployment
await fetch(
  `https://zeplo.to/https://your-app.vercel.app/api/jobs/cleanup?_cron=0|3|*|*|*&_token=${process.env.ZEPLO_TOKEN}`,
  { method: 'POST' }
);

This is especially useful on platforms where cron support is limited:

Platform Built-in Cron Limitations
Vercel Yes (Pro+) 1/day on Hobby, no sub-minute, no delays
Netlify Scheduled Functions Limited syntax, beta
Cloudflare Cron Triggers Workers-only, no arbitrary delays
Railway No
Render Yes Requires background worker service

Zeplo works identically across all of them — it’s just an HTTP call.

Real Patterns for Frontend Apps

Trial Expiration Warnings

// When user starts trial, schedule reminders
const trialDays = 14;

// Reminder at day 10
await fetch(`https://zeplo.to/https://your-app.com/api/jobs/trial-reminder?_delay=${10 * 86400}&_retry=3&_token=${TOKEN}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ userId, daysLeft: 4 }),
});

// Reminder at day 13
await fetch(`https://zeplo.to/https://your-app.com/api/jobs/trial-reminder?_delay=${13 * 86400}&_retry=3&_token=${TOKEN}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ userId, daysLeft: 1 }),
});

Webhook Fan-Out

// /app/api/webhooks/stripe/route.ts
export async function POST(request: Request) {
  const event = await request.json();
  const TOKEN = process.env.ZEPLO_TOKEN;
  const BASE = process.env.NEXT_PUBLIC_URL;
  
  // Fan out to separate handlers — each retries independently
  await Promise.all([
    fetch(`https://zeplo.to/${BASE}/api/jobs/update-subscription?_retry=3&_token=${TOKEN}`, {
      method: 'POST', body: JSON.stringify(event),
      headers: { 'Content-Type': 'application/json' },
    }),
    fetch(`https://zeplo.to/${BASE}/api/jobs/send-receipt?_retry=5&_token=${TOKEN}`, {
      method: 'POST', body: JSON.stringify(event),
      headers: { 'Content-Type': 'application/json' },
    }),
  ]);
  
  return Response.json({ received: true });
}

Delayed Content Publishing

// Schedule a blog post to go live at a specific time
const publishAt = new Date('2026-04-01T09:00:00Z');
const delaySeconds = Math.floor((publishAt - Date.now()) / 1000);

await fetch(`https://zeplo.to/https://your-cms.com/api/publish?_delay=${delaySeconds}&_token=${TOKEN}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ postId: 'draft-123' }),
});

Why Not Just Use Vercel Cron?

Vercel Cron is great for simple recurring tasks. But it can’t:

  • Delay a specific request by an arbitrary amount of time
  • Retry with backoff if your handler fails
  • Schedule dynamically from user actions (trial reminders, delayed emails)
  • Fan out a webhook to multiple handlers with independent retry
  • Log every attempt with full request/response details

If you need “run this job every day at midnight,” Vercel Cron works fine. If you need “send this specific request 47 minutes from now and retry 3 times if it fails,” that’s what Zeplo is for.

Getting Started

npm i # nothing to install, it's just fetch()

Seriously — there’s no SDK. It’s just HTTP.

  1. Sign up free — 500 requests/month included
  2. Set ZEPLO_TOKEN in your environment variables
  3. fetch('https://zeplo.to/...') from anywhere in your app

Works with Next.js, Nuxt, SvelteKit, Remix, Astro, or plain HTML with a fetch call.


Zeplo adds background jobs to any frontend platform. Delay, retry, and schedule HTTP requests with zero infrastructure. Start free →

Return to Blog