Analytics

The Analytics API provides insights and metrics about your loyalty program's performance.

Endpoints

Get Analytics

Retrieve analytics and insights for your loyalty program.

Endpoint: GET /analytics

Query Parameters:

Parameter
Type
Required
Description

startDate

string

No

ISO 8601 date string (default: 30 days ago)

endDate

string

No

ISO 8601 date string (default: now)

metric

string

No

Specific metric to retrieve

Example Request:

curl -X GET "https://api.monterosa.cloud/loyalty/v1/analytics?startDate=2025-09-01&endDate=2025-10-01" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "X-Monterosa-Org-ID: YOUR_ORG_UUID"

Example Response:

{
  "success": true,
  "data": {
    "orgId": "550e8400-e29b-41d4-a716-446655440000",
    "period": {
      "start": "2025-09-05T17:46:13.830Z",
      "end": "2025-10-05T17:46:13.830Z"
    },
    "metrics": {
      "totalTransactions": 1523,
      "byType": {
        "points": 1024,
        "xp": 312,
        "coins": 187
      },
      "totalAmount": {
        "points": 102400,
        "xp": 31200,
        "coins": 18700
      },
      "averagePerTransaction": {
        "points": 100,
        "xp": 100,
        "coins": 100
      },
      "uniqueUsers": 456
    },
    "topCampaigns": [
      {
        "campaignId": "campaign-001",
        "transactions": 823
      },
      {
        "campaignId": "campaign-002",
        "transactions": 456
      },
      {
        "campaignId": "campaign-003",
        "transactions": 244
      }
    ],
    "recentActivity": [
      {
        "transactionId": "txn_59e6dd71-4ac6-4284-8df7-787d575e60b3",
        "userId": "user123",
        "type": "points",
        "amount": 100,
        "createdAt": "2025-10-05T17:33:33.907Z"
      }
    ],
    "generatedAt": "2025-10-05T17:46:14.092Z"
  }
}

Response Fields

Period

The time range for the analytics data:

  • start - Beginning of the analytics period (ISO 8601)

  • end - End of the analytics period (ISO 8601)

Metrics

Aggregated metrics across all transactions:

Field
Description

totalTransactions

Total number of transactions in the period

byType

Breakdown of transaction counts by type (points, xp, coins)

totalAmount

Sum of all amounts by type

averagePerTransaction

Average transaction amount by type

uniqueUsers

Number of unique users with transactions

Top Campaigns

List of campaigns with the most transaction activity (limited to top 5):

  • campaignId - Campaign identifier

  • transactions - Number of transactions for this campaign

Recent Activity

The 10 most recent transactions, including:

  • transactionId - Transaction identifier

  • userId - User identifier

  • type - Transaction type

  • amount - Transaction amount

  • createdAt - Transaction timestamp

Use Cases

Performance Dashboard

Display key metrics on your admin dashboard:

async function loadAnalytics() {
  const response = await fetch('/v1/analytics?startDate=2025-09-01');
  const { data } = await response.json();

  // Display total transactions
  document.getElementById('total-txns').textContent =
    data.metrics.totalTransactions.toLocaleString();

  // Display unique users
  document.getElementById('unique-users').textContent =
    data.metrics.uniqueUsers.toLocaleString();

  // Display points awarded
  document.getElementById('points-awarded').textContent =
    data.metrics.totalAmount.points.toLocaleString();
}

Campaign Performance

Identify your best-performing campaigns:

import requests

response = requests.get(
    'https://api.monterosa.cloud/loyalty/v1/analytics',
    headers={
        'Authorization': f'Bearer {token}',
        'X-Monterosa-Org-ID': org_id
    }
)

analytics = response.json()['data']

print("Top Campaigns:")
for campaign in analytics['topCampaigns']:
    print(f"  {campaign['campaignId']}: {campaign['transactions']} transactions")

User Engagement Tracking

Monitor user engagement over time:

# Get last 7 days
START_DATE=$(date -u -d '7 days ago' +%Y-%m-%d)
END_DATE=$(date -u +%Y-%m-%d)

curl -s "https://api.monterosa.cloud/loyalty/v1/analytics?startDate=$START_DATE&endDate=$END_DATE" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Monterosa-Org-ID: $ORG_ID" | \
  jq '.data.metrics.uniqueUsers'

Transaction Type Analysis

Understand which reward types are most popular:

const response = await fetch('/v1/analytics');
const { data } = await response.json();

const typeData = data.metrics.byType;
const total = typeData.points + typeData.xp + typeData.coins;

console.log('Transaction Distribution:');
console.log(`  Points: ${(typeData.points / total * 100).toFixed(1)}%`);
console.log(`  XP: ${(typeData.xp / total * 100).toFixed(1)}%`);
console.log(`  Coins: ${(typeData.coins / total * 100).toFixed(1)}%`);

Performance Considerations

  • Analytics are calculated in real-time from transaction data

  • Large date ranges may take longer to process

  • Results are limited to 1000 transactions for performance

  • Consider caching analytics data for frequently accessed date ranges

Error Responses

400 Bad Request:

{
  "success": false,
  "error": {
    "message": "Invalid date format"
  }
}

500 Internal Server Error:

{
  "success": false,
  "error": {
    "message": "Failed to get analytics"
  }
}

Best Practices

  1. Date Ranges: Use reasonable date ranges (1-90 days) for optimal performance

  2. Caching: Cache analytics data for 15-30 minutes to reduce API calls

  3. Pagination: For detailed analysis, use the Transactions API with pagination

  4. Trending: Track metrics over time to identify trends

  5. Alerts: Set up alerts for unusual metric changes

  6. Reporting: Export analytics data regularly for long-term analysis


Recent Activity Endpoint

Get a detailed, multi-source activity feed for your organisation's loyalty program. Perfect for powering admin dashboards, activity timelines, and audit logs.

Get Recent Activity

Retrieve recent activities across all loyalty program components.

Endpoint: GET /v1/activity/recent

Query Parameters:

Parameter
Type
Required
Description

limit

number

No

Number of activities to return (default: 50, max: 100)

type

string

No

Filter by activity type (see types below)

userId

string

No

Filter activities for a specific user

cursor

string

No

Pagination cursor for fetching older activities

Activity Types:

  • transaction_created - Points, XP, or coins awarded/deducted

  • campaign_created - New campaign created

  • campaign_activated - Campaign went live

  • segment_created - New user segment created

  • product_created - New reward product added

  • user_tier_upgraded - User moved to a higher tier

  • webhook_triggered - Webhook delivery sent

  • code_redeemed - Individual code redeemed by user

Example Request:

curl -X GET "https://api.monterosa.cloud/loyalty/v1/activity/recent?limit=20&type=transaction_created" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "X-Monterosa-Org-ID: YOUR_ORG_UUID"

Example Response:

{
  "success": true,
  "data": {
    "activities": [
      {
        "activityId": "txn_abc123",
        "type": "transaction_created",
        "timestamp": "2025-10-06T10:30:00Z",
        "data": {
          "userId": "user_123",
          "transactionType": "award",
          "amount": 100,
          "reason": "Poll vote",
          "campaignId": "campaign_xyz",
          "metadata": {}
        },
        "user": {
          "userId": "user_123",
          "name": "John Smith",
          "email": "[email protected]",
          "tier": "gold"
        }
      },
      {
        "activityId": "seg_def456",
        "type": "segment_created",
        "timestamp": "2025-10-06T10:25:00Z",
        "data": {
          "segmentId": "seg_def456",
          "name": "VIP Gold Members",
          "type": "dynamic",
          "estimatedSize": 1250
        },
        "user": null
      },
      {
        "activityId": "txn_ghi789",
        "type": "user_tier_upgraded",
        "timestamp": "2025-10-06T10:20:00Z",
        "data": {
          "userId": "user_456",
          "fromTier": "silver",
          "toTier": "gold"
        },
        "user": {
          "userId": "user_456",
          "name": "Jane Doe",
          "email": "[email protected]",
          "tier": "gold"
        }
      },
      {
        "activityId": "code_jkl012",
        "type": "code_redeemed",
        "timestamp": "2025-10-06T10:15:00Z",
        "data": {
          "code": "WELCOME2025",
          "userId": "user_789",
          "rewardType": "points",
          "rewardValue": 500,
          "campaignId": "campaign_abc"
        },
        "user": {
          "userId": "user_789",
          "name": "Bob Wilson",
          "email": "[email protected]",
          "tier": "silver"
        }
      },
      {
        "activityId": "webhook_mno345",
        "type": "webhook_triggered",
        "timestamp": "2025-10-06T10:10:00Z",
        "data": {
          "eventType": "user.tier_changed",
          "url": "https://example.com/webhooks/loyalty",
          "status": "success",
          "attempts": 1
        },
        "user": null
      }
    ],
    "count": 5,
    "nextCursor": "MjAyNS0xMC0wNlQxMDoxMDowMFo=",
    "filters": {
      "type": "all",
      "userId": null,
      "limit": 20
    }
  }
}

Activity Object Structure

Each activity contains:

Field
Type
Description

activityId

string

Unique identifier for this activity

type

string

Activity type (see types above)

timestamp

string

ISO 8601 timestamp when activity occurred

data

object

Activity-specific data (varies by type)

user

object|null

Enriched user details if activity has userId

User Enrichment

Activities that involve a user automatically include enriched user data:

{
  "user": {
    "userId": "user_123",
    "name": "John Smith",
    "email": "[email protected]",
    "tier": "gold"
  }
}

User details are batch-fetched for performance (up to 100 users per request).

Pagination

Use the nextCursor to fetch older activities:

# First request
curl "https://api.monterosa.cloud/loyalty/v1/activity/recent?limit=50"

# Use nextCursor from response for next page
curl "https://api.monterosa.cloud/loyalty/v1/activity/recent?limit=50&cursor=MjAyNS0xMC0wNlQxMDoxMDowMFo="

The cursor is base64-encoded and represents the timestamp of the last activity in the current page.

Filtering Examples

Get only transactions:

curl "https://api.monterosa.cloud/loyalty/v1/activity/recent?type=transaction_created&limit=50"

Get activity for specific user:

curl "https://api.monterosa.cloud/loyalty/v1/activity/recent?userId=user_123"

Get tier upgrades only:

curl "https://api.monterosa.cloud/loyalty/v1/activity/recent?type=user_tier_upgraded"

Use Cases

1. Admin Activity Dashboard

Display real-time activity across your loyalty program:

async function loadRecentActivity() {
  const response = await fetch('/v1/activity/recent?limit=20');
  const { data } = await response.json();

  const timeline = document.getElementById('activity-timeline');
  data.activities.forEach(activity => {
    const item = document.createElement('div');
    item.className = `activity-item ${activity.type}`;

    // Format based on activity type
    if (activity.type === 'transaction_created') {
      item.innerHTML = `
        <strong>${activity.user.name}</strong>
        earned ${activity.data.amount} ${activity.data.transactionType}
        <time>${formatTime(activity.timestamp)}</time>
      `;
    } else if (activity.type === 'user_tier_upgraded') {
      item.innerHTML = `
        <strong>${activity.user.name}</strong>
        upgraded from ${activity.data.fromTier} to ${activity.data.toTier}
        <time>${formatTime(activity.timestamp)}</time>
      `;
    }

    timeline.appendChild(item);
  });
}

2. User Activity History

Show a user's complete activity history:

async function loadUserActivity(userId) {
  let allActivities = [];
  let cursor = null;

  do {
    const url = `/v1/activity/recent?userId=${userId}&limit=100` +
                (cursor ? `&cursor=${cursor}` : '');
    const response = await fetch(url);
    const { data } = await response.json();

    allActivities.push(...data.activities);
    cursor = data.nextCursor;
  } while (cursor);

  return allActivities;
}

3. Real-time Activity Feed

Create a live-updating activity feed:

class ActivityFeed {
  constructor() {
    this.latestTimestamp = null;
  }

  async loadInitial() {
    const response = await fetch('/v1/activity/recent?limit=20');
    const { data } = await response.json();
    this.latestTimestamp = data.activities[0]?.timestamp;
    this.render(data.activities);
  }

  async poll() {
    const response = await fetch('/v1/activity/recent?limit=20');
    const { data } = await response.json();

    // Filter to only new activities
    const newActivities = data.activities.filter(
      a => a.timestamp > this.latestTimestamp
    );

    if (newActivities.length > 0) {
      this.latestTimestamp = newActivities[0].timestamp;
      this.prependActivities(newActivities);
    }
  }

  startPolling(interval = 10000) {
    setInterval(() => this.poll(), interval);
  }
}

4. Activity Type Statistics

Analyze activity patterns:

import requests
from collections import Counter

def analyze_activity_types(org_id, token):
    response = requests.get(
        'https://api.monterosa.cloud/loyalty/v1/activity/recent?limit=100',
        headers={
            'Authorization': f'Bearer {token}',
            'X-Monterosa-Org-ID': org_id
        }
    )

    activities = response.json()['data']['activities']
    type_counts = Counter(a['type'] for a in activities)

    print("Activity Type Distribution:")
    for activity_type, count in type_counts.most_common():
        print(f"  {activity_type}: {count}")

Performance Considerations

  • Multi-Source Aggregation: Queries 7 different tables (transactions, campaigns, products, segments, webhooks, codes, users)

  • Batch User Lookup: User details fetched in batches of 100 for efficiency

  • Limit Optimization: Keep limit ≤ 50 for fastest response times

  • Caching: Consider caching results for 30-60 seconds for high-traffic dashboards

  • Filtering: Use type and userId filters to reduce query scope

Error Responses

400 Bad Request:

{
  "success": false,
  "error": {
    "message": "Invalid cursor format"
  }
}

500 Internal Server Error:

{
  "success": false,
  "error": {
    "message": "Failed to fetch recent activity"
  }
}

Best Practices

  1. Polling Interval: Poll every 10-30 seconds for real-time feeds

  2. Pagination: Use cursor-based pagination for loading historical data

  3. Type Filtering: Filter by type when you only need specific activities

  4. User Context: Use userId filter for user-specific activity pages

  5. Display Formatting: Format timestamps and activity descriptions for readability

  6. Error Handling: Handle missing user data gracefully (user may be deleted)

Last updated