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

Replace a reminder when an appointment moves

Use a new reminder revision when an appointment changes, while keeping replacement scheduling and old-job cleanup recoverable.

Consider a hypothetical appointment that moves after its reminder has already been scheduled. Updating the appointment time changes the product's intention. It does not rewrite a previously created HTTP job. Model the replacement explicitly so a half-finished update can be recovered without sending the old reminder by mistake.

Give the replacement its own revision

Keep the appointment separate from each reminder revision. A revision can hold the appointment identifier, intended reminder time, eligibility state, scheduling key and returned job ID. Its immutable identifier gives the receiver a way to distinguish the previous reminder from the current one.

Commit the new appointment time and the selected reminder revision together in your application database. Mark the old revision obsolete and leave the new revision awaiting scheduling. This is a proposed application design, not a transaction supplied by WebhookScheduler. Retain enough state for an operator or worker to finish the transition after a crash.

Do not put both revisions behind a mutable record that always resolves to the latest reminder. Otherwise an old delivery might load the newest appointment and act as though it were the replacement. The incoming identifier should lead to the particular intention that was scheduled.

Recover retries and replacements differently

The API reference documents that reusing a scheduling idempotency key returns the retained original job without comparing the new payload. Sending a different time with that old key therefore does not express a replacement.

Use a fresh key derived from the new reminder revision when intentionally creating replacement work. Keep that key stable across retries of this particular creation. If its response is lost, retry the same new key to recover the retained original result. Persist the returned job ID on the new revision before marking scheduling complete.

Keep the scheduling example tied to the revision

The illustrative request below schedules a reminder one day from execution. In the appointment flow, replace that time with the chosen reminder time calculated from the updated appointment. The placeholder resource ID should identify the immutable reminder revision, not just the appointment.

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: "appointment:example-123",
    idempotencyKey: "appointment-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);

// Call with the stored ID when the reminder becomes obsolete.
async function cancelReminder(jobId) {
  const result = await fetch(
    `https://webhookscheduler.com/api/v1/jobs/${encodeURIComponent(jobId)}/cancel`,
    { method: "POST", headers: { Authorization: `Bearer ${apiKey}` } },
  );
  if (!result.ok) throw new Error(`Cancellation not confirmed: ${result.status}`);
}

Cancellation succeeds only while a job is PENDING or RETRYING. The API documents 400 for a job that is no longer cancelable, 404 for a job not found, and 409 when the state changes before cancellation is applied. These responses do not prove a business action succeeded. Inspect the job and keep the current-state check at the receiver: an HTTP request already in flight cannot be retracted.

Call the cancellation helper with the stored old job ID when retiring the previous revision. Keep cancellation and creation as separately recorded operations. If either external call fails, leave that operation visible for reconciliation instead of treating a successful local database commit as proof that both remote changes succeeded.

Decide what a partial replacement means

Canceling first can leave an interval with no scheduled reminder if creating the replacement fails. Scheduling first can leave both jobs present until cancellation succeeds. Neither order creates an atomic swap across the application and scheduler. Choose the tradeoff deliberately and let the receiver's revision check prevent obsolete work from producing an effect.

If scheduling the new reminder is still unresolved, surface that condition in the application's operations view. Keep the appointment update separate from the state of its reminder. If the calculated reminder time is already past, define a product rule to skip it or handle it separately; do not silently pretend that an arbitrary future time preserves the user's original expectation.

Check the revision again when delivery arrives

Authenticate the incoming request using the documented signature procedure before loading the revision. Then check that this revision is still selected and eligible under the current appointment state. Record obsolete work as skipped. A cancellation request cannot replace this check, particularly when an old delivery has already started.

Claim the business event atomically before applying its effect. If the effect is an external notification, use the provider's idempotency support where available and retain a way to reconcile an uncertain timeout. Also decide how to handle an appointment change that arrives after the final eligibility check. Do not promise that two API calls prevent every stale or duplicate notification.

WebhookScheduler is built by AllClearStack. It can supply delayed HTTP delivery while this revision policy remains in your application. A database worker may be sufficient when it already owns the appointment workflow and can inspect due reminders directly. The workflow guides help separate those responsibilities before adding another service.

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