Success assertions
A success assertion is an extra check on a 2xx response. Use one when a 200 isn’t proof that things worked, for example a health endpoint that answers 200 with "status": "degraded", or an API that reports errors inside a 200 body.
Here is a health check with three assertions. The run passes only if all three hold:
| Type | Value | Checks |
|---|---|---|
| Status code equals | 200 | The response is exactly 200 |
| JSON path equals | status=ok | The body’s status field is ok |
| Response time under (ms) | 2000 | The response arrived in under 2 seconds |
How assertions are checked
- Only 2xx responses are checked. A 3xx, 4xx or 5xx response, a timeout or a connection error is already a failure, and assertions are skipped. An assertion can’t turn an error into a success, so “Status code equals”
404never passes. - All assertions must pass. If any one fails, the run fails.
- Up to 10 per cron or queue. Each value is text, up to 1,024 characters.
- The full body is checked, even when the stored copy is cut at 65,535 bytes.
Assertion types
| Label in the dashboard | Type | Value | Passes when |
|---|---|---|---|
| Status code equals | status_code_equals | One status code, e.g. 200 | The status code is exactly this |
| Status code in | status_code_in | Codes separated by commas, e.g. 200,201,204 | The status code is in the list. Spaces are allowed. |
| Body contains | body_contains | Any text, e.g. ok | The body contains the text |
| Body does not contain | body_not_contains | Any text, e.g. error | The body doesn’t contain the text |
| JSON path equals | json_path_equals | path=expected, e.g. data.status=active | The value at the path equals the expected value |
| Response time under (ms) | response_time_under_ms | Milliseconds, e.g. 5000 | The run took less than this |
Body contains and Body does not contain
The match is exact and case-sensitive: ok doesn’t match OK. Whatever you type is the search text, quotes included. The value "error" looks for the word with its quotes, which is a handy way to match a JSON key or string rather than any occurrence of the word.
JSON path equals
The value is a path, an =, and the expected value. The body must be JSON, otherwise the check fails with “Response body is not valid JSON”.
- Paths use dots.
statusis a top-level field,data.statusis a nested one, anditems.0.idis theidof the first element ofitems. - Only the first
=splits. Innote=a=b, the path isnoteand the expected value isa=b. Spaces around the path and the value are ignored. - Write the value the way JSON writes it, without quotes around strings:
status=ok(notstatus="ok"),count=3,ratio=1.5,healthy=true,healthy=false,error=null. - A missing field fails. If the path isn’t in the response, the check fails with “JSON path “healthy” not found in the response”, whatever the expected value.
- Objects and lists compare as compact JSON.
meta={"ok":true}passes whenmetais exactly that object. Usually it’s simpler to point the path at a single value inside it, likemeta.ok=true.
Response time under (ms)
The time runs from the start of the run until the response arrives, including the DNS lookup and connecting. It must be strictly less than the value: 5000 fails at exactly 5,000 ms. Keep it below the request timeout, or the request times out before the assertion can fail.
When an assertion fails
The run fails with the reason assertion_failed (shown as “Assertion failed”). The error message lists every assertion that didn’t pass, separated by semicolons:
Assertion failed: JSON path "status" is "degraded", expected "ok"; Response time 2341ms exceeds 2000ms limitOther messages you may see:
Expected status code 200, got 204Status code 202 not in [200, 204]Response body does not contain "ok"Response body contains "error" (should not)Response body is not valid JSONInvalid format. Use "path=expected_value"The response status, headers and body are still recorded, so you can compare them with your assertions. What happens next depends on where the assertion is set:
- Cron: the run is marked Failed and counts toward Failure alerting. Crons don’t retry, so the next attempt is the next scheduled run.
- Job: the attempt is retried like any other failure, using the queue’s retry delays. When the retries run out, the job goes to the dead letter queue. See Queues.
Where to set assertions
Assertions are set in the dashboard, on a cron or on a queue:
- Cron: open Cron jobs, then New cron job (or Edit on an existing cron). Under Success assertions, click Add assertion, pick a type and enter a value.
- Queue: open Queues, then New queue (or edit a queue), and use the same Success assertions section. Queue assertions apply to every job in that queue. A single job can’t have its own.
With no assertions, the box reads “No assertions added. All HTTP responses will be considered successful.” In practice that means every 2xx response. Assertions aren’t shown on the cron or queue page; open the edit form to see them.
The API can’t set assertions
Neither POST /api/crons nor POST /api/jobs accepts assertions. A success_assertions field in the request is ignored without an error. To use assertions with API-created resources:
- Crons: create the cron with the API, then open it in the dashboard, click Edit and add the assertions.
- Jobs: add the assertions to the queue. Queues that the API creates for you start with none.
Examples
Health check that reports its own state. Your endpoint returns {"status": "ok", "database": {"connected": true}}:
| Type | Value |
|---|---|
| Status code equals | 200 |
| JSON path equals | status=ok |
| JSON path equals | database.connected=true |
| Response time under (ms) | 3000 |
API that hides errors in a 200. Fail when the body includes an error key:
| Type | Value |
|---|---|
| Body does not contain | "error" |
Accept “done” and “nothing to do”. Your endpoint returns 200 when it did work and 204 when there was nothing to do, and anything else in the 2xx range means something unexpected happened:
| Type | Value |
|---|---|
| Status code in | 200,204 |
Page must show the right content. Catch a maintenance page or an empty template served with 200:
| Type | Value |
|---|---|
| Body contains | Order history |
| Body does not contain | Maintenance |
Next steps
- Runs and failure reasons: how a failed assertion appears next to other failures.
- Cron schedules: how crons run, and why they don’t retry.
- Queues: queue settings, including retries after a failed assertion.
- Write endpoints Delay can call: design a health endpoint that’s easy to assert on.