Skip to content

Smpl Jobs

Smpl Jobs is a scheduler that posts a URL. You define a job — an HTTP request plus a schedule — and smplkit fires it on time, captures the response, and keeps a permanent history of every execution. Run something on a recurring cron cadence, once at a future instant, right now, or only when you trigger it.

Jobs and runs

There are two resources:

  • A job is the definition of scheduled work — the request to send and when to send it. A job is identified by a customer-supplied slug you choose (data.id), unique within your account and immutable once created. Creating a job with a slug that already exists returns 409.
  • A run is a single occurrence of a job executing. A run is identified by a server-assigned UUID and references its parent job by slug. Runs carry the full forensic record of what was sent and what came back.
EndpointPurpose
POST /api/v1/jobsCreate a job.
GET /api/v1/jobsList jobs (offset paginated; filter[kind], filter[scheduled], filter[name]).
GET /api/v1/jobs/{id}Read a job (id is the slug).
PUT /api/v1/jobs/{id}Replace a job.
DELETE /api/v1/jobs/{id}Soft-delete a job.
GET /api/v1/runsList runs (cursor paginated; filter[job]={slug} for one job's history, filter[environment]={env} to scope by environment, filter[trigger]={trigger} to scope by why the run exists, and last_run_only for the latest completed run per job-and-environment).
GET /api/v1/runs/{id}Read a run (id is the run UUID).
POST /api/v1/jobs/{id}/actions/runTrigger one immediate run.
POST /api/v1/runs/{id}/actions/cancelCancel a pending or running run.
POST /api/v1/runs/{id}/actions/rerunSpawn a new run from a completed one.
POST /api/v1/retry-policiesCreate a retry policy (caller-supplied id).
GET /api/v1/retry-policiesList retry policies (page paginated; filter[name]).
GET /api/v1/retry-policies/{id}Read a retry policy.
PUT /api/v1/retry-policies/{id}Replace a retry policy.
DELETE /api/v1/retry-policies/{id}Soft-delete a retry policy.
GET /api/v1/usage?filter[period]=currentCurrent-period usage counters.

See API Reference — Jobs for the full schema, filters, and request/response shapes.

Defining a job

A job is created with POST /api/v1/jobs:

POST /api/v1/jobs
Content-Type: application/vnd.api+json
Authorization: Bearer <api-key>

{
  "data": {
    "id": "nightly-cache-warm",
    "type": "job",
    "attributes": {
      "name": "Nightly cache warm",
      "description": "Pre-warm the product cache before peak traffic.",
      "type": "http",
      "schedule": "0 4 * * *",
      "timezone": "America/New_York",
      "environments": {
        "production": { "enabled": true }
      },
      "configuration": {
        "method": "POST",
        "url": "https://api.example.com/internal/cache/warm",
        "headers": { "X-Internal-Token": "…" },
        "body": "{\"scope\":\"products\"}",
        "success_status": "2xx",
        "timeout": 30,
        "tls_verify": true
      }
    }
  }
}

The outer data.type is the JSON:API resource type and is always job; the type inside attributes is the job's execution type — http is the only value in v1.

FieldNotes
idYour chosen slug. Immutable, unique per account.
nameRequired, 1–200 characters.
descriptionOptional, up to 2000 characters.
environmentsPer-environment sparse overrides: each entry sets enabled plus only the leaves that differ from the base (e.g. schedule, timezone, retry_policy, url, timeout, or an individual headers.<name>). A job is enabled in an environment only when that environment's entry sets enabled: true. See Environments.
kindRead-only, computed from the schedule: recurring (cron), manual (no schedule), or one_off (datetime / now). See Schedules.
typeThe job's execution type. v1 ships exactly one: http.
scheduleThe job's base schedule — when it fires unless an environment overrides it. See Schedules.
timezoneThe base IANA timezone the cron schedule is evaluated in (recurring jobs only); null/omitted means UTC. See Timezones.
configurationThe request to send, keyed on type. See HTTP configuration.
retry_policyThe id of the retry policy applied to failed runs, overridable per environment. Omit or send null to reference no policy, in which case failed runs are never retried. See Retry policies.
concurrency_policyHow overlapping runs of the same job are handled. ALLOW (always run) is the default and only value in v1.

Updates follow the standard get-mutate-put pattern: read the job, change the fields you want, and PUT the full representation back. There is no PATCH.

Environments

A job's enablement is per environment. The environments map is keyed by environment id (e.g. production), and each entry is a sparse overlay: it sets enabled plus only the leaves that differ from the base — everything you don't set is inherited, and the service resolves the base ⊕ overlay when the job fires in that environment. The overridable leaves are:

  • enabled — whether the job is enabled in that environment. A recurring job is scheduled, and a manual job is triggerable, only in the environments whose entry is enabled: true; an environment with no entry is disabled there.
  • schedule — an optional per-environment cron override (recurring jobs only). Omit it to inherit the job's base schedule; when present it must be a 5-field cron expression, evaluated in this environment's effective timezone.
  • timezone — an optional per-environment timezone override (recurring jobs only). Omit it to inherit the base timezone, else UTC. When present it must be a valid IANA zone key (e.g. America/New_York). It may be set on an environment that inherits the base schedule — it need not also override schedule.
  • request leaves — any individual field of the base configuration: url, method, timeout, body, success_status, tls_verify, ca_cert, or a single header as headers.<name> (e.g. headers.Authorization). Each overrides just that leaf; the rest of the request is inherited. Overrides are per-leaf, not a whole-configuration replacement — set headers.Authorization and the environment keeps every other base header.
  • retry_policy — an optional per-environment retry policy override (the id of a policy). Omit it to inherit the job's base retry_policy; when present, runs in this environment retry according to this policy instead of the base.
  • next_run_at — read-only, computed. The next time the job will fire in that environment, always a UTC instant; null when the environment is not enabled or once a one-off has fired.
json
"environments": {
  "production": { "enabled": true },
  "staging":    { "enabled": true, "schedule": "0 6 * * *", "timezone": "Europe/London", "retry_policy": "retry-on-5xx", "url": "https://staging.example.com/cache/warm", "headers.Authorization": "Bearer staging" }
}

Here production runs the base definition unchanged, while staging overrides only its cadence, timezone, retry policy, URL, and one header — inheriting the base method, body, timeout, and every other base header. There is no top-level on/off switch — enablement and next-fire are per environment. Enable or pause a job by editing its environments entries and PUT-ting the job back.

The map governs recurring and manual jobs, and also names a one-off job's target environment(s): a one-off (a datetime or now schedule) is born in each environment you list as a key of the environments map — one run per environment — so a now one-off in {"production": {}, "staging": {}} enqueues a run in each. When the map is empty, a credential scoped to a single environment implies it; an unrestricted or multi-environment credential must name at least one.

Schedules

A job's schedule sets its kind. It is either omitted or a single string in one of three forms:

  • Omitted (or null) — a manual job. It never auto-fires; it runs only when you trigger it.
  • A 5-field cron expression — a recurring job. The cron is evaluated in the job's timezone (UTC unless you set one).
  • An ISO-8601 datetime — a one-off run at that instant. A datetime in the past runs as soon as possible.
  • The literal now — a one-off run once, as soon as possible.

The kind is implicit in the form: a cron expression recurs; no schedule never auto-fires; a datetime or now runs exactly once and then self-disables in its environment after the run is enqueued. To turn a future one-off into "run it now instead of later," PUT schedule=now — that is not the same as the run action, which leaves the schedule untouched.

If the scheduling engine was unavailable across one or more scheduled fires, on recovery it fires a single catch-up run for the most recent missed occurrence — not a backfill of every fire that was missed — and then resumes at the next future occurrence.

Timezones

By default a recurring job's cron is evaluated in UTC. Set a timezone to fire on a local wall-clock cadence instead — daylight-saving-aware. The timezone is a separate field from the cron expression: you author the 5-field expression directly (it is never translated between zones), and the timezone decides which clock it is matched against.

  • Per environment, with a base default. A job has a base timezone, and each environment may override it. Resolution mirrors schedule: the environment's timezone if set, else the base timezone, else UTC. A null or omitted timezone means UTC.
  • A valid IANA zone key. Any value other than null must be an IANA key such as America/New_York, Europe/London, or UTC.
  • Recurring jobs only. A timezone is meaningful only for a cron schedule. It is rejected on a manual or one-off job (a one-off datetime already carries its own offset; now is instantaneous).
  • UTC stays the canonical store. Only cron evaluation becomes zone-aware. next_run_at and every run timestamp are always UTC instants — the timezone shifts when the local wall-clock time maps to, not how times are stored or reported.
json
{
  "schedule": "0 2 * * *",
  "timezone": "America/New_York"
}

This job fires at 02:00 New York time every day — 06:00 or 07:00 UTC depending on daylight saving.

Daylight-saving transitions

Twice a year a local wall-clock time can be skipped or repeated. The schedule resolves both unambiguously:

  • Skipped time (spring forward — e.g. 30 2 * * * on a day when 02:30 does not exist): the job fires at the first valid instant after the nonexistent time (the moment the clock springs forward).
  • Ambiguous time (fall back — e.g. 30 1 * * * on a day when 01:30 occurs twice): the job fires once, at the earlier (pre-transition) occurrence.

HTTP configuration

For an http job, configuration describes the request to send:

FieldNotes
methodGET, POST, PUT, PATCH, or DELETE. Defaults to POST.
urlAbsolute http(s) URL, required, up to 2048 characters.
headersArray of { name, value } objects.
bodyRequest body, sent verbatim.
success_statusWhich response counts as success — a specific code (200) or a class (2xx). Defaults to 2xx (any 200-series).
timeoutPer-request timeout in seconds. Bounded by your plan's maximum.
tls_verifyVerify the server's TLS certificate. Defaults to true.
ca_certOptional PEM certificate to pin a private or self-signed CA.