ForHosting KIT · Notifications & Flows

Schedule an email

POST /notify/email-scheduled queues a message for a specific future moment instead of sending it now, and gives you a task_id you can use to cancel it any time before that moment arrives. It replaces the small cron job or delayed-queue worker teams usually build just to hold a message until the right time.

● StablePer request + per email$0.002
Use it from WebAPIEmailApp soonTelegram soon

The part of email that isn't about sending, it's about timing

Most email problems are about content and deliverability; this one is purely about timing. A trial expiration warning sent the day before renewal, a reminder for an appointment tomorrow morning, a re-engagement message exactly seven days after signup — none of these need to be sent right now, and sending them right now would actually be wrong. This endpoint exists so that 'send this, but later' is a single API call instead of a scheduling system you maintain yourself.

What happens between the call and the send

You submit the message along with a target send time, and the task sits queued until that moment on our global edge, at which point it goes out exactly like a normal send — same delivery attempt, same retry behavior, same reporting. The task_id returned at submission time is your handle on the message for as long as it's pending: it identifies a real, addressable job, not a fire-and-forget request you've already lost track of.

Cancellation is the feature that matters most

A scheduled send that can't be cancelled is barely more useful than a cron job, because the moment circumstances change — the trial gets extended, the appointment gets moved, the customer cancels their subscription — you need to pull the message back before it embarrassingly goes out anyway. Calling the cancel operation with the task_id before the send time removes it from the queue cleanly, and because a cancelled task never sends, it's never charged.

Why this beats rolling your own delay logic

Building delayed sends yourself usually means a database row with a future timestamp, a poller checking it periodically, and hoping the poller doesn't die between deploys. That's infrastructure most teams don't want to own for something as small as 'send this tomorrow at 9am.' This endpoint absorbs that infrastructure entirely — the scheduling, the reliable trigger and the retry logic live on our side.

Where it fits in a broader flow

Scheduled sends compose naturally with other automation: a signup triggers a chain of onboarding emails spaced days apart, a trial start schedules its own expiration warning at creation time, a booking schedules its own reminder. Each of those is one call at the moment the triggering event happens, not a recurring job watching a calendar.

Trial expiration reminders

The moment a trial starts, its expiration warning is scheduled for three days before it ends, and cancelled automatically if the customer upgrades early.

Appointment reminders

A booking schedules a reminder email for the evening before the appointment, cancelled instantly if the appointment is rescheduled or cancelled.

Drip onboarding sequences

A signup event schedules a series of tips emails spaced a few days apart, each one a separate scheduled task the user can effectively opt out of by unsubscribing before it fires.

Time-zone-aware campaigns

A send is scheduled for 9am in the recipient's local time zone rather than firing immediately regardless of when they'll actually see it.

How far in advance can I schedule an email?

You provide the target send time when you submit the task; as long as it's a valid future time, the message stays queued until then.

Can I cancel a scheduled email?

Yes — call the cancel operation with the task_id any time before the scheduled send time, and it's pulled from the queue without ever being sent or charged.

What does scheduling cost?

$0.002 per request plus $0.0035 per email actually sent; a cancelled or failed task is never charged.

Is there a free tier to test scheduling?

There's no free tier — free tiers get abused and slow everyone down. Access runs on a prepaid ForHosting KIT balance: top up from $10.00 (it never expires) and each request is charged at its published price, so a call with no balance returns HTTP 402. No subscription, no tokens, no invented credits, and a failed task is never charged.

How do I know when the email actually goes out?

At the scheduled time, delivery proceeds exactly like a normal send, and the outcome is reported via a signed webhook or a signed link valid for 24 hours.

Can I reschedule an email instead of cancelling it?

The reliable pattern is to cancel the pending task and submit a new one with the updated send time.

What happens if the scheduled time has already passed?

A submission with a send time in the past is rejected with a clear error rather than being sent immediately or silently dropped.

Does this replace a cron job on my server?

For per-message scheduling, yes — the endpoint handles the delay, the trigger and the retry logic, so you don't need a poller or a delayed-queue worker of your own.

Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.

POSThttps://api.kit.forhosting.com/notify/email-scheduled

Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, and soon from our app, email and Telegram.

curl -X POST https://api.kit.forhosting.com/notify/email-scheduled \
  -H "Authorization: Bearer $KIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input":"…"}'
{
  "input": "…"
}
{
  "task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
  "type": "notify.email_scheduled",
  "status": "queued",
  "_links": {
    "result": "/tasks/tsk_…/result"
  }
}

The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.

Per request$0.002
Per email$0.0035

Published price — no tokens, no invented credits. A failed task is never charged.

HTTPCodeMeaning
401unauthorizedMissing or invalid API key.
402insufficient_balanceYour balance doesn't cover the task price.
404unknown_typeThat task type doesn't exist.
429rate_limitedToo many requests. Use the webhook instead of polling.

Read the full KIT documentation →