Skip to content
All insights
AllClearStack editorial·Reliability··4 min read

Design a small payload for work that happens later

Prefer stable business identifiers to snapshots of mutable state, and let the receiver decide what is still relevant.

A delayed request carries information across time. If its payload includes an email address, a subscription state and a prepared message, each of those values may be outdated by the time the receiver uses it. A smaller payload makes that uncertainty easier to manage.

Start with the identity of the work

Send a stable event or reminder identifier that your server can connect to its own record. Distinguish the identity of the business event from the scheduler's job ID: one describes what should happen, while the other helps inspect and cancel a particular delivery.

Store enough information locally to reconstruct the intention after a failed response or process restart. Avoid a new random event identity on every retry. A consistent scheduling idempotency key can recover the retained original job instead of intentionally creating another copy of the same work.

Keep mutable data at its source

The illustrative example sends a resourceId. The receiving endpoint is responsible for loading the record and determining its current eligibility. Replace the placeholder with an identifier from your application; the scheduler does not know how to interpret it.

Illustrative server-side example: this schedules delivery 24 hours from execution. Replace the environment variables and example record IDs, persist the returned job ID, and implement your own authenticated HTTPS receiver. The request follows the current API reference.

const apiKey = process.env.WEBHOOK_SCHEDULER_API_KEY;
const receiverUrl = process.env.REMINDER_WEBHOOK_URL;
if (!apiKey || !receiverUrl) throw new Error("Set the server-side API key and public HTTPS receiver URL.");

const response = await fetch("https://webhookscheduler.com/api/v1/schedule", {
  method: "POST",
  headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    url: receiverUrl,
    method: "POST",
    runAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
    reference: "resource:example-123",
    idempotencyKey: "resource-example-123-reminder-v1",
    body: { resourceId: "example-123" },
  }),
});
if (!response.ok) throw new Error(`Scheduling failed: ${response.status}`);
const job = await response.json();
if (!job.id) throw new Error("Missing scheduled job ID");
// Persist job.id with your business record before acknowledging this work.
console.log(job.id);

Decide whether the action should use the current record or a deliberate historical snapshot. Both designs can be valid, but they express different product behavior. For example, a reminder usually needs current eligibility, while another task may explicitly refer to a versioned document. Encode that distinction rather than leaving it accidental.

Define missing and obsolete records

A user might delete a workspace before the job arrives. A record might be replaced by a newer version. Give these cases an explicit outcome at the receiver, such as skipping obsolete work and recording the reason.

An unavailable database is a different condition from a record that no longer exists. Decide when a lookup failure should be retried and when the work should be investigated. Do not silently convert an uncertain lookup into permission to perform the action. That distinction is especially useful when the action contacts a customer or crosses another service boundary.

Authenticate before using the identifier

A small payload is not an authorization mechanism. Verify the incoming delivery using the documented signature procedure before trusting the identifier. Keep API keys and signing secrets on the server, and apply your application's own rules when loading and acting on a business record.

At-least-once delivery also means an authenticated request can arrive again. Claim the business event using durable identity, and use downstream provider idempotency when available. A separate provider call and database update can still leave an uncertain outcome after a timeout, so retain a reconciliation path.

Keep the boundary easy to inspect

WebhookScheduler is built by AllClearStack. It can supply delayed HTTP delivery while your application retains the interpretation of the payload. The limitation is deliberate: it does not replace your database, compute worker or authorization model.

A database worker may be sufficient if you already operate one and do not need another service for delivery timing. Whichever transport you use, test a valid record, a missing record, an obsolete version and a repeated delivery. Use the workflow guides to document those outcomes alongside scheduling and cancellation.

Disclosure · Built by the AllClearStack team

When ownership is the expensive part

Webhook Scheduler handles delayed HTTP delivery, automatic retries, per-attempt logs, and one-call cancellation. Try a real delivery without creating an account.

Related articles