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
- Open the product dashboard → Settings → Security.
- Choose Generate secret (or Rotate secret if one already exists).
- 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. - 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) |
- Secret format:
whsec_+ base64(32 random bytes). - Signed content:
{webhook-id}.{webhook-timestamp}.{raw_json_body}(exact bytes of the request body). - Signature: strip the
whsec_prefix, base64-decode the remainder, compute HMAC-SHA256, base64-encode the digest, prefix withv1,. - Receivers should reject timestamps more than about 5 minutes from current time (replay protection).
- Custom destination
headersfrom the schedule still apply, but they never overwrite the three signature headers above.
Verify (any language)
- Read the raw request body (do not re-serialize JSON before verifying).
- Require
webhook-id,webhook-timestamp, andwebhook-signature. - Reject if
|now - timestamp|is greater than ~5 minutes. - Decode the secret (strip
whsec_, base64-decode). - HMAC-SHA256 the string
{id}.{timestamp}.{body}; accept if any space-separated entry inwebhook-signaturematchesv1,<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
- Agents
- Tasks — one-shot runs only
- CLI reference
- Errors