Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.markapidown.net/llms.txt

Use this file to discover all available pages before exploring further.

Assertions give you targeted, machine-readable checks that must all pass for a spec execution to be considered successful. Write them in the ## Assertions section of any endpoint spec file and MarkApiDown evaluates them after every request — in local runs, in CI pipelines, and in AI agent workflows. A single failing assertion sets exit code 1, making it straightforward to block merges or deployments on broken contracts.

Where assertions live

Add an ## Assertions section after ## Expected response in your endpoint spec file. Each assertion is a bullet point in the form - <path>: <operator> [value]:
## Assertions

- status: 200
- body.id: exists
- body.role: in [admin, user]
- headers.content-type: contains json
- body.slug: matches ^[a-z]+$
You can have any number of assertions. MarkApiDown evaluates all of them and reports each failure individually so you see the full picture in one run.

## Assertions vs ## Expected response

These two sections serve different purposes and work best together:

## Expected response

A full-body diff against a recorded snapshot. MarkApiDown compares the entire response body and highlights any fields that differ. Ideal for catching unexpected changes across the whole response shape.

## Assertions

Targeted checks on specific fields, headers, or the status code. Each assertion is independent and named, so failures pinpoint exactly which contract was broken — great for CI and contract testing.
Use ## Expected response to document the full shape of the response and catch regressions. Use ## Assertions for the specific invariants that must hold for the endpoint to be considered correct.

Assertion operators

status: <code> — exact status check

Asserts that the HTTP response status code equals the given value exactly.
- status: 200
- status: 201
- status: 204

body.<path>: exists — field presence check

Asserts that the field at <path> is present in the response body (not null and not missing). Use dot-notation or bracket-notation to navigate nested structures.
- body.id: exists
- body.data.token: exists
- body.items[0].id: exists

body.<path>: <value> — exact value check

Asserts that the field at <path> equals the given value exactly. Works for strings, numbers, and booleans.
- body.id: 42
- body.status: active
- body.count: 5
- body.verified: true

body.<path>: in [value1, value2, ...] — membership check

Asserts that the field at <path> is one of the listed values. Useful for validating enum-like fields without pinning to a single value.
- body.role: in [admin, user]
- body.status: in [pending, active, suspended]
- body.priority: in [low, medium, high, critical]

headers.<name>: contains <substring> — header substring check

Asserts that the response header <name> contains the given substring (case-insensitive). Most commonly used to verify Content-Type.
- headers.content-type: contains json
- headers.content-type: contains application/json
- headers.cache-control: contains no-cache
- headers.location: contains /users/

body.<path>: matches <regex> — pattern check

Asserts that the string value at <path> matches the given regular expression. Use this for format validation — slugs, UUIDs, email addresses, and similar patterns.
- body.slug: matches ^[a-z]+$
- body.email: matches ^[^@]+@[^@]+\.[^@]+$
- body.id: matches ^[0-9a-f-]{36}$
- body.createdAt: matches ^\d{4}-\d{2}-\d{2}

Path syntax reference

Navigate the response body using dot-notation for object properties and bracket-notation for array indices. Combine them freely for deeply nested structures.
Path expressionNavigates to
body.idTop-level id field
body.data.tokentoken nested inside data
body.items[0].idid of the first element in items array
body.results[2].user.emailemail inside the third result’s user object

A complete assertions example

The following spec combines multiple assertion operators to validate a user creation endpoint:
## Assertions

- status: 201
- body.id: exists
- body.email: matches ^[^@]+@[^@]+\.[^@]+$
- body.role: in [admin, user]
- body.active: true
- headers.content-type: contains json
- headers.location: contains /users/

Exit codes and CI integration

When one or more assertions fail, mad exec exits with code 1. A successful run exits with code 0. Use this in any CI pipeline to block on contract failures:
mad exec api-docs/apis/users/create-user.md --env=staging
# Exits 0 on pass, 1 on assertion failure

JUnit output for CI dashboards

Pass --output=junit to produce a JUnit XML report that CI platforms (GitHub Actions, GitLab CI, Jenkins, CircleCI) can parse and display as a test results summary:
mad exec api-docs/apis/users/create-user.md \
  --env=staging \
  --output=junit \
  > test-results/create-user.xml
Run all specs in a directory and collect results:
for spec in api-docs/apis/**/*.md; do
  mad exec "$spec" --env=staging --output=junit >> test-results/all.xml
done
Use --output=junit with mad flow as well. Pipeline JUnit output includes one test case per step, so you can see exactly which step in a multi-call flow caused a CI failure without reading through console logs.