INSULA LABS

HTML docs · raw markdown

Schedules

Armed schedules enqueue runner jobs on a fixed interval preset (same options as the product UI). Free-form cron is not accepted. Optional webhook hooks are accepted as plaintext JSON on create; the server encrypts them before sending to the runner. Ciphertext is never returned.

Schedule-triggered runs are not listed under tasks. Only one-shot API tasks appear there.

Interval presets

kobold-cli schedules intervals
GET /v1/schedules/intervals
Authorization: Bearer <api_key>
id Label
every_minute Every minute
every_5_minutes Every 5 minutes
every_25_minutes Every 25 minutes
every_30_minutes Every 30 minutes
every_hour Every hour
daily_09_00 Daily 09:00
weekly_mon_09_00 Weekly Mon 09:00

Response shape: { "intervals": [ { "id", "label" }, … ] }.

Schedule object

Field Notes
id Public sch_…
agentId Public ag_…
agentName Display name
knowledgebaseId Public kb_… when known
knowledgebaseName When resolvable
prompt Prompt text
interval Preset id when the cron matches a known interval
enabled Whether the schedule is armed
createdAt / updatedAt RFC 3339
lastEnqueuedAt RFC 3339, optional

List

Query: offset, limit (default 50).

kobold-cli schedules list
kobold-cli schedules list -offset 0 -limit 20
GET /v1/schedules?offset=0&limit=50
Authorization: Bearer <api_key>
{
  "schedules": [ /* Schedule objects */ ],
  "offset": 0,
  "limit": 50,
  "total": 1
}

Create

Requires agentId, knowledgebaseId, prompt, and interval. Optional hooks with onComplete / onFail webhook destinations.

kobold-cli schedules create -agent ag_7k2m9x4q -kb kb_qc0rp0gz -prompt "Summarize new files" -interval daily_09_00
kobold-cli schedules create -agent ag_7k2m9x4q -kb kb_qc0rp0gz -prompt ./prompt.md -interval every_hour -hooks ./hooks.json
POST /v1/schedules
Authorization: Bearer <api_key>
Content-Type: application/json

{
  "agentId": "ag_7k2m9x4q",
  "knowledgebaseId": "kb_qc0rp0gz",
  "prompt": "Summarize new files",
  "interval": "daily_09_00",
  "hooks": {
    "onComplete": {
      "type": "webhook",
      "webhook": {
        "url": "https://example.com/hook",
        "headers": { "Authorization": "Bearer …" }
      }
    },
    "onFail": {
      "type": "webhook",
      "webhook": { "url": "https://example.com/fail" }
    }
  }
}
Field Required Notes
agentId yes Owner agent from agents list
knowledgebaseId yes Knowledgebase kb_…
prompt yes Inline text (CLI also accepts a local file path)
interval yes One of the preset ids above
hooks no Only type: "webhook"; webhook.url must be http/https; optional headers

Success 200: a Schedule. Unknown agent/KB → 404. Unknown interval or invalid webhook → 400. Schedule/task limit → 429. Upstream/provider failure → 502.

Hooks file for the CLI (-hooks):

{
  "onComplete": {
    "type": "webhook",
    "webhook": { "url": "https://example.com/hook", "headers": { "Authorization": "Bearer …" } }
  },
  "onFail": {
    "type": "webhook",
    "webhook": { "url": "https://example.com/fail" }
  }
}

Get

kobold-cli schedules get -id sch_7k2m9x4q
GET /v1/schedules/sch_7k2m9x4q
Authorization: Bearer <api_key>

Unknown or other-tenant id → 404.

Enable / disable

kobold-cli schedules enable -id sch_7k2m9x4q
kobold-cli schedules disable -id sch_7k2m9x4q
POST /v1/schedules/sch_7k2m9x4q/enable
Authorization: Bearer <api_key>
POST /v1/schedules/sch_7k2m9x4q/disable
Authorization: Bearer <api_key>

Success returns the updated Schedule.

Delete

kobold-cli schedules delete -id sch_7k2m9x4q
DELETE /v1/schedules/sch_7k2m9x4q
Authorization: Bearer <api_key>

Success: {} / CLI {"ok": true}.

Webhook signing

Schedule hooks can be authenticated with a Standard Webhooks HMAC secret. Signing is account-level (one secret for all of your schedule destinations), not per URL. There is no public API to create or fetch the secret.

Configure the signing secret

  1. Open the product dashboard → SettingsSecurity.
  2. Choose Generate secret (or Rotate secret if one already exists).
  3. Copy the whsec_… value immediately and store it in your receiver’s config (for example an environment variable). The plaintext is shown once, same as API keys.
  4. Use Delete to revoke the secret. Until you generate a new one, hooks are sent unsigned again.

Until a secret is configured, hooks still POST to your URL with the JSON body and any custom headers you set — they are simply unsigned. After a secret is configured, every schedule webhook from that account is signed.

How signing works

Outbound POSTs use symmetric HMAC (Standard Webhooks), not public/private keys.

Header Value
webhook-id Unique message id (msg_…)
webhook-timestamp Unix seconds
webhook-signature One or more v1,<base64> entries (space-delimited)

Verify (any language)

  1. Read the raw request body (do not re-serialize JSON before verifying).
  2. Require webhook-id, webhook-timestamp, and webhook-signature.
  3. Reject if |now - timestamp| is greater than ~5 minutes.
  4. Decode the secret (strip whsec_, base64-decode).
  5. HMAC-SHA256 the string {id}.{timestamp}.{body}; accept if any space-separated entry in webhook-signature matches v1,<base64> (constant-time compare).

Verify in Go

import (
    "net/http"
    "os"

    "github.com/InsulaLabs/web-api/api"
)

func handle(w http.ResponseWriter, r *http.Request) {
    wh, err := api.ParseIncomingWebhook(r)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    if err := wh.Validate(os.Getenv("KOBOLD_WEBHOOK_SECRET")); err != nil {
        http.Error(w, err.Error(), http.StatusUnauthorized)
        return
    }
    // wh.Body / wh.Payload
}

Validate implements the checklist above (missing headers, skew window, and HMAC).

Related