Skip to content

REST API Full Closed Beta

The loyalty egress REST API lets your backend query loyalty data on demand. Fetch action histories, point totals, or check your channel's egress configuration — all authenticated with an API key.

Closed Beta

The REST API is in Closed Beta. Endpoints, request parameters, and response shapes described here are subject to change. Contact us for access.

Authentication

All egress endpoints require an API key with the loyalty:read permission. Pass the key in the x-api-key header:

bash
curl -H "x-api-key: your_api_key_here" \
  https://api.fanfest.vip/egress/loyalty/actions

API keys are created in the API Keys section of your channel admin panel. When creating a key, ensure the loyalty:read permission is included.

If the API key is missing, invalid, or lacks the required permission, the API returns:

json
// 401 Unauthorized — missing or invalid API key
{
  "error": "Unauthorized"
}

// 403 Forbidden — valid key but missing permission
{
  "error": "Missing required permission: loyalty:read"
}

Rate Limiting

All egress endpoints are rate-limited to 100 requests per minute per API key. Rate limits are tracked using your API key's fingerprint (not the raw key value).

When you exceed the rate limit, the API returns a 429 Too Many Requests response with a Retry-After header:

http
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json

{
  "error": "Rate limit exceeded"
}

The Retry-After header indicates the number of seconds to wait before retrying (always 60, corresponding to the per-minute window).

TIP

If you need higher rate limits for your use case, contact us to discuss options.

Endpoints

GET /egress/loyalty/actions

Query loyalty actions for your channel. Returns paginated results in the format determined by your channel's resolution mode.

Query Parameters:

ParameterTypeRequiredDefaultDescription
user_idstringNoFilter actions by user ID
app_action_namestringNoFilter by action type (e.g., quiz_answer, poll_vote)
from_dateISO 8601 datetimeNoStart of date range filter
to_dateISO 8601 datetimeNoEnd of date range filter
pageintegerNo0Page number (zero-indexed)
limitintegerNo50Results per page (max: 100)

Example Request:

bash
curl -H "x-api-key: your_api_key_here" \
  "https://api.fanfest.vip/egress/loyalty/actions?user_id=usr_xyz789&limit=10"

Example Response (aggregated mode):

json
{
  "data": [
    {
      "resolution": "aggregated",
      "channel_id": "ch_abc123",
      "user_id": "usr_xyz789",
      "app_action_name": "quiz_answer",
      "total_points": 1250,
      "total_occurrences": 47,
      "community_ids": [],
      "timestamp": "2025-06-15T14:32:00.000Z"
    },
    {
      "resolution": "aggregated",
      "channel_id": "ch_abc123",
      "user_id": "usr_xyz789",
      "app_action_name": "poll_vote",
      "total_points": 300,
      "total_occurrences": 15,
      "community_ids": [],
      "timestamp": "2025-06-15T14:32:00.000Z"
    }
  ],
  "total": 2
}

INFO

In aggregated and day aggregated modes, results are grouped by user_id and app_action_name. The community_ids field returns an empty array for grouped results — community data is only available in high fidelity mode. See Resolution Modes for details.

GET /egress/loyalty/points

Get the total loyalty points for a specific user in your channel. Returns the sum of all settled point transactions.

Query Parameters:

ParameterTypeRequiredDescription
user_idstringYesThe user ID to query points for

Example Request:

bash
curl -H "x-api-key: your_api_key_here" \
  "https://api.fanfest.vip/egress/loyalty/points?user_id=usr_xyz789"

Example Response:

json
{
  "user_id": "usr_xyz789",
  "channel_id": "ch_abc123",
  "total_points": 1550
}

The total_points value includes only settled transactions. Transactions that are on hold (e.g., pending moderation) are excluded.

GET /egress/loyalty/config

Check your channel's egress configuration status. Useful for verifying that the integration is set up correctly.

Query Parameters: None.

Example Request:

bash
curl -H "x-api-key: your_api_key_here" \
  "https://api.fanfest.vip/egress/loyalty/config"

Example Response (configured):

json
{
  "configured": true,
  "resolution_mode": "aggregated",
  "is_enabled": true,
  "active_webhook_count": 2
}

Example Response (not configured):

json
{
  "configured": false
}

INFO

This endpoint never exposes webhook secrets or URLs. It only returns whether the configuration exists, the resolution mode, enabled status, and the count of active webhooks.

Error Responses

All endpoints return errors in a consistent format:

Status CodeMeaningDescription
400Bad RequestInvalid or missing query parameters
401UnauthorizedMissing or invalid API key
403ForbiddenValid API key but missing loyalty:read permission
429Too Many RequestsRate limit exceeded (see Retry-After header)
500Internal Server ErrorUnexpected server error

Error response body:

json
{
  "error": "Description of the error"
}

Middleware Chain

For each request, the following middleware runs in order:

  1. API Key Validation — Verifies the JWT-encoded API key is valid and looks up the associated channel
  2. Permission Check — Confirms the API key includes the loyalty:read permission
  3. Rate Limiting — Checks the per-minute request count against the limit (100/min)
  4. Controller — Processes the request and returns the response

If any middleware step fails, the request is rejected and subsequent steps are not executed.

Released under the MIT License.