POST /api/v1/llm/evals/runs. You read its samples and metrics the same way, through Results and artifacts.
Creating, updating, triggering, and deleting schedules requires an API key with write:evals. Reading schedules and their runs requires read:evals.
Create a schedule
eval.schedule object with an eval_sched_... ID. enabled is true unless you pass "enabled": false, which creates the schedule paused.
Choose a cadence
Provide exactly one of these fields:
An invalid cron expression is rejected with a
400 that explains the problem.
Each fire starts up to 30 seconds after its scheduled time, so schedules that share a boundary do not all start at once. A schedule set to * * * * * and created at 18:31:33 starts its first run at about 18:32. If the scheduler is unavailable when a fire is due, that fire still starts when the scheduler recovers within 5 minutes. A fire missed by more than 5 minutes is skipped.
What each run uses
runis a frozen copy of the run fields, withoutsuite_idandsuite_version. It sets the models, optional task subset, judge and embedding models, generation settings, concurrency, and sample cap.modelsis required.suite_versionpins one suite version. Omit it to run the suite’s active version at each fire, so a new active version takes effect at the next fire.metadatais copied onto every run the schedule starts.- Each run executes as the identity that created the schedule, or that most recently updated it. At each fire, that identity’s access is checked again, and its API key scopes are capped at the scopes it had when it last saved the schedule.
Check a schedule
Retrieve a schedule to see when it fires next and what happened the last time it fired.last_run_status takes these values:
List the runs a schedule created
status, suite_version, or suite_id. Passing a suite_id other than the schedule’s returns 400.
Trigger a run now
Trigger a schedule to fire it immediately, in addition to its normal cadence. The fire creates a run exactly as a scheduled fire would.200 response means the fire was accepted, not that a run was created. Confirm the run with last_run_id or the schedule’s runs list.
- Under the default
skipoverlap policy, a trigger while one of the schedule’s runs is still active returns200, but no run is created. See Overlapping runs. - Triggering a paused schedule returns
409. Resume it first. - A
400with codeschedule_trigger_unknownmeans the API could not confirm whether the fire started. Check the schedule’s runs before you trigger again. Do not retry this error automatically.
Overlapping runs
overlap_policy decides what happens when a fire arrives while an earlier run from the same schedule is still active.
Use
skip for schedules whose runs can outlast the interval between fires. There is no team-wide cap on concurrent scheduled runs, so with allow_all a short interval can start runs faster than they finish. Keep generation_concurrency and grader_concurrency in run low enough for that.
Pause, resume, and update
Update any field with a partial request. To pause a schedule, setenabled to false. To resume it, set enabled back to true.
- A paused schedule keeps its cadence and fires again when you resume it.
- To switch cadence, set the new field, for example
{ "interval_seconds": 3600 }. The other cadence field is cleared. Sending both returns400. - Replacing
runreplaces the whole run configuration. - Every successful update, even a rename, rebinds future runs to the identity making the update.
- If an update returns a server error, retrieve the schedule. If
enabledis nowfalse, the update was saved but the schedule was paused for safety. Send the update again with"enabled": trueto resume it.
enabled to false, when the target suite version is deleted or the owning identity loses access. last_run_status tells you which. Fix the cause, then set enabled to true.
To stop a schedule permanently, delete it. Deleting a schedule keeps the runs it already created.
Get notified about runs
Setwebhook_url to receive a POST each time a run the schedule created changes status. The URL must use HTTPS and resolve to public addresses.
The webhook receives these events:
Each request body has this shape:
- When you set
webhook_secret(16 to 256 characters), each request carriesX-Webhook-Signature: sha256=<hmac>, an HMAC-SHA256 of the request body. The secret is never returned.webhook_configuredtells you whether one is stored. - Delivery is at least once. Deduplicate on
resource_idplusevent. - Each event is attempted up to 3 times with backoff. Only a
2xxresponse counts as delivered. Events that still fail are not queued for later delivery.
eval.run.failed as your failure alert. A run whose samples all fail still completes, so also check request_counts.failed and metrics in eval.run.completed events.
What to read next
- Run an eval covers suites, one-off runs, and deletion.
- Results and artifacts covers samples, scores, and artifact downloads.
- The eval schedules API reference lists every request and response field.