Skip to main content

Asserts & tests

Asserts validate data. Add an assert: block with a list of tests to an action (to gate it) or to an interface (to check the final result). Each test resolves a value — with value (a JSON path), jq, pointer, or an action reference — then checks it with one or more conditions.

actions:
- name: CheckBody
input: a|body|
assert:
http_code_on_error: 400
tests:
- value: email
is_not_null: true
is_not_empty: true
- value: age
data_type: Number # a body or query value can arrive as text
is_greater_than_or_equal_to: 18

The condition vocabulary is large — equality and ordering, string/pattern (contains, like, regex, …), type and emptiness, and specialized validators (is_valid_jwt, is_valid_hmac, verify_bcrypt, verify_signature, verify_schema, semver_matches, …). The filter transform reuses the same Test vocabulary. Every field of Assert and Test follows.

Assert

Assertion block for validating action output or interface results. Groups one or more tests with shared error handling and HTTP response codes.

Example - Action-level assertion

actions:
- name: ValidateBody
input: a|body|
assert:
tests:
- value: email
is_not_empty: true
regex: "^[^@]+@[^@]+\\.[^@]+$"
- value: age
data_type: Number
is_greater_than: 0
error_message: "Validation failed"
http_code_on_error: 400

Example - Interface-level assertion

interfaces:
getUser:
method: GET
actions:
- name: FetchUser
database: main
query: SELECT * FROM users WHERE id = $1
params:
- a|params::id|
assert:
tests:
- value: count()
is_equal_to: 1
error_message: "User not found"
http_code_on_error: 404
http_code_on_success: 200
FieldTypeDescription
success_messagestring (nullable)Message returned on successful assertion.
error_messagestring (nullable)Message returned when any test fails. Overrides individual test error messages at the assert level.
http_code_on_errornumber (nullable)HTTP status code to return when any test fails. Individual test-level http_code_on_error takes precedence when set.
http_code_on_successnumber (nullable)HTTP status code to return when all tests pass.
testsArray<Test> (nullable)List of test definitions to evaluate. All tests run concurrently; errors from all tests are collected and returned together. Example ↓

Field examples

tests

List of test definitions to evaluate. All tests run concurrently; errors from all tests are collected and returned together.

Example

tests:
- value: username
is_not_empty: true
error_message: "Username is required"
http_code_on_error: 422
- value: password
is_not_empty: true
contains_upper: true
contains_number: true
data_type: String
is_greater_than: 7

Test

Test definition for asserting conditions against a resolved value. Tests support value resolution (via value, jq, pointer, or action), type-aware comparisons, pattern matching, and structural schema validation.

When used inside an assert block, multiple tests run concurrently. When used inside verify_schema via FieldType.validate, the test runs against the leaf value at that schema path.

Example - Basic value checks

tests:
- value: email
is_not_empty: true
regex: "^[^@]+@[^@]+\\.[^@]+$"
error_message: "Invalid email"
http_code_on_error: 422

Example - Numeric comparisons

tests:
- value: age
data_type: Number
is_greater_than: 0
is_less_than: 150
- value: count()
is_greater_than_or_equal_to: 1

Example - Using jq for nested access

tests:
- jq: ".data.users | length"
data_type: Number
is_greater_than: 0

Example - Cross-action reference

tests:
- action: FetchUser
value: email
is_not_null: true

Example - Allowed/disallowed values

tests:
- value: status
contains:
allowed:
- "active"
- "pending"
- "suspended"
disallowed:
- "deleted"

Example - Schema validation with deep nested assertions

tests:
- verify_schema:
disallow_unknown_keys: true
structure:
email:
data_type: String
validate:
is_not_empty: true
regex: "^[^@]+@[^@]+\\.[^@]+$"
age:
data_type: Number
validate:
is_greater_than: 0
settings:
theme:
data_type: String
notifications:
data_type: Boolean
FieldTypeDescription
namestring (nullable)Human-readable name for identifying this test in logs and error output.
descriptionstring (nullable)Description of what this test validates.
valuestring (nullable)JSON path to the target value within the input data (e.g., email, user.name). Also supports count(): elements of an array, keys of an object, characters of a string, 0… Example ↓
actionstring (nullable)Reference a previous action's output as the target value. Example ↓
action_valuestring (nullable)Reference a previous action's output using interpolation syntax. The full marker grammar applies — paths, jq::, and filters — and the result keeps its JSON type. Example ↓
custom_valuestring (nullable)Override the target value with a custom literal string. Example ↓
jqstring (nullable)Extract the target value using a jq filter expression. Example ↓
pointerstring (nullable)Extract the target value using a JSON pointer (RFC 6901). Example ↓
http_code_on_errornumber (nullable)HTTP status code to return when this specific test fails. Takes precedence over the parent Assert.http_code_on_error.
success_messagestring (nullable)Message returned when this test succeeds.
error_messagestring (nullable)Custom error message when this test fails. Replaces the default auto-generated error detail. Example ↓
hide_errorsboolean (nullable)Suppress error details from the response output for this test.
http_responseanyStatic HTTP response value to return when this test is evaluated.
case_insensitiveboolean (nullable)Enable case-insensitive matching for is_equal_to and contains checks. Example ↓
is_equal_toanyAssert the value equals the expected value. Behavior varies by type: strings compare as text, numbers as numeric value, booleans as bool, arrays and objects compare as full… Example ↓
is_not_equal_toanyAssert the value does not equal the expected value. Example ↓
is_less_thananyAssert the value is less than the threshold. For arrays, compares the length; for numbers, the numeric value. A string needs data_type to say which is meant — NumberExample ↓
is_less_than_or_equal_toanyAssert the value is less than or equal to the threshold. Same type-dependent behaviour as is_less_than, including needing data_type for a string.
is_greater_thananyAssert the value is greater than the threshold. Same type-dependent behaviour as is_less_than, including needing data_type for a string. Example ↓
is_greater_than_or_equal_toanyAssert the value is greater than or equal to the threshold. Same type-dependent behaviour as is_less_than, including needing data_type for a string.
starts_withanyAssert the string value starts with the given prefix. Example ↓
not_starts_withany
ends_withanyAssert the string value ends with the given suffix. Example ↓
not_ends_withany
contains_textboolean (nullable)Assert the string contains at least one alphabetic character.
contains_numberboolean (nullable)Assert the string contains at least one numeric digit.
contains_upperboolean (nullable)Assert the string contains at least one uppercase letter.
contains_lowerboolean (nullable)Assert the string contains at least one lowercase letter.
contains_specialboolean (nullable)Assert the string contains at least one special character.
containsContainOptions (nullable)Assert containment. Behavior varies by target type: - String: substring match (or exact match in advanced/any mode) - Number: substring match against the string… Example ↓
likestring (nullable)SQL LIKE-style pattern matching (case-sensitive). Uses % as wildcard. Example ↓
ilikestring (nullable)SQL ILIKE-style pattern matching (case-insensitive). Uses % as wildcard. Example ↓
not_containsContainOptions (nullable)Inverse of contains for the standard and advanced modes: assert the value does NOT contain the specified content. The allowed/disallowed mode is NOT inverted. Those list… Example ↓
regexstring (nullable)Assert the string value matches a regular expression pattern. Example ↓
is_not_nullboolean (nullable)Assert the value is not null. Example ↓
is_not_emptyboolean (nullable)Assert the value is not empty. Checks strings, arrays, and objects. Example ↓
is_nullboolean (nullable)Assert the value is null (when true) or is not null (when false). Example ↓
is_uuidboolean (nullable)Assert the value is a valid UUID string. Example ↓
is_arrayboolean (nullable)Assert the value is a JSON array. Example ↓
is_emptyboolean (nullable)Assert the value is empty: an empty string, an empty array, an empty object, or null. The inverse of is_not_empty, which existed without it. Example ↓
is_stringboolean (nullable)Assert the value is a string. Example ↓
is_numberboolean (nullable)Assert the value is a number. A numeric string does not satisfy this — use regex if you mean "looks like a number". Example ↓
is_booleanboolean (nullable)Assert the value is a boolean. Example ↓
is_objectboolean (nullable)Assert the value is an object. Example ↓
is_inArray<any> (nullable)Assert the value is one of a fixed set. This is the opposite direction from contains: contains asks whether the target holds a given item, is_in asks whether the target… Example ↓
not_inArray<any> (nullable)Assert the value is not one of a fixed set. Example ↓
is_betweenBetweenRange (nullable)Assert a number — or the size of an array or object — falls within an inclusive range. Example ↓
data_typestring (nullable)One of Number, String, Array or Object, case-insensitive — what this value is, so a comparison does not have to guess. Required when ordering a string. Not the same… Example ↓
is_beforestring (nullable)Assert the value is strictly before the given moment. Example ↓
is_afterstring (nullable)Assert the value is strictly after the given moment. Example ↓
is_on_or_beforestring (nullable)Assert the value is before, or the same instant as the given moment. Example ↓
is_on_or_afterstring (nullable)Assert the value is after, or the same instant as the given moment. Example ↓
is_same_time_asstring (nullable)Assert the value is the same instant as the given moment. Example ↓
is_not_same_time_asstring (nullable)Assert the value is a different instant from the given moment. Example ↓
is_dateboolean (nullable)Assert the value parses as a date at all, in any of the accepted formats. Example ↓
not_regexstring (nullable)Assert the string value does NOT match a regular expression. The negated form of regex, which had not_contains, not_starts_with and not_ends_with as counterparts but no… Example ↓
not_likestring (nullable)SQL LIKE-style pattern that must NOT match (case-sensitive). Uses % as wildcard. Example ↓
not_ilikestring (nullable)SQL ILIKE-style pattern that must NOT match (case-insensitive). Example ↓
is_emailboolean (nullable)Assert the value parses as an email address. Example ↓
is_urlboolean (nullable)Assert the value parses as an absolute URL with a scheme and a host. Example ↓
is_ipboolean (nullable)Assert the value parses as an IPv4 or IPv6 address. Example ↓
is_valid_jwtJwtConfig (nullable)Validate the value as a JWT token using the provided secret. On success, decoded claims are stored in ok_data under the key specified by result_key (default: jwt_claims). Example ↓
is_valid_hmacIsValidHmacConfig (nullable)Verify an HMAC signature. The value field should point to the signature received in the request (e.g. x-hub-signature-256). The assertion recomputes HMAC over body using… Example ↓
is_valid_totpIsValidTotpConfig (nullable)Assert the value is a currently-valid RFC 6238 time-based one-time password for the shared secret — the second factor an authenticator app shows. Fails closed: a target that is… Example ↓
is_authorizationboolean (nullable)Parse an HTTP Authorization header value. Supports Basic (decodes base64 username:password) and Bearer (extracts token). Decoded data is stored in ok_data keyed by scheme… Example ↓
result_keystring (nullable)Key name for storing extracted data (e.g., JWT claims) in the action's ok_data output.
expressionstring (nullable)Evaluate a string expression as a boolean condition. Supports interpolation via a|...| syntax before evaluation. Example ↓
compare_valueCompareValue (nullable)Compare the target value against another value or file for structural differences. Supports JSON, XML, and string comparison with optional field exclusions. Example ↓
bcrypt_verifystring (nullable)Verify a plaintext value against a bcrypt hash. Deprecated: use verify_bcrypt.
verify_bcryptstring (nullable)Verify a plaintext value against a bcrypt hash. Example ↓
verify_signatureVerifySignature (nullable)Verify an Ed25519 signature against the target value. Example ↓
verify_schemaVerifySchema (nullable)Validate the value against a structural schema with recursive type checking and optional per-field assertions. Supports nested objects, arrays, and leaf-level validation via… Example ↓
semver_matchesstring (nullable)Assert the string value satisfies a semver version constraint. Example ↓
size_limitstring (nullable)Assert the serialized byte size of the value does not exceed a limit. Accepts human-readable sizes (e.g., 1 MB, 500 KB) or raw byte counts. Example ↓

Field examples

value

JSON path to the target value within the input data (e.g., email, user.name). Also supports count(): elements of an array, keys of an object, characters of a string, 0 for null. It works the same way with action:, against that action's data.

Example

value: email             # simple key
value: user.address.city # nested path
value: count() # how many

action

Reference a previous action's output as the target value.

Example

action: FetchUser
value: email # key within that action's output

action_value

Reference a previous action's output using interpolation syntax. The full marker grammar applies — paths, jq::, and filters — and the result keeps its JSON type.

Example

action_value: a|FetchUser::email|
action_value: a|Rows->length|

custom_value

Override the target value with a custom literal string.

Example

custom_value: "some_static_value"
is_equal_to: "some_static_value"

jq

Extract the target value using a jq filter expression.

Example

jq: ".users[0].email"
is_not_empty: true

pointer

Extract the target value using a JSON pointer (RFC 6901).

Example

pointer: "/data/0/email"
is_not_empty: true

error_message

Custom error message when this test fails. Replaces the default auto-generated error detail.

Example

value: email
is_not_empty: true
error_message: "Email address is required"

case_insensitive

Enable case-insensitive matching for is_equal_to and contains checks.

Example

value: status
is_equal_to: "active"
case_insensitive: true # matches "Active", "ACTIVE", etc.

is_equal_to

Assert the value equals the expected value. Behavior varies by type: strings compare as text, numbers as numeric value, booleans as bool, arrays and objects compare as full JSON equality.

Example

is_equal_to: "active"      # string
is_equal_to: 42 # number
is_equal_to: true # boolean

Not for null. is_equal_to: null asserts nothing — YAML null and an absent key deserialise identically, so the check is skipped silently. Use is_null: true.

is_not_equal_to

Assert the value does not equal the expected value.

Example

is_not_equal_to: "deleted"

Not for null. is_not_equal_to: null asserts nothing — see is_equal_to. Use is_not_null: true.

is_less_than

Assert the value is less than the threshold. For arrays, compares the length; for numbers, the numeric value. A string needs data_type to say which is meant — Number for its value, String for its length — and is an error without one, because "3650" could be either.

Example

# String: fewer than 256 characters. The declaration is required --
# without it the engine cannot tell this from a value comparison.
value: title
data_type: String
is_less_than: 256

# Number: value under 100. Declare it too wherever the value can arrive
# as text -- a query parameter always does.
value: percentage
data_type: Number
is_less_than: 100

# Array: fewer than 10 elements. Arrays infer, so nothing to declare.
value: items
is_less_than: 10

is_greater_than

Assert the value is greater than the threshold. Same type-dependent behaviour as is_less_than, including needing data_type for a string.

Example

# `age` can arrive as text from a query parameter, so say which reading
# is meant. Undeclared, a string here is an error.
value: age
data_type: Number
is_greater_than: 0

starts_with

Assert the string value starts with the given prefix.

Example

value: url
starts_with: "https://"

ends_with

Assert the string value ends with the given suffix.

Example

value: filename
ends_with: ".pdf"

contains

Assert containment. Behavior varies by target type:

  • String: substring match (or exact match in advanced/any mode)
  • Number: substring match against the string representation
  • Array: element membership
  • Object: key existence

Supports three modes: standard (single value or array), advanced (with at_least threshold), and any (with allowed/disallowed lists).

Example - String substring

value: email
contains: "@"

Example - Array membership

value: tags
contains: "featured"

Example - Allowed values

value: status
contains:
allowed:
- "active"
- "pending"
disallowed:
- "deleted"

Example - At least N matches

value: roles
contains:
values:
- "admin"
- "editor"
- "viewer"
at_least: 1

like

SQL LIKE-style pattern matching (case-sensitive). Uses % as wildcard.

Example

value: name
like: "John%" # starts with "John"

ilike

SQL ILIKE-style pattern matching (case-insensitive). Uses % as wildcard.

Example

value: email
ilike: "%@gmail.com" # any Gmail address

not_contains

Inverse of contains for the standard and advanced modes: assert the value does NOT contain the specified content.

The allowed/disallowed mode is NOT inverted. Those list names carry their own polarity, so they mean the same thing here as under contains — every value must be in allowed, none may be in disallowed. Writing it under not_contains is redundant rather than opposite; prefer contains.

Example

value: content
not_contains: "<script>"

regex

Assert the string value matches a regular expression pattern.

Example

value: phone
regex: "^\\+?[1-9]\\d{1,14}$"

is_not_null

Assert the value is not null.

Example

value: user_id
is_not_null: true

is_not_empty

Assert the value is not empty. Checks strings, arrays, and objects.

Example

value: name
is_not_empty: true

is_null

Assert the value is null (when true) or is not null (when false).

Example

value: deleted_at
is_null: true # must be null

value: email
is_null: false # must not be null

is_uuid

Assert the value is a valid UUID string.

Example

value: id
is_uuid: true

is_array

Assert the value is a JSON array.

Example

value: items
is_array: true

is_empty

Assert the value is empty: an empty string, an empty array, an empty object, or null. The inverse of is_not_empty, which existed without it.

Example

value: middle_name
is_empty: true

is_string

Assert the value is a string.

Example

value: user_id
is_string: true

is_number

Assert the value is a number. A numeric string does not satisfy this — use regex if you mean "looks like a number".

Example

value: quantity
is_number: true

is_boolean

Assert the value is a boolean.

Example

value: enabled
is_boolean: true

is_object

Assert the value is an object.

Example

value: address
is_object: true

is_in

Assert the value is one of a fixed set.

This is the opposite direction from contains: contains asks whether the target holds a given item, is_in asks whether the target is a member of a list you supply. Comparison is deep, so objects and arrays can be members.

Example

value: status
is_in: [200, 201, 204]

not_in

Assert the value is not one of a fixed set.

Example

value: role
not_in: ["banned", "deleted"]

is_between

Assert a number — or the size of an array or object — falls within an inclusive range.

Example

value: age
data_type: Number
is_between: { min: 18, max: 120 }

data_type

One of Number, String, Array or Object, case-insensitive — what this value is, so a comparison does not have to guess. Required when ordering a string.

Not the same thing as the DataType on an http or command action, which selects a payload format (text, json, csv, xml).

The ordering operators — is_greater_than and friends — need to know whether they are being asked about a value or a size, and the runtime type cannot tell them: query parameters, form fields, headers and CSV columns all deliver numbers as strings, so "it arrived as a string" does not mean "compare its length".

Declaring the type settles it:

- value: older_than_days     # arrives as "3650" from the query string
data_type: Number # so compare 3650, not the 4 characters
is_less_than: 365

- value: password
data_type: String # so compare how many characters it has
is_greater_than: 7

Accepts Number, String, Array, Object — the same names verify_schema uses. String means the comparison is about length; Array and Object mean how many elements or keys; Number means the value itself.

Required when the value is a string. Ordering a string without this is an error, because the runtime type cannot say whether "3650" means the value 3650 or a length of 4 — query parameters, form fields, headers, CSV columns and NUMERIC/DECIMAL database columns all deliver numbers as text.

Numbers, arrays and objects still infer from their runtime type and need no declaration. Inside verify_schema, an ordering check in a validate block inherits the field's own type: and needs nothing extra.

is_before

Assert the value is strictly before the given moment.

Example

value: expires_at
is_before: now

is_after

Assert the value is strictly after the given moment.

Example

value: created_at
is_after: now-24h

is_on_or_before

Assert the value is before, or the same instant as the given moment.

Example

value: starts_at
is_on_or_before: "2026-12-31"

is_on_or_after

Assert the value is after, or the same instant as the given moment.

Example

value: valid_from
is_on_or_after: "2026-01-01T00:00:00Z"

is_same_time_as

Assert the value is the same instant as the given moment.

Example

value: updated_at
is_same_time_as: a|Fetch->updated_at|

is_not_same_time_as

Assert the value is a different instant from the given moment.

Example

value: modified_at
is_not_same_time_as: a|Original->modified_at|

is_date

Assert the value parses as a date at all, in any of the accepted formats.

Example

value: published_at
is_date: true

not_regex

Assert the string value does NOT match a regular expression. The negated form of regex, which had not_contains, not_starts_with and not_ends_with as counterparts but no negation of its own.

Example

value: comment
not_regex: "(?i)<script"

not_like

SQL LIKE-style pattern that must NOT match (case-sensitive). Uses % as wildcard.

Example

value: email
not_like: "%@example.com"

not_ilike

SQL ILIKE-style pattern that must NOT match (case-insensitive).

Example

value: email
not_ilike: "%@EXAMPLE.com"

is_email

Assert the value parses as an email address.

Example

value: email
is_email: true

is_url

Assert the value parses as an absolute URL with a scheme and a host.

Example

value: callback_url
is_url: true

is_ip

Assert the value parses as an IPv4 or IPv6 address.

Example

value: client_ip
is_ip: true

is_valid_jwt

Validate the value as a JWT token using the provided secret. On success, decoded claims are stored in ok_data under the key specified by result_key (default: jwt_claims).

Example

value: token
is_valid_jwt: "my_jwt_secret" # HS256 secret (bare string), or an object:
# is_valid_jwt: { jwks_url: "...", alg: RS256, iss: "...", aud: "..." }
result_key: user_claims

is_valid_hmac

Verify an HMAC signature. The value field should point to the signature received in the request (e.g. x-hub-signature-256). The assertion recomputes HMAC over body using secret and compares against the target.

Example (GitHub webhook)

value: x-hub-signature-256
is_valid_hmac:
secret: a|env::GITHUB_WEBHOOK_SECRET|
body: a|raw_body|
algorithm: sha256 # sha1 | sha256 | sha512 (default: sha256)
prefix: "sha256=" # stripped from target before comparison

is_valid_totp

Assert the value is a currently-valid RFC 6238 time-based one-time password for the shared secret — the second factor an authenticator app shows.

Fails closed: a target that is not a string (an absent header, a null field) is a failure, never a pass.

Example

- value: body.code
is_valid_totp:
secret: a|secret::totp::user_seed|
skew: 1 # also accept the code from one step either side

is_authorization

Parse an HTTP Authorization header value. Supports Basic (decodes base64 username:password) and Bearer (extracts token). Decoded data is stored in ok_data keyed by scheme name.

Example

value: authorization
is_authorization: true

expression

Evaluate a string expression as a boolean condition. Supports interpolation via a|...| syntax before evaluation.

Example

expression: "a|body::count| > 0"

compare_value

Compare the target value against another value or file for structural differences. Supports JSON, XML, and string comparison with optional field exclusions.

Example - Compare against inline target

compare_value:
target: '{"status": "ok"}'
data_type: json
ignore_fields:
- timestamp

Example - Compare against file

compare_value:
file_path: "/path/to/expected.json"
data_type: json

verify_bcrypt

Verify a plaintext value against a bcrypt hash.

Example

value: password
verify_bcrypt: "$2b$12$LJ3m..."

verify_signature

Verify an Ed25519 signature against the target value.

Example

value: request_body
verify_signature:
public_key: "a1b2c3..." # hex-encoded Ed25519 public key
signature: "d4e5f6..." # hex-encoded signature

verify_schema

Validate the value against a structural schema with recursive type checking and optional per-field assertions. Supports nested objects, arrays, and leaf-level validation via the validate field on each FieldType.

Example - Flat structure

verify_schema:
disallow_unknown_keys: true
structure:
name:
data_type: String
validate:
is_not_empty: true
age:
data_type: Number
validate:
is_greater_than: 0
active:
data_type: Boolean

Example - Nested objects with validation

verify_schema:
structure:
user:
email:
data_type: String
validate:
is_not_empty: true
regex: "^[^@]+@[^@]+\\.[^@]+$"
settings:
theme:
data_type: String
validate:
contains:
allowed:
- "light"
- "dark"
- "system"
notifications:
data_type: Boolean

Example - Array with positional validation

verify_schema:
structure:
- id:
data_type: Number
validate:
is_greater_than: 0
title:
data_type: String
validate:
is_not_empty: true
is_less_than: 256

semver_matches

Assert the string value satisfies a semver version constraint.

Example

value: api_version
semver_matches: ">=1.0.0, <2.0.0"

size_limit

Assert the serialized byte size of the value does not exceed a limit. Accepts human-readable sizes (e.g., 1 MB, 500 KB) or raw byte counts.

Example

value: payload
size_limit: "1 MB"

ContainOptions

Containment check options. Supports three modes depending on the YAML structure provided: standard (single value or array), advanced (with at_least threshold), and any (with allowed/disallowed lists).

Example - Standard single value

contains: "search_term"

Example - Standard array (match at least one)

contains:
- "admin"
- "editor"

Example - Advanced (at least N matches)

contains:
values:
- "read"
- "write"
- "delete"
at_least: 2

Example - Allowed/disallowed lists

contains:
allowed:
- "active"
- "pending"
disallowed:
- "banned"

One of:

  • ContainsAny — Allowed/disallowed list mode. Target must match an allowed value and must not match any disallowed value.
  • ContainsAdv — Advanced mode with explicit value list and minimum match threshold.
  • any — Standard mode: a single value or array of values to check for containment.

ContainsAny

Allowed/disallowed containment check. For strings, checks exact match against each list. For arrays, checks that all elements are in allowed and no elements are in disallowed.

Example

contains:
allowed:
- "published"
- "draft"
- "archived"
disallowed:
- "deleted"
- "banned"
FieldTypeDescription
allowedArray<any> (nullable)Values the target is allowed to match.
disallowedArray<any> (nullable)Values the target must not match.

ContainsAdv

Advanced containment check with a minimum match threshold.

Example

contains:
values:
- "read"
- "write"
- "admin"
at_least: 2 # target must match at least 2 of the listed values
FieldTypeDescription
valuesArray<any>Required. List of candidate values to check against.
at_leastnumberRequired. Minimum number of values that must match for the check to pass.

JwtConfig

Configuration for the is_valid_jwt assertion.

Accepts either a bare string (the HS256 shared secret — the original form, still supported) or an object for asymmetric algorithms and OIDC providers:

# HS256 (unchanged):
is_valid_jwt: "my-shared-secret"

# RS256/ES256 with a static PEM public key:
is_valid_jwt:
alg: RS256
public_key: a|ap_var::IDP_PUBLIC_KEY|

# RS256/ES256 verified against a provider's rotating JWKS (Auth0/Clerk/Cognito):
is_valid_jwt:
jwks_url: https://YOUR.auth0.com/.well-known/jwks.json
alg: RS256 # optional; falls back to the token header's alg
iss: https://YOUR.auth0.com/
aud: https://your-api

One of:

  • string — Bare HS256 shared secret (back-compatible form).
  • JwtVerifyConfig — Structured verification config for HS*/RS*/ES*/EdDSA and JWKS.

JwtVerifyConfig

Structured form of [JwtConfig] — a symmetric secret, a static public key, or a JWKS URL, plus optional algorithm and issuer/audience checks.

FieldTypeDescription
secretstring (nullable)HS256/384/512 shared secret. Mutually exclusive with public_key/jwks_url.
public_keystring (nullable)PEM-encoded public key for RS*/ES*/EdDSA verification (no network calls).
jwks_urlstring (nullable)URL of a JWKS document; the signing key is selected by the token's kid. Fetched once and cached (with a short TTL), so provider key rotation is handled.
algstring (nullable)Signature algorithm, e.g. HS256, RS256, ES256, EdDSA. Required for public_key; for jwks_url it defaults to the token header's alg.
issstring (nullable)Expected iss claim. When set, tokens with a different issuer are rejected.
audstring (nullable)Expected aud claim. When set, tokens with a different audience are rejected.

IsValidHmacConfig

FieldTypeDescription
secretstringRequired. HMAC secret key. Supports interpolation: a|env::MY_SECRET|
bodystringRequired. The message to authenticate. Use a|raw_body| for webhook signature verification so the bytes match exactly what the sender signed.
algorithmstring (nullable)Hash algorithm: sha1, sha256 (default), or sha512.
prefixstring (nullable)Optional prefix to strip from the target value before comparing. GitHub uses "sha256=", Stripe uses "v1=".
encodingstring (nullable)How the signature in the target value is encoded: hex (default) or base64. GitHub, Stripe and Slack send hex; Shopify sends standard base64 in X-Shopify-Hmac-Sha256.

IsValidTotpConfig

Configuration for the is_valid_hmac assertion.

FieldTypeDescription
secretstringRequired. The shared secret, base32 by default — the form an authenticator app hands out.
encodingstring (nullable)How secret is written: base32 (default), hex, or ascii.
digitsnumber (nullable)Code length, 6 (default) to 10.
periodnumber (nullable)Seconds per step. Default 30.
algorithmstring (nullable)sha1 (default — what authenticator apps implement), sha256, sha512.
skewnumber (nullable)How many steps either side of now to also accept. Default 1, which absorbs the clock drift and human latency that make a strictly-current-step check reject codes that were…

CompareValue

Value comparison configuration for diffing against an expected value. Supports inline target strings or file paths, with optional field exclusions.

Example - Inline comparison

compare_value:
target: '{"status": "ok", "code": 200}'
data_type: json
ignore_fields:
- timestamp
- request_id

Example - File comparison

compare_value:
file_path: "./fixtures/expected_response.json"
data_type: json

One of:

  • target → string
  • file_path → string

CompareDataType

Type: string — one of: json, xml, string

VerifySignature

Ed25519 signature verification parameters.

Example

value: request_body
verify_signature:
public_key: "a1b2c3d4e5f6..." # hex-encoded Ed25519 public key
signature: "f6e5d4c3b2a1..." # hex-encoded signature bytes
FieldTypeDescription
public_keystringRequired. Hex-encoded Ed25519 public key.
signaturestringRequired. Hex-encoded signature bytes to verify against the target value.

VerifySchema

Schema validation configuration. Validates a JSON value against a recursive type structure with optional per-field assertions and unknown key rejection.

Example - Basic object validation

verify_schema:
disallow_unknown_keys: true
structure:
name:
data_type: String
validate:
is_not_empty: true
email:
data_type: String
validate:
regex: "^[^@]+@[^@]+\\.[^@]+$"
age:
data_type: Number
validate:
is_greater_than: 0
is_less_than: 150

Example - Nested with unknown key rejection

verify_schema:
disallow_unknown_keys: true
structure:
user:
name:
data_type: String
role:
data_type: String
validate:
contains:
allowed:
- "admin"
- "editor"
- "viewer"
metadata:
created_at:
data_type: Number
version:
data_type: String
validate:
semver_matches: ">=1.0.0"

Example - Array of objects (positional)

verify_schema:
structure:
- id:
data_type: Number
validate:
is_greater_than: 0
status:
data_type: String
validate:
is_not_empty: true
settings:
category:
data_type: String
featured:
data_type: Boolean
FieldTypeDescription
disallow_unknown_keysboolean (nullable)When true, any keys present in the value but not defined in the schema are reported as errors. Applies recursively to all nested objects.
structureValueTypeRequired. The expected structure definition. Can be a nested object map, a positional array, or a single leaf field type.

ValueType

Schema value type for recursive structural validation. Represents either a leaf field with a type constraint, a nested object with named fields, or a positional array of typed elements.

Example - Leaf field

email:
data_type: String
validate:
is_not_empty: true

Example - Nested object

user:
name:
data_type: String
settings:
theme:
data_type: String

Example - Positional array

structure:
- name:
data_type: String
id:
data_type: Number

One of:

  • FieldType — Leaf field with type constraint and optional validation.
  • Map<string, ValueType> — Nested object where each key maps to another ValueType.
  • Array<ValueType> — Positional array where each index maps to a ValueType.

FieldType

Leaf field definition within a verify_schema structure. Specifies the expected data type and optional validation assertions that run against the resolved value at this path.

Supported types: String, Number, Boolean, Array, Object, Null, Any.

Example - Type check only

email:
data_type: String

Example - Type check with assertions

rating:
data_type: Number
validate:
is_greater_than_or_equal_to: 0
is_less_than_or_equal_to: 5

Example - String with pattern and length

slug:
data_type: String
validate:
is_not_empty: true
regex: "^[a-z0-9]+(-[a-z0-9]+)*$"
is_less_than: 128

Example - Enum-like string constraint

status:
data_type: String
validate:
contains:
allowed:
- "published"
- "draft"
- "archived"
FieldTypeDescription
data_typestringRequired. Expected data type. One of: String, Number, Boolean, Array, Object, Null, Any. Named data_type to match the assert-level field of the same name, because it…
validateTest (nullable)Optional test assertions to run against the leaf value after the type check passes. Uses the same Test definition as the normal assertion system, giving full access to all… Example ↓

Field examples

validate

Optional test assertions to run against the leaf value after the type check passes. Uses the same Test definition as the normal assertion system, giving full access to all checks (is_equal_to, regex, contains, is_greater_than, etc.).

Example

validate:
is_not_empty: true
regex: "^[a-z0-9-]+$"
is_less_than: 64