curl --request POST \
--url https://api.kit.com/v4/subscribers/filter \
--header 'Content-Type: application/json' \
--header 'X-Kit-Api-Key: <api-key>' \
--data '
{
"all": [
{
"type": "opens",
"count_greater_than": 5,
"after": "2024-01-01",
"before": "2024-12-31"
},
{
"type": "clicks",
"count_greater_than": 2,
"after": "2024-01-01",
"before": "2024-12-31",
"any": [
{
"type": "urls",
"urls": [
"kit.com",
"amazon.com"
],
"matching": "contains"
},
{
"type": "broadcasts",
"ids": [
1,
2,
3
]
}
]
},
{
"type": "tags",
"any": [
{
"type": "ids",
"matching": [
123,
456
]
}
]
},
{
"type": "attribution",
"any": [
{
"type": "forms",
"ids": [
789,
1001
]
},
{
"type": "kit_source",
"source_type": "api_subscription",
"source_ids": [
555
],
"source_names": [
"Welcome"
],
"mechanism": "import",
"mechanism_ids": [
9
]
}
]
},
{
"type": "custom_field",
"subscriber_custom_field_id": 42,
"value": "premium",
"comparison": "is"
}
]
}
'require 'uri'
require 'net/http'
url = URI("https://api.kit.com/v4/subscribers/filter")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Kit-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"all\": [\n {\n \"type\": \"opens\",\n \"count_greater_than\": 5,\n \"after\": \"2024-01-01\",\n \"before\": \"2024-12-31\"\n },\n {\n \"type\": \"clicks\",\n \"count_greater_than\": 2,\n \"after\": \"2024-01-01\",\n \"before\": \"2024-12-31\",\n \"any\": [\n {\n \"type\": \"urls\",\n \"urls\": [\n \"kit.com\",\n \"amazon.com\"\n ],\n \"matching\": \"contains\"\n },\n {\n \"type\": \"broadcasts\",\n \"ids\": [\n 1,\n 2,\n 3\n ]\n }\n ]\n },\n {\n \"type\": \"tags\",\n \"any\": [\n {\n \"type\": \"ids\",\n \"matching\": [\n 123,\n 456\n ]\n }\n ]\n },\n {\n \"type\": \"attribution\",\n \"any\": [\n {\n \"type\": \"forms\",\n \"ids\": [\n 789,\n 1001\n ]\n },\n {\n \"type\": \"kit_source\",\n \"source_type\": \"api_subscription\",\n \"source_ids\": [\n 555\n ],\n \"source_names\": [\n \"Welcome\"\n ],\n \"mechanism\": \"import\",\n \"mechanism_ids\": [\n 9\n ]\n }\n ]\n },\n {\n \"type\": \"custom_field\",\n \"subscriber_custom_field_id\": 42,\n \"value\": \"premium\",\n \"comparison\": \"is\"\n }\n ]\n}"
response = http.request(request)
puts response.read_bodyconst options = {
method: 'POST',
headers: {'X-Kit-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
all: [
{
type: 'opens',
count_greater_than: 5,
after: '2024-01-01',
before: '2024-12-31'
},
{
type: 'clicks',
count_greater_than: 2,
after: '2024-01-01',
before: '2024-12-31',
any: [
{type: 'urls', urls: ['kit.com', 'amazon.com'], matching: 'contains'},
{type: 'broadcasts', ids: [1, 2, 3]}
]
},
{type: 'tags', any: [{type: 'ids', matching: [123, 456]}]},
{
type: 'attribution',
any: [
{type: 'forms', ids: [789, 1001]},
{
type: 'kit_source',
source_type: 'api_subscription',
source_ids: [555],
source_names: ['Welcome'],
mechanism: 'import',
mechanism_ids: [9]
}
]
},
{
type: 'custom_field',
subscriber_custom_field_id: 42,
value: 'premium',
comparison: 'is'
}
]
})
};
fetch('https://api.kit.com/v4/subscribers/filter', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kit.com/v4/subscribers/filter"
payload := strings.NewReader("{\n \"all\": [\n {\n \"type\": \"opens\",\n \"count_greater_than\": 5,\n \"after\": \"2024-01-01\",\n \"before\": \"2024-12-31\"\n },\n {\n \"type\": \"clicks\",\n \"count_greater_than\": 2,\n \"after\": \"2024-01-01\",\n \"before\": \"2024-12-31\",\n \"any\": [\n {\n \"type\": \"urls\",\n \"urls\": [\n \"kit.com\",\n \"amazon.com\"\n ],\n \"matching\": \"contains\"\n },\n {\n \"type\": \"broadcasts\",\n \"ids\": [\n 1,\n 2,\n 3\n ]\n }\n ]\n },\n {\n \"type\": \"tags\",\n \"any\": [\n {\n \"type\": \"ids\",\n \"matching\": [\n 123,\n 456\n ]\n }\n ]\n },\n {\n \"type\": \"attribution\",\n \"any\": [\n {\n \"type\": \"forms\",\n \"ids\": [\n 789,\n 1001\n ]\n },\n {\n \"type\": \"kit_source\",\n \"source_type\": \"api_subscription\",\n \"source_ids\": [\n 555\n ],\n \"source_names\": [\n \"Welcome\"\n ],\n \"mechanism\": \"import\",\n \"mechanism_ids\": [\n 9\n ]\n }\n ]\n },\n {\n \"type\": \"custom_field\",\n \"subscriber_custom_field_id\": 42,\n \"value\": \"premium\",\n \"comparison\": \"is\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Kit-Api-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kit.com/v4/subscribers/filter",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'all' => [
[
'type' => 'opens',
'count_greater_than' => 5,
'after' => '2024-01-01',
'before' => '2024-12-31'
],
[
'type' => 'clicks',
'count_greater_than' => 2,
'after' => '2024-01-01',
'before' => '2024-12-31',
'any' => [
[
'type' => 'urls',
'urls' => [
'kit.com',
'amazon.com'
],
'matching' => 'contains'
],
[
'type' => 'broadcasts',
'ids' => [
1,
2,
3
]
]
]
],
[
'type' => 'tags',
'any' => [
[
'type' => 'ids',
'matching' => [
123,
456
]
]
]
],
[
'type' => 'attribution',
'any' => [
[
'type' => 'forms',
'ids' => [
789,
1001
]
],
[
'type' => 'kit_source',
'source_type' => 'api_subscription',
'source_ids' => [
555
],
'source_names' => [
'Welcome'
],
'mechanism' => 'import',
'mechanism_ids' => [
9
]
]
]
],
[
'type' => 'custom_field',
'subscriber_custom_field_id' => 42,
'value' => 'premium',
'comparison' => 'is'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Kit-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}import requests
url = "https://api.kit.com/v4/subscribers/filter"
payload = { "all": [
{
"type": "opens",
"count_greater_than": 5,
"after": "2024-01-01",
"before": "2024-12-31"
},
{
"type": "clicks",
"count_greater_than": 2,
"after": "2024-01-01",
"before": "2024-12-31",
"any": [
{
"type": "urls",
"urls": ["kit.com", "amazon.com"],
"matching": "contains"
},
{
"type": "broadcasts",
"ids": [1, 2, 3]
}
]
},
{
"type": "tags",
"any": [
{
"type": "ids",
"matching": [123, 456]
}
]
},
{
"type": "attribution",
"any": [
{
"type": "forms",
"ids": [789, 1001]
},
{
"type": "kit_source",
"source_type": "api_subscription",
"source_ids": [555],
"source_names": ["Welcome"],
"mechanism": "import",
"mechanism_ids": [9]
}
]
},
{
"type": "custom_field",
"subscriber_custom_field_id": 42,
"value": "premium",
"comparison": "is"
}
] }
headers = {
"X-Kit-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"subscribers": [
{
"id": "456",
"first_name": "Jane",
"email_address": "jane@example.com",
"created_at": "2024-12-01T15:45:00Z",
"tag_names": [
"newsletter",
"engaged"
],
"tag_ids": [
"123",
"456"
]
},
{
"id": "789",
"first_name": null,
"email_address": "anonymous@example.com",
"created_at": "2024-11-15T10:00:00Z",
"tag_names": [],
"tag_ids": []
}
],
"pagination": {
"has_previous_page": false,
"has_next_page": true,
"start_cursor": "WzQ1Nl0=",
"end_cursor": "Wzc4OV0=",
"per_page": 10,
"total_count": 42
}
}{
"errors": [
"The access token is invalid"
]
}Filter subscribers by engagement, sign-up date, state, and tags
Searches your subscriber list with compound conditions: email engagement (opens, clicks, sends, deliveries — with count thresholds and date ranges), sign-up date, subscriber state, and tags. Every condition in the all array must match (AND logic).
Use counting_mode to control how engagement thresholds are tallied — raw (default) counts every event, unique_email counts distinct emails — and the include array to embed extra fields (tags, stats, custom fields, location, attribution, canceled_at) on each returned subscriber.
Data retention: Starting October 15, 2026, email stats (opens, clicks, sends, bounces, and unsubscribes) are available via the API for the last 5 years — engagement-condition date bounds are clamped to that window, and a stats include range outside it returns a 400 error. See Email data retention for the full policy.
curl --request POST \
--url https://api.kit.com/v4/subscribers/filter \
--header 'Content-Type: application/json' \
--header 'X-Kit-Api-Key: <api-key>' \
--data '
{
"all": [
{
"type": "opens",
"count_greater_than": 5,
"after": "2024-01-01",
"before": "2024-12-31"
},
{
"type": "clicks",
"count_greater_than": 2,
"after": "2024-01-01",
"before": "2024-12-31",
"any": [
{
"type": "urls",
"urls": [
"kit.com",
"amazon.com"
],
"matching": "contains"
},
{
"type": "broadcasts",
"ids": [
1,
2,
3
]
}
]
},
{
"type": "tags",
"any": [
{
"type": "ids",
"matching": [
123,
456
]
}
]
},
{
"type": "attribution",
"any": [
{
"type": "forms",
"ids": [
789,
1001
]
},
{
"type": "kit_source",
"source_type": "api_subscription",
"source_ids": [
555
],
"source_names": [
"Welcome"
],
"mechanism": "import",
"mechanism_ids": [
9
]
}
]
},
{
"type": "custom_field",
"subscriber_custom_field_id": 42,
"value": "premium",
"comparison": "is"
}
]
}
'require 'uri'
require 'net/http'
url = URI("https://api.kit.com/v4/subscribers/filter")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Kit-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"all\": [\n {\n \"type\": \"opens\",\n \"count_greater_than\": 5,\n \"after\": \"2024-01-01\",\n \"before\": \"2024-12-31\"\n },\n {\n \"type\": \"clicks\",\n \"count_greater_than\": 2,\n \"after\": \"2024-01-01\",\n \"before\": \"2024-12-31\",\n \"any\": [\n {\n \"type\": \"urls\",\n \"urls\": [\n \"kit.com\",\n \"amazon.com\"\n ],\n \"matching\": \"contains\"\n },\n {\n \"type\": \"broadcasts\",\n \"ids\": [\n 1,\n 2,\n 3\n ]\n }\n ]\n },\n {\n \"type\": \"tags\",\n \"any\": [\n {\n \"type\": \"ids\",\n \"matching\": [\n 123,\n 456\n ]\n }\n ]\n },\n {\n \"type\": \"attribution\",\n \"any\": [\n {\n \"type\": \"forms\",\n \"ids\": [\n 789,\n 1001\n ]\n },\n {\n \"type\": \"kit_source\",\n \"source_type\": \"api_subscription\",\n \"source_ids\": [\n 555\n ],\n \"source_names\": [\n \"Welcome\"\n ],\n \"mechanism\": \"import\",\n \"mechanism_ids\": [\n 9\n ]\n }\n ]\n },\n {\n \"type\": \"custom_field\",\n \"subscriber_custom_field_id\": 42,\n \"value\": \"premium\",\n \"comparison\": \"is\"\n }\n ]\n}"
response = http.request(request)
puts response.read_bodyconst options = {
method: 'POST',
headers: {'X-Kit-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
all: [
{
type: 'opens',
count_greater_than: 5,
after: '2024-01-01',
before: '2024-12-31'
},
{
type: 'clicks',
count_greater_than: 2,
after: '2024-01-01',
before: '2024-12-31',
any: [
{type: 'urls', urls: ['kit.com', 'amazon.com'], matching: 'contains'},
{type: 'broadcasts', ids: [1, 2, 3]}
]
},
{type: 'tags', any: [{type: 'ids', matching: [123, 456]}]},
{
type: 'attribution',
any: [
{type: 'forms', ids: [789, 1001]},
{
type: 'kit_source',
source_type: 'api_subscription',
source_ids: [555],
source_names: ['Welcome'],
mechanism: 'import',
mechanism_ids: [9]
}
]
},
{
type: 'custom_field',
subscriber_custom_field_id: 42,
value: 'premium',
comparison: 'is'
}
]
})
};
fetch('https://api.kit.com/v4/subscribers/filter', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kit.com/v4/subscribers/filter"
payload := strings.NewReader("{\n \"all\": [\n {\n \"type\": \"opens\",\n \"count_greater_than\": 5,\n \"after\": \"2024-01-01\",\n \"before\": \"2024-12-31\"\n },\n {\n \"type\": \"clicks\",\n \"count_greater_than\": 2,\n \"after\": \"2024-01-01\",\n \"before\": \"2024-12-31\",\n \"any\": [\n {\n \"type\": \"urls\",\n \"urls\": [\n \"kit.com\",\n \"amazon.com\"\n ],\n \"matching\": \"contains\"\n },\n {\n \"type\": \"broadcasts\",\n \"ids\": [\n 1,\n 2,\n 3\n ]\n }\n ]\n },\n {\n \"type\": \"tags\",\n \"any\": [\n {\n \"type\": \"ids\",\n \"matching\": [\n 123,\n 456\n ]\n }\n ]\n },\n {\n \"type\": \"attribution\",\n \"any\": [\n {\n \"type\": \"forms\",\n \"ids\": [\n 789,\n 1001\n ]\n },\n {\n \"type\": \"kit_source\",\n \"source_type\": \"api_subscription\",\n \"source_ids\": [\n 555\n ],\n \"source_names\": [\n \"Welcome\"\n ],\n \"mechanism\": \"import\",\n \"mechanism_ids\": [\n 9\n ]\n }\n ]\n },\n {\n \"type\": \"custom_field\",\n \"subscriber_custom_field_id\": 42,\n \"value\": \"premium\",\n \"comparison\": \"is\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Kit-Api-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kit.com/v4/subscribers/filter",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'all' => [
[
'type' => 'opens',
'count_greater_than' => 5,
'after' => '2024-01-01',
'before' => '2024-12-31'
],
[
'type' => 'clicks',
'count_greater_than' => 2,
'after' => '2024-01-01',
'before' => '2024-12-31',
'any' => [
[
'type' => 'urls',
'urls' => [
'kit.com',
'amazon.com'
],
'matching' => 'contains'
],
[
'type' => 'broadcasts',
'ids' => [
1,
2,
3
]
]
]
],
[
'type' => 'tags',
'any' => [
[
'type' => 'ids',
'matching' => [
123,
456
]
]
]
],
[
'type' => 'attribution',
'any' => [
[
'type' => 'forms',
'ids' => [
789,
1001
]
],
[
'type' => 'kit_source',
'source_type' => 'api_subscription',
'source_ids' => [
555
],
'source_names' => [
'Welcome'
],
'mechanism' => 'import',
'mechanism_ids' => [
9
]
]
]
],
[
'type' => 'custom_field',
'subscriber_custom_field_id' => 42,
'value' => 'premium',
'comparison' => 'is'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Kit-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}import requests
url = "https://api.kit.com/v4/subscribers/filter"
payload = { "all": [
{
"type": "opens",
"count_greater_than": 5,
"after": "2024-01-01",
"before": "2024-12-31"
},
{
"type": "clicks",
"count_greater_than": 2,
"after": "2024-01-01",
"before": "2024-12-31",
"any": [
{
"type": "urls",
"urls": ["kit.com", "amazon.com"],
"matching": "contains"
},
{
"type": "broadcasts",
"ids": [1, 2, 3]
}
]
},
{
"type": "tags",
"any": [
{
"type": "ids",
"matching": [123, 456]
}
]
},
{
"type": "attribution",
"any": [
{
"type": "forms",
"ids": [789, 1001]
},
{
"type": "kit_source",
"source_type": "api_subscription",
"source_ids": [555],
"source_names": ["Welcome"],
"mechanism": "import",
"mechanism_ids": [9]
}
]
},
{
"type": "custom_field",
"subscriber_custom_field_id": 42,
"value": "premium",
"comparison": "is"
}
] }
headers = {
"X-Kit-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"subscribers": [
{
"id": "456",
"first_name": "Jane",
"email_address": "jane@example.com",
"created_at": "2024-12-01T15:45:00Z",
"tag_names": [
"newsletter",
"engaged"
],
"tag_ids": [
"123",
"456"
]
},
{
"id": "789",
"first_name": null,
"email_address": "anonymous@example.com",
"created_at": "2024-11-15T10:00:00Z",
"tag_names": [],
"tag_ids": []
}
],
"pagination": {
"has_previous_page": false,
"has_next_page": true,
"start_cursor": "WzQ1Nl0=",
"end_cursor": "Wzc4OV0=",
"per_page": 10,
"total_count": 42
}
}{
"errors": [
"The access token is invalid"
]
}Authorizations
Authenticate API requests via an API Key
Body
Filter subscribers based on engagement and subscription criteria using the 'all' array with filter conditions that must all be met (AND logic).
Array of filter conditions where ALL must be met (AND logic)
Show child attributes
Show child attributes
Controls how engagement-filter count thresholds are tallied. raw (default) counts every event — five opens of the same email = five. unique_email counts distinct emails on which the action occurred — five opens of the same email = one. Applies to every engagement filter (opens, clicks, sent, delivered) in the request; ignored for other filter types.
raw, unique_email Optional. Array of { type, ...config } objects naming additional fields to embed on each subscriber row. Valid types: attribution, tags, location, canceled_at, stats, custom_fields. The stats type accepts an optional range: { start, end } (YYYY-MM-DD dates, defaulting to the last 90 days). The custom_fields type adds a fields object with all account custom field values (null for fields the subscriber has not set).
Show child attributes
Show child attributes
[
{ "type": "tags" },
{
"type": "stats",
"range": {
"start": "2026-05-01",
"end": "2026-06-30"
}
}
]
Was this page helpful?