Skip to content
API PlatformDevelopers
POST/v1/contacts/filters/validatebeta

Check a contact filter

Needs
Read your data (mcp:read)
Plan
Any plan with API access
Limits
300 a minute per key
Undo
Nothing to undo: this only reads.

Checks an advanced contact filter without running a search. Answers valid with every problem (issues, each with its path), the filter as it would run (relative dates turned into absolute ones in your workspace's timezone), warnings, and with count: true how many contacts match.

Use it before saving a filter.

Try it

Body

38 / 16,384 bytes as JSON

Limits: at most 8 levels deep, 60 conditions, 500 items per list, 500 characters per value, regex ≤ 200 characters, 16 KB in all. Format, operators and recipes: Filtering contacts.

The advanced filter to check (see **Search contacts**).

A saved contact filter to include.

`true` = also count the matching contacts.

This only reads. It uses your real data and changes nothing.

Code and response

curl -X POST 'https://mcp.wa-api.cloud/v1/contacts/filters/validate' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "filter": {
    "createdAt": {
      "gte": "start_of_month"
    }
  },
  "count": true
}'

The code reads your key from $API_KEY.

Body

Body fields
FieldTypeWhat it is
filterobjectThe advanced filter to check (see Search contacts).
saved_filter_idstring | integerA saved contact filter to include.pattern ^[1-9]\d{0,18}$
countbooleantrue = also count the matching contacts.default false

Headers

Headers
FieldTypeWhat it is
AuthorizationrequiredheaderBearer $API_KEY — your API key.
Api-VersionheaderThe API version to use, e.g. 2026-10-01. Default: the version your key is pinned to.one of: 2026-10-01 · pattern ^\d{4}-\d{2}-\d{2}$

Response 200

Whether the filter is valid, and how it would run.

Response fields
FieldTypeWhat it is
validrequiredboolean
issuesrequiredarray of objectWhy it is not valid (empty when valid).
pathrequiredstring
messagerequiredstring
reasonstringThe refusal class when it has one (filter_too_deep, filter_regex_invalid, saved_filter_not_found, …).
filterrequiredobject or nullYour filter, normalised: what POST /v1/saved-filters would store.
resolved_datesrequiredarray of object
pathrequiredstring
inputrequiredstring
valuerequiredstring
warningsrequiredarray of objectFilter conditions that may not mean what they look like: {path, message}.
pathstring
messagerequiredstring
notesrequiredarray of stringNormalisations applied.
conditionsrequiredinteger-9007199254740991–9007199254740991
depthrequiredinteger-9007199254740991–9007199254740991
saved_filtersrequiredarray of objectSaved filters it uses (applied as part of it).
idrequiredstring
namerequiredstring
timezonerequiredstring or nullTimezone relative dates were resolved in (null when not valid).
countrequiredinteger or null-9007199254740991–9007199254740991
approximaterequiredboolean or null

Errors

Errors are application/problem+json. Branch on code.

StatusCodeWhen
400invalid_input

A field is missing or has the wrong format. errors[] points at each field. The request itself is malformed (e.g. filter is not an object). A filter that breaks the rules is not an error: the answer is valid: false with issues[] (each with path, message and, when it has one, reason).

401unauthenticated

The Authorization header is missing, the key is unknown, expired or revoked.

403entitlement_required

The workspace's plan does not include API access (api_access).

403insufficient_scope

The key does not have the permission this operation needs.

429rate_limited

The key or workspace went over its rate limit. Wait for Retry-After seconds.

502upstream_error

With count: true: the contacts service could not run this filter (reason: filter_failed). Simplify it.

503service_unconfigured

Advanced filters are switched off on this server (reason: advanced_filter_disabled).

503upstream_unavailable

A service behind the API is briefly unavailable. Safe to retry with backoff.

504timeout

With count: true: counting took too long (reason: query_timeout). Narrow the filter.

Examples

Check a filter with a relative date

Request body

{
  "filter": {
    "createdAt": {
      "gte": "start_of_month"
    }
  },
  "count": true
}

Response 200

{
  "valid": true,
  "issues": [],
  "filter": {
    "createdAt": {
      "gte": "2026-08-31T20:00:00.000Z"
    }
  },
  "resolved_dates": [
    {
      "path": "filter.createdAt.gte",
      "input": "start_of_month",
      "value": "2026-08-31T20:00:00.000Z"
    }
  ],
  "warnings": [],
  "notes": [],
  "conditions": 1,
  "depth": 1,
  "saved_filters": [],
  "timezone": "Asia/Dubai",
  "count": 120,
  "approximate": false
}

Operation path

The same operation is also at POST /v1/ops/crm_validate_contact_filter, with every field in the JSON body.