Schedule a trigger

A "trigger" is a scheduled HTTP request.

Any HTTP method

Our API accepts any HTTP method on the /schedule endpoint. We repeat your exact method when firing the trigger.

Send us a PUT? We fire a PUT. A POST with a JSON body? We forward the exact body. A GET? We fire a GET with no body.

Headers

Our API is designed for minimal changes to your existing HTTP calls. It heavily relies on HTTP headers prefixed with ttr-.

Think of TimeTriggers as a proxy that repeats your request at the scheduled time. We transparently pass any headers you set (except ttr- prefixed ones).

ttr- prefixed headers

Headers prefixed with ttr- are used to authenticate against our service and to set scheduling options. They are not forwarded to your target URL.

Request

There are 3 required headers to schedule a trigger:

  • ttr-api-keyheader : your API key
  • ttr-urlheader : the URL you want to hit at the scheduled time
  • ttr-scheduled-atheader : when to execute the request. Either a one-shot date in ISO 8601 format (optionally combined with date operations like now | add 2d), or a cron(...) expression for recurring triggers — see Recurring triggers.

All request headers

HeaderExampleDescription
ttr-urlheaderhttps://httpbin.org/postThe URL to hit
ttr-api-keyheaderttr_abcdef123456Your API key
ttr-scheduled-atheader2025-06-01T09:00:00Z or cron(0 9 * * 1-5)When to fire the trigger. ISO 8601 for one-shot, cron(...) for recurring
ttr-custom-keyheaderbilling:customer-42:2025-03Optional. Custom key for idempotency. See Custom trigger keys

Request body

For methods that support a body (POST, PUT, PATCH, DELETE), we store and forward the raw request body as-is.

For bodyless methods (GET, HEAD, OPTIONS), no body is read or stored.

Response

Successful response

A JSON body with the following fields:

FieldExampleDescription
triggerIdclxyz123abcUnique ID. For one-shot triggers this is the trigger ID; for recurring triggers this is the generator ID. Same value to hand back to /cancel either way.
scheduledAt2025-06-01T09:00:00.000ZFor one-shot triggers, the resolved schedule time. For recurring triggers, the time of the next instance.
operationscheduleEither schedule (new) or reschedule (existing trigger or generator updated)
kindjobEither job (one-shot) or generator (recurring).
monthQuotaRemaining455Triggers remaining in your monthly quota

Status codes

Status codeMeaning
200OKTrigger created or rescheduled
400Bad RequestInvalid request (bad URL, bad date format, etc.)
401UnauthorizedInvalid API key
402Payment RequiredMonthly quota exceeded
404Not FoundTrigger not found (when rescheduling by ID)
410GoneTrigger already executed or cancelled

Advanced Usage

Operations on ttr-scheduled-atheader

You can perform simple date arithmetic in the ttr-scheduled-atheader header:

When to scheduleHeader value
2 days from nownow | add 2d
1 hour before a date2025-06-01T09:00:00Z | add -1h
30 minutes from nownow | add 30m

Supported units: d (days), h (hours), m (minutes), s (seconds).

Try it out

ttr-scheduled-at

Custom trigger keys

Add ttr-custom-keyheader to make your trigger idempotent. If you schedule a trigger with the same custom key, the existing trigger is rescheduled instead of creating a duplicate.

This is useful for scenarios like "send a reminder 24h before an appointment" where the appointment time might change — just re-send with the same key and we'll update the schedule.

The custom-key namespace is shared between one-shot triggers and recurring generators: a custom key is owned by at most one of them at a time. Posting a recurring trigger with the same custom key as an existing one-shot will cancel the one-shot and replace it with the generator (and vice-versa).

Recurring triggers

Use a cron(...) value in the ttr-scheduled-atheader header to schedule a recurring trigger. We call this a generator — it produces one trigger instance per cron tick.

ttr-scheduled-at: cron(0 9 * * 1-5)

The grammar is cron(<expr>[, <timezone>]):

Header valueMeaning
cron(0 9 * * 1-5)Weekdays at 09:00 UTC
cron(0 9 * * 1-5, Europe/Paris)Weekdays at 09:00 Paris time
cron(*/15 * * * *)Every 15 minutes
cron(0 0 1 * *)First of every month at midnight UTC

The timezone is optional and defaults to UTC. Any IANA timezone name is accepted.

How recurring triggers work

  • The first instance is materialized immediately when you call /schedule. The response's scheduledAt field is the time of that first instance.
  • After each instance is claimed for execution, the next instance is automatically materialized. There's always exactly one pending instance ahead.
  • Each instance is a normal trigger: it gets the generator's URL, method, headers, body, and tags snapshotted at materialization time. Subsequent changes to the generator do not affect already-materialized instances.
  • Rate limits apply to instances exactly like one-shot triggers. The ttr-custom-keyheader applies to the generator itself, not to its instances.

Editing or cancelling a recurring trigger

Re-POST /schedule with the same generator ID or custom key (and a new cron expression, URL, headers, etc.) to update the generator. The currently-pending instance is replaced; past instances are unchanged.

DELETE /cancel with the generator ID or custom key cancels the generator and its currently-pending instance. Past instances (already executed or running) are kept. See Cancel a trigger.

TimeTriggers — Schedule HTTP requests at any time.