All docs

Getting Started

SendItWhenever is a precision HTTP webhook launcher. You tell it what request to send, where, and when — it holds the request and fires it at the scheduled time, signed and encrypted at rest.

Think of it as setTimeout for HTTP, but durable: it survives your process restarting, runs on second-level precision with Early Firing correction, and never loses a scheduled call.

Common uses:

  • Trial-ending and dunning emails fired at an exact future moment
  • Delayed billing charges (charge in 14 days)
  • Reminders, follow-ups, and drip sequences
  • Any "do this thing later" that you don't want to build a queue and worker for

How a schedule flows

Every scheduled webhook moves through a small set of states:

State Meaning
scheduled Accepted and waiting for its fire time.
firing The fire time arrived; delivery is in progress (including retries).
succeeded Your endpoint returned a 2xx response.
failed Delivery failed but may still retry.
dead All retries were exhausted, or the target was permanently rejected. The request is moved to a dead-letter queue.
cancelled You cancelled it before it fired.

Internally there are two layers, and the split matters for understanding behavior:

  • Execution layer (Redis): holds the encrypted job and fires it. This is the hot path; nothing slow is added to it.
  • Record layer (Postgres): holds metadata you query — status, timestamps, attempt counts. When you call list() or get(), you read this layer.

The payload itself is encrypted at rest and only decrypted in memory at the exact moment of firing. It is never written to logs.

Install

npm install @sendithq/sdk
# or: pnpm add @sendithq/sdk

The Node SDK (Node 18+) has zero runtime dependencies — it uses the built-in fetch.

There is also a Python SDK with the same surface (sync + async):

pip install sendithq

Your first scheduled webhook

Get an API key from your dashboard (it starts with sw_live_), then:

import { SendIt } from "@sendithq/sdk";

const sendit = new SendIt("sw_live_xxx");

await sendit.schedule({
  url: "https://api.myapp.com/billing/charge",
  in: "14d", // or fireAt: "2026-06-29T09:00:00Z"
  payload: { userId: 42, amount: 9900 },
});

In Python it's the same call (note in_in is a reserved word):

from sendithq import SendIt

sendit = SendIt("sw_live_xxx")

sendit.schedule(
    url="https://api.myapp.com/billing/charge",
    in_="14d",  # or fire_at="2026-06-29T09:00:00Z"
    payload={"user_id": 42, "amount": 9900},
)

That's it. At the scheduled time, SendItWhenever sends a signed POST to your URL with that JSON body. If your endpoint is slow or down, it retries with backoff. You can later look the schedule up, reschedule it, or cancel it.

Without the SDK

Everything the SDK does is a thin wrapper over a REST API, so you can use plain HTTP from any language:

curl -X POST https://api.sendit-whenever.com/v1/schedules \
  -H "Authorization: Bearer sw_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "targetUrl": "https://api.myapp.com/billing/charge",
    "fireAt": "2026-06-29T09:00:00Z",
    "payload": "{\"userId\":42,\"amount\":9900}"
  }'

See the REST API Reference for the full surface.

Where to go next