Documentation Index
Fetch the complete documentation index at: https://docs.fanfare.io/llms.txt
Use this file to discover all available pages before exploring further.
Audiences API
Audiences represent groups of consumers that can be targeted for specific experiences. Audiences can be static lists, dynamic rule-based segments, or synced from external sources like Klaviyo.
Create Audience
Create a new audience.
POST /api/v1/audiences
Authentication
Request Body
interface CreateAudienceRequest {
name: string;
description?: string;
type: "STATIC" | "DYNAMIC" | "SYNCED_LIST";
iconName?: string;
metadata?: Record<string, unknown>;
rules?: AudienceRule[];
}
interface AudienceRule {
field: string;
operator:
| "EQUALS"
| "NOT_EQUALS"
| "GREATER_THAN"
| "GREATER_THAN_OR_EQUAL"
| "LESS_THAN"
| "LESS_THAN_OR_EQUAL"
| "CONTAINS"
| "NOT_CONTAINS"
| "IN"
| "NOT_IN";
values: (string | number)[];
groupId?: string;
position?: number;
}
Response
interface Audience {
id: string;
organizationId: string;
name: string;
description: string | null;
type: "STATIC" | "DYNAMIC" | "SYNCED_LIST";
iconName: string | null;
metadata: Record<string, unknown> | null;
version: number;
groupId: string | null;
groupType: string | null;
groupName: string | null;
primarySyncSourceId: string | null;
lastRefreshedAt: string | null;
refreshIntervalSeconds: number | null;
createdAt: string;
updatedAt: string;
rules?: AudienceRule[];
}
Example
curl -X POST https://admin.fanfare.io/api/v1/audiences \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "VIP Customers",
"description": "Customers with 5+ orders",
"type": "DYNAMIC",
"rules": [
{
"field": "totalOrders",
"operator": "GREATER_THAN_OR_EQUAL",
"values": [5]
}
]
}'
Response:
{
"id": "aud_01HXYZ123456789",
"organizationId": "org_01HXYZ123456789",
"name": "VIP Customers",
"description": "Customers with 5+ orders",
"type": "DYNAMIC",
"iconName": null,
"metadata": null,
"version": 1,
"groupId": null,
"groupType": null,
"groupName": null,
"primarySyncSourceId": null,
"lastRefreshedAt": null,
"refreshIntervalSeconds": null,
"createdAt": "2024-12-01T10:00:00Z",
"updatedAt": "2024-12-01T10:00:00Z",
"rules": [
{
"id": "rule_01HXYZ123456789",
"field": "totalOrders",
"operator": "GREATER_THAN_OR_EQUAL",
"values": [5],
"groupId": "grp_01HXYZ123456789",
"position": 0
}
]
}
List Audiences
List all audiences in your organization.
GET /api/v1/audiences
Authentication
Query Parameters
| Parameter | Type | Description |
|---|
include | string | Relations to include (rules, imports, primarySyncSource) |
Example
curl -X GET "https://admin.fanfare.io/api/v1/audiences?include=rules" \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Response:
[
{
"id": "aud_01HXYZ123456789",
"name": "VIP Customers",
"type": "DYNAMIC",
"rules": [...]
},
{
"id": "aud_01HXYZ123456790",
"name": "Newsletter Subscribers",
"type": "SYNCED_LIST"
}
]
Get Audience
Get a single audience by ID.
GET /api/v1/audiences/:audienceId
Authentication
Path Parameters
| Parameter | Type | Description |
|---|
audienceId | string | The audience ID |
Query Parameters
| Parameter | Type | Description |
|---|
include | string | Relations to include (default: rules,imports) |
Example
curl -X GET "https://admin.fanfare.io/api/v1/audiences/aud_01HXYZ123456789?include=rules,primarySyncSource" \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Error Responses
| Status | Error | Description |
|---|
| 404 | Audience not found | Audience ID does not exist |
Update Audience
Update an existing audience.
PUT /api/v1/audiences/:audienceId
Authentication
Path Parameters
| Parameter | Type | Description |
|---|
audienceId | string | The audience ID |
Request Body
interface UpdateAudienceRequest {
name?: string;
description?: string | null;
iconName?: string | null;
metadata?: Record<string, unknown> | null;
lastRefreshedAt?: string;
}
Example
curl -X PUT https://admin.fanfare.io/api/v1/audiences/aud_01HXYZ123456789 \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Premium VIP Customers",
"description": "Top tier customers"
}'
Delete Audience
Delete (archive) an audience.
DELETE /api/v1/audiences/:audienceId
Authentication
Path Parameters
| Parameter | Type | Description |
|---|
audienceId | string | The audience ID |
Example
curl -X DELETE https://admin.fanfare.io/api/v1/audiences/aud_01HXYZ123456789 \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Get Audience Members
Get paginated members (consumers) of an audience.
GET /api/v1/audiences/:audienceId/members
Authentication
Path Parameters
| Parameter | Type | Description |
|---|
audienceId | string | The audience ID |
Query Parameters
| Parameter | Type | Default | Description |
|---|
first | number | 20 | Number of items per page (max 100) |
after | string | - | Cursor for forward pagination |
search | string | - | Search by email, phone, or name |
include | string | - | Relations to include |
Response
interface AudienceMembersResponse {
data: Consumer[];
pageInfo: {
startCursor: string | null;
endCursor: string | null;
};
}
Example
curl -X GET "https://admin.fanfare.io/api/v1/audiences/aud_01HXYZ123456789/members?first=20&search=john" \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Response:
{
"data": [
{
"id": "cons_01HXYZ123456789",
"email": "[email protected]",
"fullName": "John Doe",
"totalOrders": 12,
"totalOrderValue": 2500.0
}
],
"pageInfo": {
"startCursor": "eyJpZCI6ImNvbnMifQ==",
"endCursor": "eyJpZCI6ImNvbnMifQ=="
}
}
Get Audience Status
Get the materialization status of an audience.
GET /api/v1/audiences/:audienceId/status
Authentication
Response
interface AudienceStatus {
audienceId: string;
version: number;
syncStatus: "PENDING" | "SUCCESS" | "FAILED" | null;
lastSyncedAt: string | null;
lastRefreshedAt: string | null;
refreshIntervalSeconds: number | null;
stale: boolean;
inProgress: boolean;
pendingShards: number | null;
}
Example
curl -X GET https://admin.fanfare.io/api/v1/audiences/aud_01HXYZ123456789/status \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Get Audience Count
Get the current member count for an audience.
GET /api/v1/audiences/:audienceId/count
Authentication
Response
interface AudienceCount {
audienceId: string;
count: number;
source: "valkey_alias" | "valkey_staged" | "sync_source" | "db_list" | "unknown";
}
Example
curl -X GET https://admin.fanfare.io/api/v1/audiences/aud_01HXYZ123456789/count \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Response:
{
"audienceId": "aud_01HXYZ123456789",
"count": 15420,
"source": "db_list"
}
Create Audience Import
Create a new audience import to upload members via CSV.
POST /api/v1/audiences/:audienceId/import
Authentication
Response
interface AudienceImportResponse {
id: string;
audienceId: string;
status: "PENDING" | "PROCESSING" | "SUCCESS" | "FAILED";
s3Key: string;
uploadUrl: string; // Pre-signed URL for uploading CSV
createdAt: string;
}
Example
curl -X POST https://admin.fanfare.io/api/v1/audiences/aud_01HXYZ123456789/import \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Response:
{
"id": "imp_01HXYZ123456789",
"audienceId": "aud_01HXYZ123456789",
"status": "PENDING",
"s3Key": "imports/org_01HXYZ/aud_01HXYZ/1701432000000.csv",
"uploadUrl": "https://s3.amazonaws.com/...",
"createdAt": "2024-12-01T12:00:00Z"
}
Then upload your CSV file to the presigned URL:
curl -X PUT "https://s3.amazonaws.com/..." \
-H "Content-Type: text/csv" \
--data-binary @customers.csv
Re-sync Audience
Trigger a re-sync for a synced list audience from its external source.
POST /api/v1/audiences/:audienceId/sync
Authentication
Response
interface SyncResponse {
success: true;
syncSourceId: string;
status: "PENDING";
}
Example
curl -X POST https://admin.fanfare.io/api/v1/audiences/aud_01HXYZ123456789/sync \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Error Responses
| Status | Error | Description |
|---|
| 400 | Audience is not a synced list | Only synced lists can be synced |
| 400 | Audience has no sync source | No external source configured |
| 409 | Sync already in progress | Wait for current sync to finish |
Audience Groups
Get Audiences in Group
Get all audiences in a loyalty tier or segment group.
GET /api/v1/audiences/groups/:groupId
Example
curl -X GET "https://admin.fanfare.io/api/v1/audiences/groups/tier_01HXYZ?include=rules" \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Get Group Members
Get paginated members across all audiences in a group.
GET /api/v1/audiences/groups/:groupId/members
Query Parameters
| Parameter | Type | Description |
|---|
first | number | Page size |
after | string | Pagination cursor |
search | string | Search term |
audienceId | string | Filter to specific audience in group |
Delete Group
Delete all audiences in a group.
DELETE /api/v1/audiences/groups/:groupId
Loyalty Tiers
Create segmented value audiences for loyalty programs.
Create Loyalty Tiers
POST /api/v1/audiences/loyalty-tiers
Request Body
interface CreateLoyaltyTiersRequest {
groupName: string;
attribute: "totalOrderValue" | "totalOrders" | "lifetimeSpend";
tiers: Array<{
name: string;
iconName?: string;
startValue: number;
endValue?: number; // Optional for last tier (unlimited)
order: number;
}>;
}
Example
curl -X POST https://admin.fanfare.io/api/v1/audiences/loyalty-tiers \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"groupName": "Spending Tiers",
"attribute": "totalOrderValue",
"tiers": [
{"name": "Bronze", "startValue": 0, "endValue": 100, "order": 0},
{"name": "Silver", "startValue": 100, "endValue": 500, "order": 1},
{"name": "Gold", "startValue": 500, "endValue": 1000, "order": 2},
{"name": "Platinum", "startValue": 1000, "order": 3}
]
}'
Response:
{
"tierGroup": "tier_01HXYZ123456789",
"audiences": [
{
"id": "aud_01HXYZ123456789",
"name": "Bronze",
"type": "DYNAMIC",
"groupId": "tier_01HXYZ123456789",
"groupType": "SEGMENTED_VALUE",
"metadata": {
"tierGroup": "tier_01HXYZ123456789",
"tierAttribute": "totalOrderValue",
"tierOrder": 0,
"tierBoundaries": {"min": 0, "max": 100}
},
"rules": [...]
},
...
]
}
Update Loyalty Tiers
PUT /api/v1/audiences/loyalty-tiers/:groupId
Updates an existing tier group. New tiers are created, existing tiers are updated, and removed tiers are deleted.
Klaviyo Import
Bulk import Klaviyo lists as synced audiences.
POST /api/v1/audiences/import/klaviyo
Request Body
interface KlaviyoImportRequest {
listIds: string[];
}
Response
interface KlaviyoImportResponse {
imported: Array<{
listId: string;
syncSourceId: string;
status: "PENDING";
}>;
skipped: Array<{
listId: string;
reason: string;
existingAudienceId: string | null;
}>;
}
Example
curl -X POST https://admin.fanfare.io/api/v1/audiences/import/klaviyo \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"listIds": ["YwxYPP", "AbCdEf", "XyZaBc"]
}'
Response:
{
"imported": [
{ "listId": "YwxYPP", "syncSourceId": "sync_01HXYZ", "status": "PENDING" },
{ "listId": "XyZaBc", "syncSourceId": "sync_01HXYZ", "status": "PENDING" }
],
"skipped": [{ "listId": "AbCdEf", "reason": "Already synced", "existingAudienceId": "aud_01HXYZ" }]
}
Audience Rules
Add Rules to Audience
POST /api/v1/audiences/:audienceId/rules
Request Body
type AddRulesRequest = AudienceRule[];
Example
curl -X POST https://admin.fanfare.io/api/v1/audiences/aud_01HXYZ123456789/rules \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '[
{
"field": "totalOrders",
"operator": "GREATER_THAN",
"values": [10]
},
{
"field": "email",
"operator": "CONTAINS",
"values": ["@example.com"]
}
]'
Available Rule Fields
| Field | Type | Description |
|---|
email | string | Consumer email address |
phone | string | Consumer phone number |
fullName | string | Consumer full name |
totalOrders | number | Lifetime order count |
totalOrderValue | currency | Lifetime order value |
lastOrderAt | datetime | Most recent order date |
createdAt | datetime | Consumer creation date |
externalId | string | External system ID |
metadata.* | any | Custom metadata fields |
SDK Usage
import { FanfareAdmin } from "@fanfare/admin-sdk";
const admin = new FanfareAdmin({
secretKey: process.env.FANFARE_SECRET_KEY,
});
// Create dynamic audience
const audience = await admin.audiences.create({
name: "High Value Customers",
type: "DYNAMIC",
rules: [{ field: "totalOrderValue", operator: "GREATER_THAN", values: [1000] }],
});
// List audiences
const audiences = await admin.audiences.list({
include: ["rules"],
});
// Get audience members
const { data: members, pageInfo } = await admin.audiences.getMembers(audience.id, {
first: 50,
search: "john",
});
// Create loyalty tiers
const tiers = await admin.audiences.createLoyaltyTiers({
groupName: "Customer Tiers",
attribute: "totalOrderValue",
tiers: [
{ name: "Bronze", startValue: 0, endValue: 100, order: 0 },
{ name: "Silver", startValue: 100, endValue: 500, order: 1 },
{ name: "Gold", startValue: 500, order: 2 },
],
});
// Import from Klaviyo
const importResult = await admin.audiences.importKlaviyo({
listIds: ["YwxYPP", "AbCdEf"],
});
// Trigger re-sync
await admin.audiences.sync(audience.id);