Webhook Scheduler
Log inStart free

Next.js delayed jobs

Schedule delayed jobs in Next.js on Vercel without a polling cron.

Vercel Cron is a good fit for fixed recurring work. It is a different problem when every user creates a job at runtime, such as sending an HTTP request exactly 24 hours after signup.

API request
const runAt = new Date(
  Date.now() + 24 * 60 * 60 * 1000
).toISOString();

const response = await fetch(
  'https://webhookscheduler.com/api/v1/schedule',
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': process.env.WEBHOOK_SCHEDULER_API_KEY!
    },
    body: JSON.stringify({
      url: 'https://your-app.com/api/jobs/onboarding',
      method: 'POST',
      runAt,
      body: {
        event: 'onboarding.follow_up',
        userId: 'user_123'
      },
      idempotencyKey: 'user_123:onboarding_follow_up'
    })
  }
);

if (!response.ok) {
  throw new Error('Could not schedule delayed job');
}
01

Runtime schedules

Create a future job when a user signs up, an invoice fails, or another product event occurs.

02

Retries without a worker

Keep retry attempts, backoff, status codes, and response details outside your Next.js request lifecycle.

03

Visible job state

Inspect, cancel, and manually retry jobs from a dashboard instead of querying a queue or database table.

Fixed schedules and runtime jobs are different

Vercel Cron calls a route on a schedule defined in your deployment configuration. It works well for tasks such as a nightly report, a cache refresh, or a cleanup job that runs at the same time for everyone.

A delayed product job is created while the application is running. One customer may need a callback tomorrow at 09:12, another next week, and another may cancel before delivery. A single cron expression does not represent those individual schedules.

The official Vercel Cron documentation is the right starting point for fixed recurring tasks. For per-user jobs, schedule each future HTTP delivery directly.

Schedule the job from server-side Next.js code

Keep the scheduling API key in a server environment variable. Call the API from a Route Handler, API route, Server Action, or another trusted backend function after the product event succeeds.

Node.js
const runAt = new Date(
  Date.now() + 24 * 60 * 60 * 1000
).toISOString();

const response = await fetch(
  'https://webhookscheduler.com/api/v1/schedule',
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': process.env.WEBHOOK_SCHEDULER_API_KEY!
    },
    body: JSON.stringify({
      url: 'https://your-app.com/api/jobs/onboarding',
      method: 'POST',
      runAt,
      body: {
        event: 'onboarding.follow_up',
        userId: 'user_123'
      },
      idempotencyKey: 'user_123:onboarding_follow_up'
    })
  }
);

if (!response.ok) {
  throw new Error('Could not schedule delayed job');
}

Calculate the timestamp from the event rather than hard-coding a calendar date. Store the returned job ID with your own record if the workflow may need to be canceled later.

Webhook Scheduler delivery queue showing scheduled endpoints, delivery status, execution time, and latest HTTP attempt
Each runtime job keeps its destination, schedule, delivery status, and latest HTTP attempt in one queue.

Receive the delayed request in a normal API route

The target can be any public HTTPS endpoint, including a Next.js API route. Keep the receiver small: validate the request, claim an idempotency key, run the business action, and return a clear status code.

Next.js Route Handler
import { NextRequest } from 'next/server';

export async function POST(request: NextRequest) {
  const body = await request.json();

  // Claim the idempotency key before running side effects.
  await sendOnboardingFollowUp(body.userId);

  return Response.json({ received: true });
}

Authenticate the callback with a secret header or a signature that your route verifies. Never expose the Webhook Scheduler API key in browser code.

Retries do not remove the need for idempotency

A receiver can finish its work and then time out before the sender sees the response. The next retry is correct from the sender's perspective, but it can repeat the side effect if the receiver is not idempotent.

Use a stable business key, such as the user ID plus the workflow name, and claim it atomically before sending an email, charging a card, or updating an external system. The webhook retry logic guide covers the failure cases in more detail.

Cancellation is part of the product workflow

Delayed jobs often become invalid. A user may delete an account, complete onboarding early, or pay an invoice before the follow-up runs. Save the scheduled job ID so the application can cancel it when the underlying state changes.

This is one reason a managed scheduled webhook is different from a periodic database scan. Each future action has its own status, attempt history, cancellation path, and delivery record.

Choose the smallest tool that matches the job

Use Vercel Cron for fixed recurring maintenance. Use a queue when your team needs custom consumers and owns the operational infrastructure. Use a scheduled webhook when the output is an HTTP request that must run later with retries and visible delivery state.

You can compare the tradeoffs in cron jobs vs scheduled webhook APIs, review the delivery security model, or create a real draft on the interactive scheduler.

FAQ

Can Vercel Cron schedule a job for each user?

Vercel Cron is designed around recurring schedules configured for a deployment. Per-user timestamps created at runtime need their own job storage and dispatch layer.

Can I schedule a Next.js API route for later?

Yes. Schedule its public HTTPS URL as the target, keep the scheduling call server-side, and authenticate the callback at the receiving route.

What happens if the Next.js route is temporarily down?

Webhook Scheduler records the failed attempt and retries according to the plan recovery limit. The receiver should remain idempotent because a request can be delivered more than once.

Ship delayed webhooks without maintaining scheduling infrastructure.

Start with the free plan, test a real delivery, then upgrade when the workflow becomes production critical.

Schedule a test job