A schedule (called a policy in the API) attaches an automated trigger to a concept so it runs without manual intervention. Two trigger types are supported: cron fires at a fixed calendar interval, and data_change polls for upstream data changes at a configurable interval and fires when new data is detected. All paths are relative to the base URL and require authentication. All responses use the standard envelope. The scope parameter follows the same scope semantics used across the platform.

Create a policy

Attach a new evaluation policy to a concept. On success the scheduler immediately registers the trigger; the concept will run at the next scheduled moment or when the data-change condition is met.
POST /schedules/{project_id}/policies
ParameterInRequiredDefaultDescription
project_idpathyesThe project ID.
concept_namebodyyesName of the concept this policy targets.
trigger_typebodyno"cron""cron" to fire on a calendar schedule; "data_change" to fire when upstream data changes.
trigger_configbodyyesConfiguration object for the chosen trigger type (see below).
scopebodyno"user"Scope of the concept.
enabledbodynotrueWhether the policy is active immediately after creation.
trigger_config for cron
{ "cron_expression": "0 3 * * *" }   // runs at 03:00 UTC every day
trigger_config for data_change
{ "check_interval_minutes": 15 }     // poll every 15 minutes; must be ≥ 1

Example

curl -X POST "$BASE_URL/schedules/$PROJECT_ID/policies" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "concept_name": "daily_report",
    "trigger_type": "cron",
    "trigger_config": { "cron_expression": "0 3 * * *" },
    "scope": "user",
    "enabled": true
  }'
{
  "status": "success",
  "message": "Evaluation policy created",
  "data": {
    "id": "pol_4a7f...",
    "project_id": "proj_123",
    "concept_name": "daily_report",
    "trigger_type": "cron",
    "trigger_config": { "cron_expression": "0 3 * * *" },
    "scope": "user",
    "enabled": true,
    "created_at": "2026-06-25T09:00:00+00:00"
  }
}

List policies

Return all evaluation policies for a project, optionally filtered to a single concept.
GET /schedules/{project_id}/policies
ParameterInRequiredDefaultDescription
project_idpathyesThe project ID.
scopequeryno"user"Scope of the project.
concept_namequerynoFilter results to policies targeting this concept.
curl "$BASE_URL/schedules/$PROJECT_ID/policies?scope=user" \
  -H "Authorization: Bearer $TOKEN"
data is an array of policy objects in the same shape as the create response.

Get a policy

Retrieve a single evaluation policy by ID.
GET /schedules/{project_id}/policies/{policy_id}
ParameterInRequiredDefaultDescription
project_idpathyesThe project ID.
policy_idpathyesThe policy ID.
scopequeryno"user"Scope of the project.
curl "$BASE_URL/schedules/$PROJECT_ID/policies/$POLICY_ID?scope=user" \
  -H "Authorization: Bearer $TOKEN"
{
  "status": "success",
  "message": "Policy loaded",
  "data": {
    "id": "pol_4a7f...",
    "project_id": "proj_123",
    "concept_name": "daily_report",
    "trigger_type": "cron",
    "trigger_config": { "cron_expression": "0 3 * * *" },
    "scope": "user",
    "enabled": true,
    "created_at": "2026-06-25T09:00:00+00:00"
  }
}
Returns 404 if the policy does not exist.

Update a policy

Change a policy’s trigger configuration or enable/disable it. Only the fields supplied in the request body are modified; omitted fields are left unchanged.
PATCH /schedules/{project_id}/policies/{policy_id}
ParameterInRequiredDefaultDescription
project_idpathyesThe project ID.
policy_idpathyesThe policy ID.
scopebodyno"user"Scope of the project.
trigger_configbodynoReplacement trigger configuration object. Must be a valid config for the policy’s existing trigger_type.
enabledbodynoPass true to activate or false to pause the policy.

Example — pause a policy

curl -X PATCH "$BASE_URL/schedules/$PROJECT_ID/policies/$POLICY_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": false, "scope": "user" }'
{
  "status": "success",
  "message": "Policy updated",
  "data": {
    "id": "pol_4a7f...",
    "enabled": false
  }
}
Returns 404 if the policy does not exist.

Delete a policy

Remove a policy and cancel its scheduled job. This does not affect run history already recorded.
DELETE /schedules/{project_id}/policies/{policy_id}
ParameterInRequiredDefaultDescription
project_idpathyesThe project ID.
policy_idpathyesThe policy ID.
scopequeryno"user"Scope of the project.
curl -X DELETE "$BASE_URL/schedules/$PROJECT_ID/policies/$POLICY_ID?scope=user" \
  -H "Authorization: Bearer $TOKEN"
{
  "status": "success",
  "message": "Policy deleted",
  "data": null
}
Returns 404 if the policy does not exist.

Trigger a policy now

Fire a policy’s concept run immediately, outside its normal schedule. Useful for testing a new policy or backfilling a missed run. The policy must exist and the trigger_now call enqueues an execution synchronously.
POST /schedules/{project_id}/policies/{policy_id}/trigger
ParameterInRequiredDefaultDescription
project_idpathyesThe project ID.
policy_idpathyesThe policy ID.
scopequeryno"user"Scope of the project.
curl -X POST "$BASE_URL/schedules/$PROJECT_ID/policies/$POLICY_ID/trigger?scope=user" \
  -H "Authorization: Bearer $TOKEN"
{
  "status": "success",
  "message": "Policy triggered successfully",
  "data": {
    "id": "pol_4a7f...",
    "concept_name": "daily_report",
    "last_triggered_at": "2026-06-25T11:42:00+00:00"
  }
}
To track whether the triggered run succeeded, poll Run history until a new entry appears with a terminal status (success or error).

Run history

Return the execution log for a policy, ordered by most recent first. Use limit and offset for pagination.
GET /schedules/{project_id}/policies/{policy_id}/runs
ParameterInRequiredDefaultDescription
project_idpathyesThe project ID.
policy_idpathyesThe policy ID.
scopequeryno"user"Scope of the project.
limitqueryno50Number of runs to return (1–500).
offsetqueryno0Number of runs to skip before returning results.
curl "$BASE_URL/schedules/$PROJECT_ID/policies/$POLICY_ID/runs?limit=10&offset=0" \
  -H "Authorization: Bearer $TOKEN"
{
  "status": "success",
  "message": "Run history loaded",
  "data": {
    "runs": [
      {
        "id": "run_9c1e...",
        "policy_id": "pol_4a7f...",
        "status": "success",
        "triggered_by": "cron",
        "started_at": "2026-06-25T03:00:01+00:00",
        "finished_at": "2026-06-25T03:00:08+00:00",
        "duration_ms": 7210,
        "error": null
      },
      {
        "id": "run_7b3d...",
        "policy_id": "pol_4a7f...",
        "status": "error",
        "triggered_by": "manual",
        "started_at": "2026-06-24T11:42:00+00:00",
        "finished_at": "2026-06-24T11:42:03+00:00",
        "duration_ms": 3100,
        "error": "VL0023: predicate 'raw_feed' not found"
      }
    ],
    "count": 2
  }
}
status valueMeaning
successThe concept ran and completed without error.
errorThe run failed; see the error field for the reason.
runningThe run is still in progress.
cancelledThe run was cancelled before completion.