Skip to main content

Event Handler API

The Event Handler worker receives and processes customer events from your website or application, automatically distributing LTZ rewards based on your configured rules.

🚀 Try It Out: Interactive API Explorer → - Test this endpoint directly in your browser!

Base URL

https://api.loyalteez.app

Endpoints

GET /loyalteez-api/event-config

Retrieve all active event configurations for a brand, including custom events and their detection methods. Used by the SDK to automatically set up event detection.

Authentication: None required

Query Parameters:

  • brandId (required) - Your brand ID

Response:

{
"success": true,
"brandId": "0x1234...5678",
"events": [
{
"eventId": "custom_abc123_1234567890",
"eventType": "custom_abc123_1234567890",
"rewardAmount": 100,
"maxClaims": 1,
"cooldownHours": 0,
"detectionMethod": "url_pattern",
"detectionConfig": {
"urlPatterns": ["/thank-you", "/success"],
"successSelectors": [".success-message"]
},
"isCustom": true
}
],
"count": 1
}

Example cURL:

curl "https://api.loyalteez.app/loyalteez-api/event-config?brandId=YOUR_BRAND_ID"

Use Cases:

  • SDK automatically loads configurations on initialization
  • Backend systems can query available events
  • Debugging event configurations

Caching: Responses are cached for 5 minutes to improve performance.

See Also: Custom Events Guide | SDK Integration


POST /loyalteez-api/manual-event

Track a custom event and trigger LTZ distribution.

Authentication: Brand ID + Domain validation required

Request Body:

{
"brandId": "0x47511fc1c6664c9598974cb112965f8b198e0c725e",
"eventType": "account_creation",
"userEmail": "[email protected]",
"domain": "example.com",
"sourceUrl": "https://example.com/signup",
"metadata": {
"userId": "user_123",
"source": "website",
"timestamp": 1699564800000
}
}

Required Fields:

  • brandId (string) - Your brand wallet address (must be valid Ethereum address: 42 chars, starts with 0x)
  • eventType (string) - Event type (alphanumeric + underscore only, max 50 chars)
  • userEmail (string) - User's email address (RFC 5322 compliant, max 254 chars)

Optional Fields:

  • domain (string) - Your website domain (valid domain format, max 253 chars). If not provided, extracted from sourceUrl or Origin header
  • sourceUrl (string) - URL where event occurred (must be HTTP/HTTPS, max 2048 chars)
  • userIdentifier (string) - Alternative identifier (email or Ethereum address)
  • metadata (object) - Additional event data

Note: For custom events, use the custom event ID (starts with custom_) as the eventType.

Domain Authentication:

  • The domain field must match your configured website_url in Partner Portal Settings
  • Domain is extracted from: domain field → sourceUrlOrigin header
  • Returns 403 if domain is not authorized for the brand

Response:

{
"success": true,
"eventId": "550e8400-e29b-41d4-a716-446655440000",
"message": "100 LTZ tokens minted successfully!",
"rewardAmount": 100,
"eventType": "account_creation",
"walletAddress": "0x1234...5678",
"transactionHash": "0xabcd...ef01",
"reward": {
"amount": 100,
"eventType": "account_creation",
"walletAddress": "0x1234...5678",
"transactionHash": "0xabcd...ef01"
}
}

Example cURL:

curl -X POST https://api.loyalteez.app/loyalteez-api/manual-event \
-H "Content-Type: application/json" \
-H "Origin: https://example.com" \
-d '{
"brandId": "0x47511fc1c6664c9598974cb112965f8b198e0c725e",
"eventType": "account_creation",
"userEmail": "[email protected]",
"domain": "example.com"
}'

POST /loyalteez-api/create-checkout

Create a Stripe checkout session for purchasing LTZ credits.

Request Body:

{
"brandId": "0x47511fc1c6664c9598974cb112965f8b198e0c725e",
"amount": 10000,
"currency": "usd",
"userEmail": "[email protected]",
"successUrl": "https://yoursite.com/success",
"cancelUrl": "https://yoursite.com/cancel"
}

Required Fields:

  • brandId (string) - Your brand wallet address
  • amount (number) - Amount in USD cents (1000 = $10.00)
  • userEmail (string) - User's email address
  • successUrl (string) - Redirect URL after successful payment
  • cancelUrl (string) - Redirect URL if payment cancelled

Optional Fields:

  • currency (string) - Currency code (default: "usd")

Response:

{
"success": true,
"checkoutUrl": "https://checkout.stripe.com/c/pay/cs_test_...",
"sessionId": "cs_test_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
}

POST /loyalteez-api/stripe-mint

⚠️ Internal Webhook Endpoint - Called automatically by Stripe when payment completes. Do not call directly.

This endpoint handles Stripe payment completion and mints LTZ tokens to the user's wallet.

POST /loyalteez-api/bulk-events

Submit multiple events in a single request for batch processing.

Request Body:

{
"events": [
{
"brandId": "0x47511fc1c6664c9598974cb112965f8b198e0c725e",
"eventType": "account_creation",
"userEmail": "[email protected]",
"domain": "example.com"
},
{
"brandId": "0x47511fc1c6664c9598974cb112965f8b198e0c725e",
"eventType": "newsletter_subscribe",
"userEmail": "[email protected]",
"domain": "example.com"
}
]
}

Response:

{
"success": true,
"processed": 2,
"results": [
{
"success": true,
"eventId": "550e8400-e29b-41d4-a716-446655440000"
},
{
"success": true,
"eventId": "660e8400-e29b-41d4-a716-446655440001"
}
]
}

GET /loyalteez-api/diagnostic

Run diagnostic checks to verify worker configuration and dependencies.

Response:

{
"status": "healthy",
"database": "connected",
"blockchain": "connected",
"privy": "connected",
"timestamp": "2025-11-11T14:30:00.000Z"
}

POST /loyalteez-api/verify-dns

Verify DNS configuration for a domain.

Request Body:

{
"domain": "example.com"
}

Response:

{
"success": true,
"domain": "example.com",
"dnsConfigured": true,
"brandId": "0x47511fc1c6664c9598974cb112965f8b198e0c725e"
}

GET /loyalteez-api/debug

Debug endpoint to verify worker configuration and connectivity.

Response:

{
"debug": "API Worker debug info",
"hostname": "api.loyalteez.app",
"path": "/loyalteez-api/debug",
"method": "GET",
"timestamp": "2025-11-11T14:30:00.000Z",
"worker_version": "1.0.0"
}

Event Types

The following event types are supported:

Event TypeDescriptionTypical LTZ Reward
account_creationUser creates an account100-500 LTZ
email_verificationUser verifies email50-200 LTZ
first_purchaseUser makes first purchase200-1000 LTZ
purchaseAny purchase1-10 LTZ per $
referralUser refers a friend500-2000 LTZ
review_submissionUser submits review50-200 LTZ
newsletter_signupNewsletter subscription25-100 LTZ
profile_completionUser completes profile100-300 LTZ

Custom Events: You can define any custom event type in your partner portal settings. See the Custom Events Guide for detailed instructions on creating and tracking custom events.

DNS-Based Configuration

For advanced integrations, configure your domain's DNS TXT records to enable automatic brand detection:

TXT record: _loyalteez.yourdomain.com
Value: brand_id=YOUR_BRAND_ID;api_key=YOUR_API_KEY

This enables the worker to automatically associate events from your domain with your brand account.

JavaScript SDK Integration

The simplest way to integrate is via our SDK:

<script src="https://api.loyalteez.app/sdk.js"></script>
<script>
LoyalteezAutomation.init('YOUR_BRAND_ID');

// Events are auto-tracked based on your configuration
// Or manually track custom events:
LoyalteezAutomation.track('custom_event', {
userEmail: user.email,
metadata: {
userId: user.id
}
});
</script>

See the SDK Integration Guide for details.

Rate Limiting

Rate limiting is based on event rule configuration:

  • Duplicate Detection: Same event type + user email within last 60 seconds returns 409 Conflict
  • Cooldown: Based on cooldownHours in event rule (default: 24 hours)
  • Max Claims: Based on maxClaims in event rule (default: 1)
  • Cooldown Violations: Returns 429 Too Many Requests

Example:

  • User claims account_creation reward → Success
  • User claims account_creation again within cooldown period → 429 Rate Limit
  • User claims newsletter_subscribe (different event) → Success (no cooldown conflict)

Error Responses

All errors follow this format:

{
"success": false,
"error": "Error message description",
"details": {
"errors": ["validation error 1", "validation error 2"]
}
}

Common Error Codes

StatusDescriptionCommon Causes
400Bad RequestMissing required fields, invalid data format, validation errors
403ForbiddenDomain not authorized for brand, automation disabled
404Not FoundInvalid endpoint
409ConflictDuplicate event detected (same event + user within 60 seconds)
413Payload Too LargeRequest body exceeds 10KB limit
429Too Many RequestsRate limit exceeded, cooldown period not expired
500Internal Server ErrorServer error, blockchain transaction failed
503Service UnavailableDatabase not configured

Error Examples

400 - Invalid Event Data:

{
"success": false,
"error": "Invalid event data",
"details": {
"errors": [
"brandId: Invalid Ethereum address format",
"userEmail: Invalid email format"
]
}
}

403 - Domain Not Authorized:

{
"success": false,
"error": "Domain evil.com is not authorized for brand 0x47511fc1c6664c9598974cb112965f8b198e0c725e. Configured domain: example.com"
}

409 - Duplicate Event:

{
"success": false,
"error": "Duplicate event detected. This event is already being processed.",
"details": {
"existingEventId": "550e8400-e29b-41d4-a716-446655440000"
}
}

429 - Rate Limit Exceeded:

{
"success": false,
"error": "Duplicate reward",
"details": {
"message": "You already received a reward for account_creation recently. Please wait 24 hours before trying again.",
"reason": "cooldown_not_expired",
"cooldownSeconds": 86400
}
}

Webhooks

The Event Handler can send webhooks to your server when events are processed:

Configure in: Partner Portal → Settings → Webhooks

Webhook Payload:

{
"event": "ltz_distributed",
"brandId": "brand_123",
"userId": "user_456",
"email": "[email protected]",
"walletAddress": "0x1234...5678",
"ltzAmount": 100,
"transactionHash": "0xabcd...ef01",
"timestamp": 1699564800000
}

Testing

Test Endpoint

curl https://api.loyalteez.app/loyalteez-api/debug

Should return worker status and configuration.

Test Event Tracking

// In browser console on your site
Loyalteez.trackEvent('test_event', {
email: '[email protected]',
testMode: true
});

Check the Partner Portal analytics to verify the event was received.

Performance

  • Latency: < 200ms average response time
  • Availability: 99.9% uptime SLA
  • Scalability: Auto-scales to handle traffic spikes
  • Global: Deployed on Cloudflare's global network

Security

Domain Authentication

  • Brand-Domain Validation: Events require brandId + domain to match configured website_url in Partner Portal
  • CORS: Headers set to authorized domain (not wildcard) based on brand configuration
  • Subdomain Support: subdomain.example.com matches example.com configuration

Input Validation

  • Email: RFC 5322 compliant, max 254 characters
  • Ethereum Addresses: Must be 42 characters, start with 0x, valid hex
  • Event Types: Alphanumeric + underscore only, max 50 characters
  • Domains: Valid domain format, max 253 characters
  • URLs: Must be HTTP/HTTPS, max 2048 characters
  • Request Body: Max 10KB size limit
  • String Sanitization: All string inputs sanitized (control characters removed)

Other Security Measures

  • HTTPS Only: All requests must use HTTPS
  • Rate Limiting: Cooldown-based and duplicate detection
  • DNS Verification: Optional domain ownership verification via TXT records

Support