Periodic triggers send an HTTP request to a URL on a cron schedule. Use them to run recurring tasks, health checks, or scheduled calls to your functions.
All endpoints are scoped to an environment. Authenticate with an
environment-level API key, or pass envId (query string for GET/DELETE,
request body for POST/PATCH) when using an app-, team- or user-level key.
Cron expressions are evaluated in UTC. See crontab.guru for help writing them.
These endpoints are also available as MCP tools (list_triggers,
create_trigger, update_trigger, delete_trigger, invoke_trigger,
get_trigger_logs) — see the MCP Server docs.
Request header values are masked. Triggers commonly carry secrets in their request headers (e.g.
Authorization,X-Api-Key). For security, header values are blanked out (returned as empty strings) in every response that lists triggers or their logs — the header names are kept so you can see what is configured. The stored values are used unchanged when the trigger actually runs.
Create a trigger.
interface Request {
envId?: string // Required when the API key is not environment-scoped.
cron: string // Cron expression, evaluated in UTC.
status: boolean // Whether the trigger is active.
description?: string // One-line summary shown in listings. Max 200 chars, single line.
documentation?: string // Markdown notes describing the trigger. Max 64KB.
options: {
method: string // GET, POST, HEAD, PATCH or DELETE.
url: string // http/https URL to call.
payload?: string // Request body, sent for non-GET methods.
headers?: Record<string, string> | string // Either a map or "key:value;key:value".
}
}
interface Response {
trigger: Trigger
}
# Example
curl -X POST \
-H 'Authorization: <api_key>' \
-H 'Content-Type: application/json' \
'https://api.stormkit.io/v1/trigger' \
-d '{
"cron": "*/5 * * * *",
"status": true,
"description": "Nightly rollup",
"documentation": "Nightly rollup. Ping #data if it fails.",
"options": {
"method": "POST",
"url": "https://www.example.org/cron",
"payload": "{ \"hello\": \"world\" }",
"headers": { "Content-Type": "application/json" }
}
}'
{
"trigger": {
"id": "18914",
"envId": "1500",
"cron": "*/5 * * * *",
"description": "Nightly rollup",
"documentation": "Nightly rollup. Ping #data if it fails.",
"status": true,
"nextRunAt": 1712418330,
"options": {
"method": "POST",
"url": "https://www.example.org/cron",
"payload": "{ \"hello\": \"world\" }",
"headers": { "Content-Type": "" }
}
}
}
Header values are masked in the response (see the note above); the value you sent is stored and used when the trigger runs.
Validation errors return 400 with a map of field errors, e.g.
{ "cron": "Invalid cron format" } or { "url": "Invalid URL" }.
description is a one-line summary shown next to the trigger in listings —
"Autofill weekly newsletter" against a URL ending in /api/cron/newsletter-autofill.
documentation is free-form markdown: the longer runbook explaining how the
trigger is used and what breaks if it stops. Neither is sent with the request or
affects execution.
Update an existing trigger. The id must belong to the authenticated
environment.
This is a partial update: only the fields present in the body are changed
and everything else keeps its current value. To clear a field, send its empty
value explicitly (e.g. "documentation": "").
options.headersis replaced wholesale when you send it. Because list responses mask header values, always re-send the real values you want to keep — sending back the masked (blanked) values will overwrite the stored ones. Omittingoptions.headersleaves the stored headers untouched.
interface Request {
id: string
envId?: string // Required when the API key is not environment-scoped.
cron?: string
status?: boolean
description?: string
documentation?: string
options?: {
method?: string
url?: string
payload?: string
headers?: Record<string, string> | string
}
}
interface Response {
ok: boolean
}
# Example — changes the schedule only; status, documentation and every
# option keep their current values.
curl -X PATCH \
-H 'Authorization: <api_key>' \
-H 'Content-Type: application/json' \
'https://api.stormkit.io/v1/trigger' \
-d '{
"id": "18914",
"cron": "0 * * * *"
}'
{
"ok": true
}
Delete a trigger by its id.
interface QueryString {
triggerId: string
envId?: string // Required when the API key is not environment-scoped.
}
interface Response {
ok: boolean
}
# Example
curl -X DELETE \
-H 'Authorization: <api_key>' \
'https://api.stormkit.io/v1/trigger?triggerId=18914'
{
"ok": true
}
Run a trigger immediately, regardless of its schedule or status. The request is executed synchronously and the resulting log is returned and stored alongside the scheduled runs.
interface Request {
id: string
envId?: string // Required when the API key is not environment-scoped.
}
interface Response {
log: TriggerLog
}
# Example
curl -X POST \
-H 'Authorization: <api_key>' \
-H 'Content-Type: application/json' \
'https://api.stormkit.io/v1/trigger/invoke' \
-d '{ "id": "18914" }'
{
"log": {
"triggerId": "18914",
"request": {
"url": "https://www.example.org/cron",
"method": "GET",
"headers": null,
"payload": ""
},
"response": {
"code": 200,
"body": "pong"
}
}
}
List the triggers configured for an environment.
interface QueryString {
envId?: string // Required when the API key is not environment-scoped.
}
interface Response {
triggers: []Trigger
}
# Example
curl -X GET \
-H 'Authorization: <api_key>' \
'https://api.stormkit.io/v1/triggers'
{
"triggers": [
{
"id": "18914",
"envId": "1500",
"cron": "*/5 * * * *",
"description": "Nightly rollup",
"documentation": "Nightly rollup. Ping #data if it fails.",
"status": true,
"nextRunAt": 1712418330,
"options": {
"method": "POST",
"url": "https://www.example.org/cron",
"payload": "{ \"hello\": \"world\" }",
"headers": null
}
}
]
}
Return the last 25 executions of a trigger, most recent first. Each scheduled
run and each invoke call is recorded.
interface QueryString {
triggerId: string
envId?: string // Required when the API key is not environment-scoped.
}
interface Response {
logs: []TriggerLog
}
# Example
curl -X GET \
-H 'Authorization: <api_key>' \
'https://api.stormkit.io/v1/trigger/logs?triggerId=18914'
{
"logs": [
{
"id": "5001",
"triggerId": "18914",
"request": {
"url": "https://www.example.org/cron",
"method": "GET",
"headers": null,
"payload": ""
},
"response": {
"code": 200,
"body": "pong"
},
"createdAt": 1712418330
}
]
}
interface Trigger {
id: string
envId: string
cron: string
description: string // One-line summary. Empty when unset.
documentation: string // Markdown notes. Empty when undocumented.
status: boolean
nextRunAt: number // Unix timestamp of the next scheduled run.
options: {
method: string
url: string
payload: string
headers: Record<string, string> | null
}
}
interface TriggerLog {
id: string
triggerId: string
request: {
url: string
method: string
headers: Record<string, string> | null
payload: string
}
response: {
code?: number // HTTP status code of the response, when one was received.
body?: string // Response body.
error?: string // Set instead of code/body when the request failed.
}
createdAt: number
}
| Property | Definition |
|---|---|
| id | The unique id of the trigger. |
| envId | The environment the trigger belongs to. |
| cron | The cron expression, evaluated in UTC. |
| description | One-line summary shown next to the trigger in listings. Max 200 chars. |
| documentation | Markdown notes describing the trigger, shown in the UI. Max 64KB. |
| status | Whether the trigger is active. Inactive triggers are not scheduled. |
| nextRunAt | Unix timestamp of the next scheduled run. 0 when the trigger is inactive. |
| options | The HTTP request executed on each run. |