Skip to main content

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

  • Secret key required

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

  • Secret key required

Query Parameters

ParameterTypeDescription
includestringRelations 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

  • Secret key required

Path Parameters

ParameterTypeDescription
audienceIdstringThe audience ID

Query Parameters

ParameterTypeDescription
includestringRelations 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

StatusErrorDescription
404Audience not foundAudience ID does not exist

Update Audience

Update an existing audience. PUT /api/v1/audiences/:audienceId

Authentication

  • Secret key required

Path Parameters

ParameterTypeDescription
audienceIdstringThe 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

  • Secret key required

Path Parameters

ParameterTypeDescription
audienceIdstringThe 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

  • Secret key required

Path Parameters

ParameterTypeDescription
audienceIdstringThe audience ID

Query Parameters

ParameterTypeDefaultDescription
firstnumber20Number of items per page (max 100)
afterstring-Cursor for forward pagination
searchstring-Search by email, phone, or name
includestring-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

  • Secret key required

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

  • Secret key required

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

  • Secret key required

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

  • Secret key required

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

StatusErrorDescription
400Audience is not a synced listOnly synced lists can be synced
400Audience has no sync sourceNo external source configured
409Sync already in progressWait 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

ParameterTypeDescription
firstnumberPage size
afterstringPagination cursor
searchstringSearch term
audienceIdstringFilter 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

FieldTypeDescription
emailstringConsumer email address
phonestringConsumer phone number
fullNamestringConsumer full name
totalOrdersnumberLifetime order count
totalOrderValuecurrencyLifetime order value
lastOrderAtdatetimeMost recent order date
createdAtdatetimeConsumer creation date
externalIdstringExternal system ID
metadata.*anyCustom 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);