---
title: "Dry-run endpoint rules against a received email"
method: POST
path: "/endpoints/{id}/rules/test"
tags: ["Endpoints"]
---

# Dry-run endpoint rules against a received email

`POST /endpoints/{id}/rules/test`

## Request

- Base URL: `https://api.primitive.dev/v1`
- URL: `https://api.primitive.dev/v1/endpoints/{id}/rules/test`
- Auth: HTTP bearer

Evaluates the endpoint's filtering rules against an
already-received email WITHOUT delivering anything. The same
shared matcher the live delivery paths use produces the
verdict, so the response explains exactly why a webhook fired
or was suppressed for that message.

When delivery would be suppressed, `rule` names the failing
rule and `reason` carries a human-readable explanation; both
are null when the message matches. `evaluated` echoes the
message metadata the matcher compared (size, attachments, and
the authenticated From identity versus the raw envelope
sender), so a surprising verdict can be traced to its inputs.

Two independent gates are surfaced separately:
`subscribed_to_event` reports the endpoint's event-type
subscription (checked before message matching), and
`rules_valid` reports whether the stored rules blob parsed at
all. Delivery fails OPEN on an invalid blob (the message is
delivered as if unfiltered), so `rules_valid: false` exposes a
misconfiguration that is otherwise silent.

## Headers

- `Idempotency-Key` string

## Request body

- TestEndpointRulesInput
  - `email_id` string, uuid, required: Id of an already-received email (in your org) to evaluate the rules against.

## Response `200`

Rule evaluation verdict

- object
  - `success` true, required
  - `data` TestEndpointRulesResult, required: Verdict of a dry-run rule evaluation. Produced by the same shared matcher the live delivery paths use.
    - `would_deliver` boolean, required: Whether the delivery path would deliver this email to the endpoint.
    - `rule` string, nullable, required: Name of the failing rule when delivery would be suppressed; null when the message matches and the endpoint is subscribed to the event type.
    - `reason` string, nullable, required: Human-readable explanation of the failing rule; null when the message matches.
    - `rules_valid` boolean, required: False when the endpoint's stored rules blob failed validation. Delivery fails OPEN on an invalid blob (delivers as if unfiltered), so false here surfaces a misconfiguration that is otherwise silent.
    - `subscribed_to_event` boolean, required: Whether the endpoint's event-type subscription includes this email's event type. A separate gate applied before message matching, surfaced independently so an unsubscribed endpoint is distinguishable from a rule rejection.
    - `event_type` string, required: The event type this email would be delivered as.
    - `evaluated` object, required: The message metadata the matcher compared, so the caller can see WHAT was evaluated (in particular the authenticated From identity versus the raw envelope sender).
      - `size_bytes` integer, required
      - `has_attachments` boolean, required
      - `attachment_size_bytes` integer, required
      - `sender` string, required: Raw envelope sender the blacklist matches against.
      - `from_address` string, nullable, required: Bare From-header address, when one was present.
      - `sender_authenticated` boolean, required: Whether the sender identity passed authentication (the whitelist matches only authenticated identities).
      - `sender_trust_basis` string, required: Which signal established (or failed to establish) the sender identity.

## Other responses

- `400`: Invalid request parameters
- `401`: Invalid or missing API key
- `404`: Endpoint or email not found. Both the endpoint id (path) and `email_id` (body) must belong to the caller's org; the endpoint must be active (not deleted).

## Changes

> 32 revisions in range; 1 not diffed.

- **2026-11-03** `bce409c97acb`: 93 warning
  - added the new `access_mode_unavailable` enum value to the `error/code` response property for the response status `400`
  - added the new `access_mode_unavailable` enum value to the `error/code` response property for the response status `401`
  - added the new `access_mode_unavailable` enum value to the `error/code` response property for the response status `404`
  - added the new `builtin_role` enum value to the `error/code` response property for the response status `400`
  - …89 more
  - …this revision’s changelog is incomplete
- **2026-10-21** `0360ea8d4f3d`: 39 warning
  - added the new `agent_changed` enum value to the `error/code` response property for the response status `400`
  - added the new `agent_changed` enum value to the `error/code` response property for the response status `401`
  - added the new `agent_changed` enum value to the `error/code` response property for the response status `404`
  - added the new `agent_limit` enum value to the `error/code` response property for the response status `400`
  - …35 more
- …earlier changes not shown

[Operation history](https://skmtc.dev/primitive/apis/primitive-api/changes/endpoints/:id/rules/test/post.md)

---

[API](https://skmtc.dev/primitive/apis/primitive-api.md) - [All operations](https://skmtc.dev/primitive/apis/primitive-api/llms.txt) - [OpenAPI document](https://skmtc.dev/primitive/apis/primitive-api/revisions/bce409c97acb?raw)
