Third-Party Integration

How to set up third party triggers and actions

This guide explains how external systems (eCommerce platforms, ticketing systems, payment processors, etc.) can send events to trigger loyalty rewards.

Overview

Third-party systems can integrate with the Loyalty API to trigger rewards for user actions that occur outside the main platform, such as:

  • Purchases from eCommerce systems

  • Ticket scans at venues or events

  • App interactions from mobile applications

  • Payment confirmations from payment processors

  • Content consumption from streaming platforms

  • Physical store visits tracked by POS systems

Authentication

All third-party API calls require authentication using API Keys.

Obtaining API Credentials

Contact Monterosa support to receive:

  • API Key: Unique identifier for your integration

  • API Secret: Secret key for authentication

  • Organisation ID: Your organization's UUID

Making Authenticated Requests

Include these headers in all API requests:

POST /api/audience/internal/actions
Authorization: Bearer YOUR_API_SECRET
X-Monterosa-Org-ID: YOUR_ORG_UUID
Content-Type: application/json

Event Ingestion Endpoint

POST /api/audience/internal/actions

Send user actions from your system to trigger loyalty campaigns.

Request Body

{
  "userId": "user_123",
  "action": "purchase_completed",
  "timestamp": "2025-10-06T16:45:00Z",
  "data": {
    "orderId": "ORD-12345",
    "amount": 99.99,
    "currency": "USD",
    "items": [
      {
        "sku": "PRODUCT-001",
        "quantity": 2,
        "price": 49.99
      }
    ]
  },
  "metadata": {
    "source": "shopify",
    "storeId": "store_456"
  }
}

Parameters

Field
Type
Required
Description

userId

string

User's loyalty platform ID

action

string

Event type identifier (see below)

timestamp

string

No

ISO8601 timestamp (defaults to current time)

data

object

No

Event-specific data

metadata

object

No

Additional context information

Response

{
  "eventId": "evt_7f9e2c8a-1234-5678-90ab-cdef12345678",
  "processed": false,
  "message": "Action queued for processing"
}

The event is queued for asynchronous processing. Campaign triggers matching this action will fire automatically.

Event Types (Actions)

Define custom action types for your use case. Recommended naming convention: {category}_{verb}

Common Event Types

eCommerce:

  • purchase_completed - Order completed

  • cart_abandoned - User left items in cart

  • product_reviewed - User left a product review

  • referral_used - Referral code was applied

Ticketing:

  • ticket_purchased - Ticket bought

  • ticket_scanned - Ticket validated at venue

  • event_attended - User checked in to event

  • vip_upgrade - User upgraded to VIP

Content:

  • video_watched - Video completed

  • article_read - Article finished

  • milestone_reached - Achievement unlocked

  • streak_maintained - Daily streak continued

Physical:

  • store_visit - Customer entered store

  • pos_purchase - In-store purchase made

  • loyalty_card_scan - Card scanned at register

Mapping Users

User ID Matching

The userId field must match the user's ID in the loyalty platform. Options:

  1. Direct ID: Use the loyalty platform's user ID directly

  2. External ID Mapping: Map your system's user ID to loyalty platform ID

  3. Email/Phone Lookup: Use email or phone number (requires user schema configuration)

Identity Mapping Example

If your system uses email addresses but the loyalty platform uses UUIDs:

# First, look up the user
GET /api/audience/[email protected]
# Response: { "userId": "550e8400-e29b-41d4-a716-446655440000", ... }

# Then, send the event
POST /api/audience/internal/actions
{
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "action": "purchase_completed",
  ...
}

Configuring Campaign Triggers

Once events are flowing, configure campaigns to respond to them.

Step 1: Create Custom Trigger

Define your custom event type in the campaign system:

{
  "key": "purchase_completed",
  "name": "Purchase Completed",
  "category": "commerce",
  "fields": [
    {
      "key": "amount",
      "type": "number",
      "description": "Purchase amount"
    },
    {
      "key": "currency",
      "type": "string"
    }
  ]
}

Step 2: Create Campaign with Trigger

{
  "name": "Reward Purchases Over $100",
  "triggers": [
    {
      "type": "purchase_completed",
      "conditions": [
        {
          "field": "amount",
          "operator": ">=",
          "value": 100
        }
      ]
    }
  ],
  "effects": [
    {
      "type": "add_points",
      "config": {
        "amount": 500,
        "reason": "Purchase reward"
      }
    },
    {
      "type": "award_product",
      "config": {
        "productId": "prod_vip_badge",
        "reason": "VIP shopper badge"
      }
    }
  ]
}

Now when your system sends a purchase_completed event with amount >= 100, the user receives 500 points and a VIP badge.

Integration Examples

E-Commerce (Shopify Webhook)

// Shopify webhook handler
app.post('/webhooks/shopify/order-created', async (req, res) => {
  const order = req.body;

  // Send to Loyalty API
  await fetch('https://api.monterosa.cloud/loyalty/api/audience/internal/actions', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.LOYALTY_API_SECRET}`,
      'X-Monterosa-Org-ID': process.env.LOYALTY_ORG_ID,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      userId: order.customer.id,
      action: 'purchase_completed',
      timestamp: order.created_at,
      data: {
        orderId: order.id,
        amount: parseFloat(order.total_price),
        currency: order.currency,
        items: order.line_items.map(item => ({
          sku: item.sku,
          quantity: item.quantity,
          price: parseFloat(item.price)
        }))
      },
      metadata: {
        source: 'shopify',
        orderNumber: order.name
      }
    })
  });

  res.status(200).send('OK');
});

Ticketing System (Stadium Entry)

# Ticket scanner at stadium gate
import requests
from datetime import datetime

def scan_ticket(ticket_code, scanner_id):
    # Validate ticket in your system
    ticket = validate_ticket(ticket_code)

    if ticket['valid']:
        # Send event to Loyalty API
        response = requests.post(
            'https://api.monterosa.cloud/loyalty/api/audience/internal/actions',
            headers={
                'Authorization': f'Bearer {LOYALTY_API_SECRET}',
                'X-Monterosa-Org-ID': LOYALTY_ORG_ID,
                'Content-Type': 'application/json'
            },
            json={
                'userId': ticket['user_id'],
                'action': 'ticket_scanned',
                'timestamp': datetime.utcnow().isoformat() + 'Z',
                'data': {
                    'ticketId': ticket['id'],
                    'sectionSeat': ticket['section'],
                    'eventId': ticket['event_id'],
                    'scanner': scanner_id
                },
                'metadata': {
                    'source': 'gate_scanner',
                    'gate': scanner_id
                }
            }
        )

        return response.json()

Mobile App (In-App Purchase)

// iOS App Purchase Handler
func handlePurchaseComplete(transaction: SKPaymentTransaction) {
    let purchaseData: [String: Any] = [
        "userId": UserDefaults.standard.string(forKey: "loyaltyUserId") ?? "",
        "action": "iap_completed",
        "data": [
            "productId": transaction.payment.productIdentifier,
            "transactionId": transaction.transactionIdentifier ?? "",
            "quantity": transaction.payment.quantity
        ],
        "metadata": [
            "source": "ios_app",
            "appVersion": Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
        ]
    ]

    var request = URLRequest(url: URL(string: "https://api.monterosa.cloud/loyalty/api/audience/internal/actions")!)
    request.httpMethod = "POST"
    request.setValue("Bearer \(loyaltyAPISecret)", forHTTPHeaderField: "Authorization")
    request.setValue(loyaltyOrgID, forHTTPHeaderField: "X-Monterosa-Org-ID")
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try? JSONSerialization.data(withJSONObject: purchaseData)

    URLSession.shared.dataTask(with: request) { data, response, error in
        // Handle response
    }.resume()
}

Best Practices

Event Naming

  • Be consistent: Use a naming convention like {domain}_{action}

  • Be specific: purchase_completed is better than purchase

  • Avoid duplicates: Use the same event name across all systems

Data Structure

  • Include context: Send relevant data that campaigns might filter on

  • Be flat: Avoid deeply nested structures when possible

  • Use standards: ISO8601 for dates, ISO currency codes, etc.

Error Handling

  • Implement retries: Network failures can happen

  • Log failures: Track which events didn't send

  • Use idempotency: Include unique identifiers to prevent duplicate processing

Performance

  • Queue events: Don't block user experience waiting for API calls

  • Batch when possible: If sending many events, batch them

  • Handle rate limits: Implement exponential backoff

Security

  • Rotate keys: Periodically rotate API secrets

  • Use HTTPS: Always use secure connections

  • Validate inputs: Sanitize user data before sending

Monitoring & Debugging

Check Event Processing

Events are queued and processed asynchronously. To verify processing:

  1. Check campaign triggers: Ensure trigger conditions match your event data

  2. Review transactions: Check if rewards were granted (GET /v1/transactions)

  3. Monitor analytics: View campaign performance metrics

Common Issues

Events not triggering campaigns:

  • Verify userId exists in the loyalty platform

  • Check trigger conditions match event data fields

  • Confirm campaign is active and not expired

Authentication failures:

  • Verify API key and secret are correct

  • Check organization ID matches

  • Ensure API key has actions:write permission

Missing user IDs:

  • Implement user identity mapping

  • Sync user records between systems

  • Use email/phone lookup if configured

Rate Limits

  • Standard: 100 requests per second per organization

  • Burst: Up to 500 requests per second for short periods

  • Contact us for higher limits

Support

For integration support:

  • Documentation: https://docs.monterosa.co

  • API Status: https://status.monterosa.co

Example: Complete Integration Flow

  1. User makes purchase in your eCommerce system

  2. Your system sends event to Loyalty API

POST /api/audience/internal/actions
{
  "userId": "user_123",
  "action": "purchase_completed",
  "data": { "amount": 150, "currency": "USD" }
}
  1. Campaign system evaluates triggers

  • Checks active campaigns

  • Matches purchase_completed trigger

  • Validates conditions (amount >= 100)

  1. Campaign effects execute

  • Awards 500 points

  • Awards VIP badge product

  • Allocates unique discount code from pool

  1. User receives rewards

  • Transaction created

  • Balance updated

  • Product allocated

  • Code assigned

  1. User can view rewards

GET /api/audience/transactions
# Returns list of transactions including the reward

Last updated