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 fromsourceUrlorOriginheadersourceUrl(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
domainfield must match your configuredwebsite_urlin Partner Portal Settings - Domain is extracted from:
domainfield →sourceUrl→Originheader - 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 addressamount(number) - Amount in USD cents (1000 = $10.00)userEmail(string) - User's email addresssuccessUrl(string) - Redirect URL after successful paymentcancelUrl(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 Type | Description | Typical LTZ Reward |
|---|---|---|
account_creation | User creates an account | 100-500 LTZ |
email_verification | User verifies email | 50-200 LTZ |
first_purchase | User makes first purchase | 200-1000 LTZ |
purchase | Any purchase | 1-10 LTZ per $ |
referral | User refers a friend | 500-2000 LTZ |
review_submission | User submits review | 50-200 LTZ |
newsletter_signup | Newsletter subscription | 25-100 LTZ |
profile_completion | User completes profile | 100-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
cooldownHoursin event rule (default: 24 hours) - Max Claims: Based on
maxClaimsin event rule (default: 1) - Cooldown Violations: Returns 429 Too Many Requests
Example:
- User claims
account_creationreward → Success - User claims
account_creationagain 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
| Status | Description | Common Causes |
|---|---|---|
| 400 | Bad Request | Missing required fields, invalid data format, validation errors |
| 403 | Forbidden | Domain not authorized for brand, automation disabled |
| 404 | Not Found | Invalid endpoint |
| 409 | Conflict | Duplicate event detected (same event + user within 60 seconds) |
| 413 | Payload Too Large | Request body exceeds 10KB limit |
| 429 | Too Many Requests | Rate limit exceeded, cooldown period not expired |
| 500 | Internal Server Error | Server error, blockchain transaction failed |
| 503 | Service Unavailable | Database 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+domainto match configuredwebsite_urlin Partner Portal - CORS: Headers set to authorized domain (not wildcard) based on brand configuration
- Subdomain Support:
subdomain.example.commatchesexample.comconfiguration
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
- Documentation: Developer Docs
- Examples: Integration Examples
- Email: [email protected]
- Status: status.loyalteez.app