curl --request POST \
--url https://galinum.com/api/v1/audiences/check \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"expression": {
"version": 1,
"root": {
"kind": "all",
"children": [
{
"kind": "field",
"field": {
"kind": "trait",
"key": "plan"
},
"op": "eq",
"value": "free"
},
{
"kind": "not",
"child": {
"kind": "event",
"event": "used_csv_export"
}
}
]
}
},
"sampleLimit": 10,
"segment": "<string>",
"version": 2
}
'import requests
url = "https://galinum.com/api/v1/audiences/check"
payload = {
"expression": {
"version": 1,
"root": {
"kind": "all",
"children": [
{
"kind": "field",
"field": {
"kind": "trait",
"key": "plan"
},
"op": "eq",
"value": "free"
},
{
"kind": "not",
"child": {
"kind": "event",
"event": "used_csv_export"
}
}
]
}
},
"sampleLimit": 10,
"segment": "<string>",
"version": 2
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
expression: {
version: 1,
root: {
kind: 'all',
children: [
{kind: 'field', field: {kind: 'trait', key: 'plan'}, op: 'eq', value: 'free'},
{kind: 'not', child: {kind: 'event', event: 'used_csv_export'}}
]
}
},
sampleLimit: 10,
segment: '<string>',
version: 2
})
};
fetch('https://galinum.com/api/v1/audiences/check', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://galinum.com/api/v1/audiences/check",
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([
'expression' => [
'version' => 1,
'root' => [
'kind' => 'all',
'children' => [
[
'kind' => 'field',
'field' => [
'kind' => 'trait',
'key' => 'plan'
],
'op' => 'eq',
'value' => 'free'
],
[
'kind' => 'not',
'child' => [
'kind' => 'event',
'event' => 'used_csv_export'
]
]
]
]
],
'sampleLimit' => 10,
'segment' => '<string>',
'version' => 2
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://galinum.com/api/v1/audiences/check"
payload := strings.NewReader("{\n \"expression\": {\n \"version\": 1,\n \"root\": {\n \"kind\": \"all\",\n \"children\": [\n {\n \"kind\": \"field\",\n \"field\": {\n \"kind\": \"trait\",\n \"key\": \"plan\"\n },\n \"op\": \"eq\",\n \"value\": \"free\"\n },\n {\n \"kind\": \"not\",\n \"child\": {\n \"kind\": \"event\",\n \"event\": \"used_csv_export\"\n }\n }\n ]\n }\n },\n \"sampleLimit\": 10,\n \"segment\": \"<string>\",\n \"version\": 2\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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))
}HttpResponse<String> response = Unirest.post("https://galinum.com/api/v1/audiences/check")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"expression\": {\n \"version\": 1,\n \"root\": {\n \"kind\": \"all\",\n \"children\": [\n {\n \"kind\": \"field\",\n \"field\": {\n \"kind\": \"trait\",\n \"key\": \"plan\"\n },\n \"op\": \"eq\",\n \"value\": \"free\"\n },\n {\n \"kind\": \"not\",\n \"child\": {\n \"kind\": \"event\",\n \"event\": \"used_csv_export\"\n }\n }\n ]\n }\n },\n \"sampleLimit\": 10,\n \"segment\": \"<string>\",\n \"version\": 2\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://galinum.com/api/v1/audiences/check")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"expression\": {\n \"version\": 1,\n \"root\": {\n \"kind\": \"all\",\n \"children\": [\n {\n \"kind\": \"field\",\n \"field\": {\n \"kind\": \"trait\",\n \"key\": \"plan\"\n },\n \"op\": \"eq\",\n \"value\": \"free\"\n },\n {\n \"kind\": \"not\",\n \"child\": {\n \"kind\": \"event\",\n \"event\": \"used_csv_export\"\n }\n }\n ]\n }\n },\n \"sampleLimit\": 10,\n \"segment\": \"<string>\",\n \"version\": 2\n}"
response = http.request(request)
puts response.read_body{
"expression": {
"version": 1,
"root": {
"kind": "all",
"children": [
{
"kind": "field",
"field": {
"kind": "trait",
"key": "plan"
},
"op": "eq",
"value": "free"
},
{
"kind": "not",
"child": {
"kind": "event",
"event": "used_csv_export"
}
}
]
}
},
"expressionHash": "<string>",
"summary": "trait plan is \"free\" and not (performed used_csv_export)",
"diagnostics": [
{
"severity": "error",
"code": "unobserved_event",
"path": "/root/children/1",
"message": "<string>",
"suggestions": [
"<string>"
]
}
],
"evaluatedAt": 123,
"countType": "exact",
"matchedCount": 123,
"totalUsers": 123,
"samples": [
{
"externalUserId": "<string>",
"firstSeenAt": 123,
"lastSeenAt": 123,
"traits": {},
"events": {}
}
],
"segment": {
"id": "<string>",
"key": "<string>",
"version": 123
}
}{
"error": "<string>",
"diagnostics": [
{
"severity": "error",
"code": "unobserved_event",
"path": "/root/children/1",
"message": "<string>",
"suggestions": [
"<string>"
]
}
]
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}Check an audience expression
Validates and evaluates an audience expression against the project’s current users WITHOUT persisting or launching anything. Returns the normalized canonical expression, its stable hash, a derived readable summary, structured diagnostics (stable codes, JSON Pointer paths, bounded typo suggestions), a single evaluatedAt instant, the exact matching-user count, and a bounded sample of matching users. Use it to verify an audience behaves as intended before creating a campaign with it. Invalid expressions return 400 with error diagnostics.
curl --request POST \
--url https://galinum.com/api/v1/audiences/check \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"expression": {
"version": 1,
"root": {
"kind": "all",
"children": [
{
"kind": "field",
"field": {
"kind": "trait",
"key": "plan"
},
"op": "eq",
"value": "free"
},
{
"kind": "not",
"child": {
"kind": "event",
"event": "used_csv_export"
}
}
]
}
},
"sampleLimit": 10,
"segment": "<string>",
"version": 2
}
'import requests
url = "https://galinum.com/api/v1/audiences/check"
payload = {
"expression": {
"version": 1,
"root": {
"kind": "all",
"children": [
{
"kind": "field",
"field": {
"kind": "trait",
"key": "plan"
},
"op": "eq",
"value": "free"
},
{
"kind": "not",
"child": {
"kind": "event",
"event": "used_csv_export"
}
}
]
}
},
"sampleLimit": 10,
"segment": "<string>",
"version": 2
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
expression: {
version: 1,
root: {
kind: 'all',
children: [
{kind: 'field', field: {kind: 'trait', key: 'plan'}, op: 'eq', value: 'free'},
{kind: 'not', child: {kind: 'event', event: 'used_csv_export'}}
]
}
},
sampleLimit: 10,
segment: '<string>',
version: 2
})
};
fetch('https://galinum.com/api/v1/audiences/check', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://galinum.com/api/v1/audiences/check",
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([
'expression' => [
'version' => 1,
'root' => [
'kind' => 'all',
'children' => [
[
'kind' => 'field',
'field' => [
'kind' => 'trait',
'key' => 'plan'
],
'op' => 'eq',
'value' => 'free'
],
[
'kind' => 'not',
'child' => [
'kind' => 'event',
'event' => 'used_csv_export'
]
]
]
]
],
'sampleLimit' => 10,
'segment' => '<string>',
'version' => 2
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://galinum.com/api/v1/audiences/check"
payload := strings.NewReader("{\n \"expression\": {\n \"version\": 1,\n \"root\": {\n \"kind\": \"all\",\n \"children\": [\n {\n \"kind\": \"field\",\n \"field\": {\n \"kind\": \"trait\",\n \"key\": \"plan\"\n },\n \"op\": \"eq\",\n \"value\": \"free\"\n },\n {\n \"kind\": \"not\",\n \"child\": {\n \"kind\": \"event\",\n \"event\": \"used_csv_export\"\n }\n }\n ]\n }\n },\n \"sampleLimit\": 10,\n \"segment\": \"<string>\",\n \"version\": 2\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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))
}HttpResponse<String> response = Unirest.post("https://galinum.com/api/v1/audiences/check")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"expression\": {\n \"version\": 1,\n \"root\": {\n \"kind\": \"all\",\n \"children\": [\n {\n \"kind\": \"field\",\n \"field\": {\n \"kind\": \"trait\",\n \"key\": \"plan\"\n },\n \"op\": \"eq\",\n \"value\": \"free\"\n },\n {\n \"kind\": \"not\",\n \"child\": {\n \"kind\": \"event\",\n \"event\": \"used_csv_export\"\n }\n }\n ]\n }\n },\n \"sampleLimit\": 10,\n \"segment\": \"<string>\",\n \"version\": 2\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://galinum.com/api/v1/audiences/check")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"expression\": {\n \"version\": 1,\n \"root\": {\n \"kind\": \"all\",\n \"children\": [\n {\n \"kind\": \"field\",\n \"field\": {\n \"kind\": \"trait\",\n \"key\": \"plan\"\n },\n \"op\": \"eq\",\n \"value\": \"free\"\n },\n {\n \"kind\": \"not\",\n \"child\": {\n \"kind\": \"event\",\n \"event\": \"used_csv_export\"\n }\n }\n ]\n }\n },\n \"sampleLimit\": 10,\n \"segment\": \"<string>\",\n \"version\": 2\n}"
response = http.request(request)
puts response.read_body{
"expression": {
"version": 1,
"root": {
"kind": "all",
"children": [
{
"kind": "field",
"field": {
"kind": "trait",
"key": "plan"
},
"op": "eq",
"value": "free"
},
{
"kind": "not",
"child": {
"kind": "event",
"event": "used_csv_export"
}
}
]
}
},
"expressionHash": "<string>",
"summary": "trait plan is \"free\" and not (performed used_csv_export)",
"diagnostics": [
{
"severity": "error",
"code": "unobserved_event",
"path": "/root/children/1",
"message": "<string>",
"suggestions": [
"<string>"
]
}
],
"evaluatedAt": 123,
"countType": "exact",
"matchedCount": 123,
"totalUsers": 123,
"samples": [
{
"externalUserId": "<string>",
"firstSeenAt": 123,
"lastSeenAt": 123,
"traits": {},
"events": {}
}
],
"segment": {
"id": "<string>",
"key": "<string>",
"version": 123
}
}{
"error": "<string>",
"diagnostics": [
{
"severity": "error",
"code": "unobserved_event",
"path": "/root/children/1",
"message": "<string>",
"suggestions": [
"<string>"
]
}
]
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}Authorizations
Your project's secret key (pk_…, without the pub segment). Server-side only — never ship it to a browser. Get it from Settings → Projects in the dashboard.
Body
- Option 1
- Option 2
Provide exactly one of expression (inline) or segment (+ optional version) — both run through the identical validator and evaluator.
Versioned, strictly validated audience rule. Example: { "version": 1, "root": { "kind": "all", "children": [ { "kind": "field", "field": { "kind": "trait", "key": "plan" }, "op": "eq", "value": "free" }, { "kind": "not", "child": { "kind": "event", "event": "used_csv_export" } } ] } }
Show child attributes
Show child attributes
{
"version": 1,
"root": {
"kind": "all",
"children": [
{
"kind": "field",
"field": { "kind": "trait", "key": "plan" },
"op": "eq",
"value": "free"
},
{
"kind": "not",
"child": {
"kind": "event",
"event": "used_csv_export"
}
}
]
}
}
Matching-user samples to return (0 to skip samples).
0 <= x <= 25Saved segment to evaluate, by id (seg_…) or machine key. Provide exactly one of expression or segment.
Segment version to evaluate; omitted = current.
x >= 1Response
Check result.
The normalized canonical expression (stable key order, event counts defaulted, membership lists sorted/deduped).
Show child attributes
Show child attributes
{
"version": 1,
"root": {
"kind": "all",
"children": [
{
"kind": "field",
"field": { "kind": "trait", "key": "plan" },
"op": "eq",
"value": "free"
},
{
"kind": "not",
"child": {
"kind": "event",
"event": "used_csv_export"
}
}
]
}
}
sha256 of the canonical serialization — equal hashes mean identical semantics.
Deterministically derived readable summary. Display text, not a parseable format.
"trait plan is \"free\" and not (performed used_csv_export)"
Warnings that don't block: unobserved traits/events (with typo suggestions), zero matches, and similar.
Show child attributes
Show child attributes
The single instant (epoch ms) every relative rule in this evaluation used.
exact Exact number of users currently matching.
Total identified users in the project.
Bounded, context-efficient sample of matching users: lifecycle fields plus only the referenced traits and event aggregates.
Show child attributes
Show child attributes
Present when the evaluated audience came from a saved segment.
Show child attributes
Show child attributes