EN IT

Scheduler

The Scheduler lets you program deferred HTTP callbacks: "in N seconds (or at a given date/time) call this URL with this payload". It supports one-shot and recurring jobs (by interval or by calendar), with automatic retries, dead-letter and a dashboard to inspect the queue and history.

How it works

Job state lives in a dedicated container: the store is the queue. An internal poller (every ~1 minute) picks up due jobs, runs their HTTP callback and updates the outcome. As a result:

  • Firing precision equals the poll interval (~1 minute): it is not meant for second-level callbacks.
  • The model is at-least-once: receivers must tolerate duplicate calls (use the idempotency key, see below).
  • All instants are stored in UTC; calendar scheduling uses Italian wall-clock time (see Recurrence).

Endpoints

Method Endpoint Description Scope
POST /scheduled-jobs Create a deferred job write
GET /scheduled-jobs Paginated list (filters: status, from, to) read
GET /scheduled-jobs/{id} Job detail read
DELETE /scheduled-jobs/{id} Cancel a job (only while Pending) write

Creating a job

curl -X POST "https://api.contit.cloud/scheduled-jobs" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Order reminder",
    "delaySeconds": 3600,
    "callbackUrl": "https://example.com/hooks/reminder",
    "method": "POST",
    "headers": { "X-Source": "contit" },
    "payload": { "orderId": "abc123" },
    "maxRetries": 5
  }'

Response: the created job, with id and status: "Pending".

Request fields

Field Type Description
name string Friendly name (optional).
delaySeconds number Seconds to wait from now. Alternative to fireAtUtc.
fireAtUtc datetime Absolute fire time (UTC). Takes precedence over delaySeconds.
callbackUrl string http(s) URL to call. Required.
method string HTTP method (default POST).
headers object Custom HTTP headers sent with the callback.
payload any (JSON) Body sent to the callback (ignored for GET/HEAD).
maxRetries number Max attempts before dead-letter (default 5).
idempotencyKey string Dedup key propagated to the receiver (generated if absent).
correlationId string Correlation id for end-to-end tracing.
recurrenceSeconds number Interval recurrence (see below).
scheduleTimes string[] Calendar recurrence: "HH:mm" times (see below).
scheduleDaysOfWeek number[] Allowed days (0=Sunday .. 6=Saturday).
endAtUtc datetime Recurrence stop: no occurrence past this date.
maxOccurrences number Recurrence stop: maximum number of occurrences.

Recurrence

A job can repeat automatically: when an occurrence completes (on success or dead-letter — the series continues even after a failure) the next one is created. All occurrences share a seriesId and have an increasing occurrenceNumber.

By interval

recurrenceSeconds (minimum 60): the next occurrence fires at a fixed cadence relative to the planned one.

{
  "name": "Hourly ping",
  "callbackUrl": "https://example.com/ping",
  "recurrenceSeconds": 3600
}

By calendar (daily / weekly)

scheduleTimes (one or more "HH:mm" times) and optionally scheduleDaysOfWeek. Times are Italian wall-clock time (Europe/Rome) with automatic DST handling; the first run is the next matching occurrence.

// Every day at 10:00 and 15:00
{
  "name": "Daily sync",
  "callbackUrl": "https://example.com/sync",
  "scheduleTimes": ["10:00", "15:00"]
}
// Monday and Tuesday at 11:00, max 10 occurrences
{
  "callbackUrl": "https://example.com/report",
  "scheduleTimes": ["11:00"],
  "scheduleDaysOfWeek": [1, 2],
  "maxOccurrences": 10
}

The cadence is fixed: even if a run is delayed by retries, the next occurrence is anchored to the planned time (no drift). If the poller was down, it resumes from the next future occurrence without replaying missed ones.

Retries and dead-letter

On failure (HTTP error or exception) the attempt is counted and the job rescheduled with exponential backoff (2^(attempts-1) minutes, capped at 1 hour). Once maxRetries is exceeded the job moves to DeadLetter and is logged as an error (useful for alerting).

Statuses

Status Meaning
Pending Waiting to fire.
Firing Claimed by the poller, delivery in progress.
Done Callback delivered successfully.
Cancelled Cancelled via DELETE (was Pending).
DeadLetter All attempts failed.

Jobs in a terminal state (Done, Cancelled, DeadLetter) are cleaned up automatically after 30 days.

Callback security

Each callback includes extra headers:

  • Contit-Idempotency-Key — the occurrence's idempotency key.
  • Contit-Correlation-Id — if set on the job.
  • Contit-Signature — HMAC-SHA256 signature of the body in the form t={timestamp},s={signature}, present only if a signing secret is configured. Verify it on the receiver by recomputing HMAC-SHA256(secret, "{timestamp}.{body}").

SDK

var client = new ContitClient(apiKey);

// One-shot in 1 hour
var job = await client.ScheduledJob.Create(new CreateScheduledJobRequest
{
    Name = "Order reminder",
    DelaySeconds = 3600,
    CallbackUrl = "https://example.com/hooks/reminder",
    Payload = JToken.Parse("""{ "orderId": "abc123" }""")
});

// Recurring: every day at 10:00 and 15:00
await client.ScheduledJob.Create(new CreateScheduledJobRequest
{
    Name = "Daily sync",
    CallbackUrl = "https://example.com/sync",
    ScheduleTimes = new List<string> { "10:00", "15:00" }
});

// Inspect and cancel
var pending = await client.ScheduledJob.Get(status: ScheduledJobStatus.Pending);
await client.ScheduledJob.Cancel(job.Id);

Dashboard

In the panel, under Settings → Developer → Scheduler, you'll find the list of jobs (filterable by status), the detail view with payload/headers/outcome, and a New job button to create them manually — including the visual builder for daily/weekly scheduling at one or more times.