Rules
Rules are the core of mockd’s request handling. Each rule combines conditions, a response (with optional sequencing), and actions — all in a single, composable unit. Rules are evaluated top-to-bottom by priority; the first rule whose conditions match determines the response.
How Rules Work
Section titled “How Rules Work”When a request arrives, mockd walks the endpoint’s active rules in priority order:
- Evaluate conditions — if the rule has conditions and they don’t all match, skip to the next rule
- Execute actions — if the rule has actions, run them (mutations are visible to subsequent rules)
- Resolve response — if the rule has a response definition, use it and stop evaluating further rules
If no rule matches or no rule defines a response, the endpoint’s default response is returned.
Creating a Rule
Section titled “Creating a Rule”From the endpoint detail page, click Add Rule. Each rule has:
- Name — a descriptive label
- Priority — evaluation order (lower numbers first)
- Active toggle — enable/disable without deleting
- Conditions — when this rule applies (optional — matches all requests if empty)
- Response — what to return, with optional multi-step sequencing
- Actions — server-side logic to execute when matched
Conditions
Section titled “Conditions”Conditions control when a rule fires. All conditions on a rule use AND logic — every condition must match.
Condition Targets
Section titled “Condition Targets”| Target | Key | Description |
|---|---|---|
| Method | — | HTTP method (GET, POST, etc.) |
| Path | — | Request path |
| Header | Header name | Value of a specific request header |
| Query | Parameter name | Value of a query string parameter |
| Body (raw) | — | Raw request body content |
| Body (JSON path) | Dot-notation path | JSON field value (e.g., user.role, items.0.name) |
| Random | — | Probabilistic matching (see below) |
Operators
Section titled “Operators”| Operator | Description |
|---|---|
equals |
Exact string match |
not_equals |
Does not equal |
contains |
Substring match |
not_contains |
Does not contain substring |
matches_regex |
Regular expression match |
exists |
Value is present |
not_exists |
Value is absent |
less_than |
Numeric comparison (also used with random target) |
Random Matching
Section titled “Random Matching”Use the random target with less_than to create probabilistic rules. For example, a condition with target random and value 30 matches ~30% of requests. This is useful for simulating flaky behavior directly within a rule.
Response
Section titled “Response”A rule’s response defines what to return when matched. Each response has one or more steps and a sequence mode.
Single Response
Section titled “Single Response”For a simple conditional response, add a single step:
| Field | Description |
|---|---|
| Status Code | HTTP status (100–599) |
| Body | Response content (supports template variables) |
| Headers | Response headers (key-value pairs) |
| Delay (ms) | Minimum response delay |
| Delay Max (ms) | Maximum delay for random jitter |
Response Sequences
Section titled “Response Sequences”Add multiple steps to cycle through different responses on successive requests. Each step also has a Count field — how many times to return this step before advancing (default: 1).
Sequence Modes
Section titled “Sequence Modes”| Mode | Behavior |
|---|---|
| Loop | After the last step, cycle back to the first |
| Hold Last | After the last step, keep returning it indefinitely |
Click Reset Sequence on a rule to restart its position back to step 0.
Sequence Examples
Section titled “Sequence Examples”Simulate a resource being created then retrieved:
| Step | Status | Body | Count |
|---|---|---|---|
| 1 | 201 | {"id": "abc", "status": "creating"} |
1 |
| 2 | 200 | {"id": "abc", "status": "ready"} |
1 |
Mode: Hold Last — first request gets 201, all subsequent get 200.
Simulate a flaky API:
| Step | Status | Body | Count |
|---|---|---|---|
| 1 | 500 | {"error": "Internal Server Error"} |
2 |
| 2 | 200 | {"data": "success"} |
1 |
Mode: Loop — fails twice, succeeds once, then repeats.
Actions
Section titled “Actions”Actions execute server-side logic when a rule’s conditions match. They run before the response is resolved, so actions can modify the response.
Action Types
Section titled “Action Types”Set Variable
Section titled “Set Variable”Sets a variable for the current request’s response processing. Access with {{vars.name}}.
| Config | Description |
|---|---|
| Name | Variable name |
| Value | Variable value (supports template variables) |
Store Variable
Section titled “Store Variable”Persists a variable in the endpoint’s storage across requests. Access with {{endpoint.name}}.
| Config | Description |
|---|---|
| Name | Variable name |
| Value | Variable value (supports template variables) |
HTTP Request
Section titled “HTTP Request”Makes an outbound HTTP request. Useful for webhooks or callbacks.
| Config | Description |
|---|---|
| URL | Target URL |
| Method | HTTP method (default: GET) |
| Headers | Request headers (JSON object) |
| Forward request headers | Incoming headers to copy onto the outbound request, comma-separated |
| Body | Request body |
| Apply Response | If true, use the HTTP response as the mock response |
Incoming headers are not passed through by default. Only the headers you
name under Forward request headers are copied from the incoming request,
and anything you set under Headers is applied on top. There is one
exception: when you leave Body empty, the incoming body is relayed, and its
Content-Type goes with it unless you set your own.
Credential headers are never passed through. Authorization, Cookie,
Proxy-Authorization, Set-Cookie, X-Api-Key, X-Auth-Token,
X-Access-Token, X-Session-Token and X-CSRF-Token are dropped even if you
list them under Forward request headers. They are also hidden from
templates in HTTP Request, Set Variable and Store Variable actions, so
{{request.header.authorization}} resolves to an empty string there. A
credential someone else sends to your mock is never relayed onward, stored in a
variable, or recorded in the action’s request log. To authenticate against the
destination, set the header yourself under Headers — values you set
explicitly are always sent. A credential in some other, vendor-specific header
can’t be recognised, so don’t forward headers you don’t need.
Private and internal addresses are blocked for security: private IPv4
(10.x, 172.16–31.x, 192.168.x), loopback (127.x), link-local
(169.254.x, including cloud metadata endpoints), CGNAT (100.64–127.x),
0.0.0.0, and IPv6 loopback, unique-local (fc00::/7) and link-local
(fe80::/10). Redirects are followed, but every hop is re-checked against the
same rules, so a redirect cannot be used to reach a blocked address. Redirect
chains are capped at 5 hops. The check applies to the address as written: a
hostname is not resolved first, so a DNS name that points at a private address
is not caught by it.
Action Error Handling
Section titled “Action Error Handling”Each action specifies an error behavior:
| Option | Behavior |
|---|---|
| Continue | If the action fails, proceed with remaining actions |
| Stop | If the action fails, stop executing further actions |
Timeouts
Section titled “Timeouts”- Each action has a 5-second timeout by default
- The entire action pipeline has a 10-second timeout
- If an action times out, processing continues with remaining actions
Rule Limits by Plan
Section titled “Rule Limits by Plan”| Feature | Free | Pro | Business |
|---|---|---|---|
| Rules per endpoint | 3 | 15 | 25 |
All plans support conditions, response steps, and actions within rules.
The rules panel shows how many of the limit an endpoint is using, so you can see the cap before you reach it. At the cap, Add Rule and Duplicate are disabled and the panel links to upgrade options — duplicating a rule counts against the same limit. For a team project the limit comes from the team owner’s plan, not your own.
Exporting and Importing Rules
Section titled “Exporting and Importing Rules”To copy rules between endpoints, use Export in the rules panel header. It downloads the endpoint’s rules as JSON. To load them into another endpoint, click Import there and paste the file’s contents.
Imported rules are added after the endpoint’s existing rules, in the order they were exported. Each import counts against the endpoint’s rule limit and is all-or-nothing: if it would exceed the limit, or if it contains rules with actions on a Free plan, nothing is imported and the panel tells you why.
To move whole endpoints along with their rules, export the endpoints instead — see Exporting and importing endpoints.
Examples
Section titled “Examples”Return different responses based on query params:
A GET /api/users endpoint with two rules:
- Rule: condition
query.status equals active→ return 200 with active users - Rule: condition
query.status equals inactive→ return 200 with inactive users - Default: return 200 with all users
Webhook on POST with conditional response:
A POST /api/orders endpoint with a rule that:
- Condition: method equals POST
- Action: HTTP Request to
https://hooks.example.com/new-orderwith body{"orderId": "{{$uuid}}"} - Response: 201 with
{"id": "{{$uuid}}", "status": "created"}
Simulate auth flow with sequences:
A POST /api/auth/token endpoint with a rule that returns different tokens:
| Step | Status | Body | Count |
|---|---|---|---|
| 1 | 200 | {"token": "valid-token-1", "expiresIn": 3600} |
3 |
| 2 | 401 | {"error": "token_expired"} |
1 |
Mode: Loop — three successful auths, then one expiry, repeating.