@open-loyalty/mcp-server 1.3.1 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,4 +2,4 @@
2
2
  * MCP Server Instructions - provides context and guidance for AI agents
3
3
  * using the Open Loyalty MCP server.
4
4
  */
5
- export declare const SERVER_INSTRUCTIONS = "\nOpen Loyalty MCP Server - Complete Loyalty Program Management\n\n## Domain Model\n\nMember (loyalty program participant)\n \u2514\u2500\u2500 Points (wallet balance, transfers)\n \u2514\u2500\u2500 Tier (current level: Bronze, Silver, Gold)\n \u2514\u2500\u2500 Transactions (purchase history)\n \u2514\u2500\u2500 Rewards (redeemed coupons)\n \u2514\u2500\u2500 Achievements (gamification progress)\n \u2514\u2500\u2500 Badges (visual rewards from achievements)\n\nTierSet (loyalty program structure)\n \u2514\u2500\u2500 Conditions (criteria: activeUnits, totalSpending)\n \u2514\u2500\u2500 Tiers (levels with thresholds)\n\nWalletType (points currency configuration)\n\nReward (redeemable items)\n \u2514\u2500\u2500 Categories (reward groupings)\n\nCampaign (automated points/rewards rules)\n \u2514\u2500\u2500 Type (earning, spending, custom, instant_reward)\n \u2514\u2500\u2500 Trigger (transaction, custom_event, points_transfer)\n \u2514\u2500\u2500 Rules (SKU, category, transaction amount conditions)\n \u2514\u2500\u2500 Effects (give_points, multiply_points, percentage_discount)\n \u2514\u2500\u2500 Targeting (segments, tiers for audience)\n\nSegment (member audience grouping)\n \u2514\u2500\u2500 Parts (groups of criteria - OR logic between parts)\n \u2514\u2500\u2500 Criteria (conditions - AND logic within part)\n Types: transaction_count (working; requires min+max). Other types may be rejected by the API.\n\nAchievement (gamification goals)\n \u2514\u2500\u2500 Trigger (transaction, custom_event, points_transfer, reward_redemption, referral, achievement, tier_change, profile_update)\n \u2514\u2500\u2500 CompleteRule (periodGoal, period type, unique counting)\n \u2514\u2500\u2500 Badge (visual reward when completed)\n\nBadge (visual recognition)\n \u2514\u2500\u2500 Linked to achievements via badgeTypeId\n \u2514\u2500\u2500 Auto-created when referenced by achievement\n\n## Key Workflows\n\n### 1. Create 3-tier Loyalty Program:\nwallet_type_list \u2192 tierset_create \u2192 tierset_get \u2192 tierset_update_tiers\n\n### 2. Register and Reward Member:\nmember_create \u2192 points_add (welcome bonus) \u2192 member_get (verify)\n\n### 3. Record Purchase and Earn Points:\ntransaction_create (with customerData) \u2192 triggers campaigns \u2192 points auto-added\n\n### 4. Redeem Reward:\nreward_list \u2192 reward_buy (deducts points) \u2192 reward_redeem (mark coupon used)\n\n### 5. Assign Unmatched Transaction:\ntransaction_list (matched=false) \u2192 transaction_assign_member \u2192 points earned\n\n### 6. Check Member Tier Progress:\nmember_get_tier_progress \u2192 shows current tier, next tier, progress %\n\n### 7. Double Points for VIP Members:\nsegment_create (with transaction_count criteria) \u2192 campaign_create (targeting that segment with give_points effect and pointsRule: \"transaction.grossValue * 2\")\n\n### 8. Purchase Achievement with Badge:\nbadge_list (find or note badgeTypeId) \u2192 achievement_create (type+trigger+aggregation+period required, badgeTypeId)\n\n### 9. Create Targeted Promotion:\nsegment_create (define audience) \u2192 campaign_create (type: earning, target: segment, segmentIds: [segmentId])\n\n### 10. Track Member Gamification:\nachievement_list_member_achievements \u2192 badge_get_member_badges \u2192 achievement_get_member_progress\n\n## Discovery Paths:\n- Members: member_list \u2192 member_get \u2192 points_get_balance\n- Tiers: tierset_list \u2192 tierset_get \u2192 tierset_get_tiers\n- Rewards: reward_category_list \u2192 reward_list \u2192 reward_get\n- Transactions: transaction_list \u2192 transaction_get\n- Campaigns: campaign_list \u2192 campaign_get \u2192 campaign_simulate\n- Segments: segment_list \u2192 segment_get \u2192 segment_get_members \u2192 campaign_create (audience targeting)\n- Achievements: achievement_list \u2192 badge_list \u2192 achievement_create (with badge)\n- Member Gamification: achievement_list_member_achievements \u2192 badge_get_member_badges\n\n## Important Patterns:\n- conditionId REQUIRED for tier thresholds - call tierset_get after tierset_create\n- Points operations: check balance with points_get_balance before spending\n- Reward flow: reward_buy returns couponCode, use reward_redeem to mark used\n- Transactions auto-match to members via customerData (email, phone, loyaltyCardNumber)\n\n### Pagination:\n- Traditional pagination: use page + perPage params\n- Cursor pagination: provide cursor from previous response for efficient deep pagination\n- Cursor-enabled tools: member_list, transaction_list, points_get_history\n- First scroll request: cursor=\"\" (empty string)\n- Subsequent requests: use cursor value from previous response\n- When cursor provided, page param is ignored\n\n### Campaign Patterns:\n- Campaign types: direct (standard), referral (referral programs)\n- Triggers: transaction (purchase), custom_event, time, achievement, etc.\n- Effects: give_points, give_reward, deduct_unit\n- Target campaigns to segments or tiers using audience.target: \"segment\" and audience.segments array\n- campaign_create requires activity.startsAt, rules[].name, and effects[].effect (use key effect, not type). pointsRule is a STRING expression.\n\n### Points Expression (pointsRule):\npointsRule is a STRING expression, not an object. Examples:\n- Fixed: \"100\"\n- Per dollar: \"transaction.grossValue * 10\"\n- Category-based: \"transaction.category('electronics').grossValue * 5\"\n- Capped: \"(transaction.grossValue * 2 >= 100) ? 100 : transaction.grossValue * 2\"\n- Rounded: \"round_up(0.1 * transaction.grossValue)\"\n\n### Segment Patterns:\n- Parts use OR logic (member matches ANY part)\n- Criteria within a part use AND logic (member must match ALL criteria in that part)\n- Common criteria: transaction_count (working; requires min+max). Other criteria may be rejected by the API.\n\n### Achievement Patterns:\n- Triggers: transaction, custom_event, points_transfer, reward_redemption, referral, achievement, tier_change, profile_update\n- periodGoal sets the target (e.g., 5 purchases, 1000 points spent)\n- period.type defines timeframe: day, week, month, year, last_day, calendarDays, calendarWeeks, calendarMonths, calendarYears\n- aggregation.type defines counting method: quantity (count events only)\n- Link to badge via badgeTypeId - badge auto-created if doesn't exist\n- uniqueAttribute for counting distinct values (e.g., unique products)\n\n### Achievement Period Types:\n- \"day\": Count all-time when consecutive=1\n- \"week\": Count per week (use consecutive=1 for all-time weekly tracking)\n- \"month\": Count per month\n- \"year\": Count per year\n- \"last_day\": Rolling window of N days (e.g., value: 7 for last 7 days)\n- \"calendarDays\": Reset daily at midnight\n- \"calendarWeeks\": Reset weekly (Monday)\n- \"calendarMonths\": Reset monthly (1st of month)\n- \"calendarYears\": Reset yearly (January 1st)\n\n### Streak Achievement Example (7-day login streak):\n{\n \"rules\": [{\n \"trigger\": \"custom_event\",\n \"event\": \"app_login\",\n \"type\": \"direct\",\n \"aggregation\": {\"type\": \"quantity\"},\n \"completeRule\": {\n \"periodGoal\": 1,\n \"period\": {\"type\": \"last_day\", \"value\": 7, \"consecutive\": 1}\n },\n \"limit\": {\n \"interval\": {\"type\": \"calendarDays\", \"value\": 1},\n \"value\": 1\n }\n }]\n}\n\n### Custom Event Workflows:\n\n#### Create Custom Event Campaign:\n1. custom_event_schema_list \u2192 Check if event type exists\n2. custom_event_schema_create (if needed) \u2192 Define event type and fields\n3. campaign_create with trigger: \"custom_event\", event: \"{event_type}\"\n4. Send events via custom_event_send to trigger campaign\n\n#### Create Achievement with Custom Event:\n1. custom_event_schema_create \u2192 Define event (e.g., \"location_visit\")\n2. achievement_create with:\n - rules[].trigger: \"custom_event\"\n - rules[].event: \"{event_type}\"\n - rules[].type: \"direct\"\n - rules[].aggregation.type: \"quantity\"\n - rules[].completeRule.periodGoal: {count}\n - rules[].completeRule.period: { type: \"day\", consecutive: 1 } (all-time)\n\n#### Create Campaign Triggered by Achievement:\n1. achievement_create \u2192 Get achievementId from response\n2. campaign_create with:\n - trigger: \"achievement\"\n - achievementId: \"{achievement_id}\"\n - rules with effects (give_points, give_reward)\n\n### Condition Operators (for campaigns/achievements):\n- is_equal, is_not_equal\n- gte, gt, lte, lt\n- is_between, is_not_between\n- is_time_between\n- is_day_of_week, is_day_of_month\n- contains, not_contains\n- starts_with, ends_with\n- one_of, not_one_of\n- expression (for custom logic)\n\n## Common Campaign Patterns (Industry-Agnostic)\n\nThese patterns work for any loyalty program - retail, QSR, aviation, fan engagement, hospitality, etc.\n\n### Pattern 1: Count Events Toward Goal (Achievements)\nUse case: Track member actions (visits, purchases, logins, check-ins) toward a milestone.\n1. custom_event_schema_create \u2192 Define your action type (e.g., \"store_visit\", \"app_login\")\n2. achievement_create with:\n - trigger: \"custom_event\"\n - event: \"{your_event_code}\"\n - aggregation: { type: \"quantity\" }\n - completeRule: { periodGoal: {count}, period: { type: \"day\", consecutive: 1 } }\n3. custom_event_send to log each action\n\n### Pattern 2: Points Per Action (Instant Rewards)\nUse case: Award instant points for each qualifying action.\n1. custom_event_schema_create (if not using transaction)\n2. campaign_create with:\n - trigger: \"custom_event\" (or \"transaction\")\n - event: \"{event_code}\" (for custom events)\n - rules: [{ effects: [{ effect: \"give_points\", pointsRule: \"50\" }] }]\n\n### Pattern 3: Conditional Rewards (Bonus Conditions)\nUse case: Award points only when a condition is met (e.g., early arrival, large purchase).\nUse ternary expressions in pointsRule instead of conditions array:\n- pointsRule: \"event.body.minutes_before >= 60 ? 25 : 0\"\n- pointsRule: \"transaction.grossValue >= 100 ? 50 : 0\"\n\n### Pattern 4: Execution Limits (Anti-Fraud)\nUse case: Limit rewards to prevent abuse (once per day, once per week).\nCampaign limits structure:\n{\n \"limits\": {\n \"executionsPerMember\": {\n \"value\": 1,\n \"interval\": { \"type\": \"calendarDays\", \"value\": 1 }\n }\n }\n}\nNote: Use \"calendarDays\" (not \"days\"), \"calendarWeeks\", \"calendarMonths\", \"calendarYears\".\nOmit interval entirely for lifetime/forever limit.\n\n### Pattern 5: Achievement-Triggered Bonus\nUse case: Award bonus points/rewards when member completes an achievement.\n1. achievement_create \u2192 Get achievementId from response\n2. campaign_create with:\n - trigger: \"achievement\"\n - achievementId: \"{achievement_id}\"\n - rules with give_points or give_reward effect\n\n### Pattern 6: Tiered Milestones\nUse case: Multiple achievement levels (bronze/silver/gold, 5/10/25 visits).\nCreate multiple achievements with increasing periodGoal values,\neach linked to a different bonus campaign with increasing rewards.\n\n### Pattern 7: Time-Limited Promotion\nUse case: Seasonal or promotional campaigns.\n{\n \"activity\": {\n \"startsAt\": \"2026-01-01 00:00+00:00\",\n \"endsAt\": \"2026-03-31 23:59+00:00\"\n }\n}\n\n### Pattern 8: Streak Tracking\nUse case: Reward consecutive daily/weekly actions (login streaks, workout streaks).\nAchievement with:\n- completeRule.period: { type: \"last_day\", value: 7 } (rolling 7-day window)\n- limit: { value: 1, interval: { type: \"calendarDays\", value: 1 } } (max 1 per day)\n\n## Phase 3: Analytics, Admin, Roles & Stores\n\n### Domain Model (Extended)\n\nAdmin (system user)\n \u2514\u2500\u2500 Roles (permission sets)\n \u2514\u2500\u2500 Permissions (resource + access level)\n \u2514\u2500\u2500 API Keys (programmatic access)\n\nStore (multi-tenant container)\n \u2514\u2500\u2500 Members, Campaigns, Rewards (isolated per store)\n\nAudit Log (compliance tracking)\n \u2514\u2500\u2500 eventType, entityType, entityId, username, timestamp\n\n### Analytics Workflows:\n\n#### 11. Get Program Overview:\nanalytics_dashboard \u2192 analytics_tiers \u2192 analytics_members\n\n#### 12. Analyze Points Economy:\nanalytics_points \u2192 analytics_units (per wallet) \u2192 points_get_histogram\n\n#### 13. Measure Campaign Performance:\nanalytics_campaigns \u2192 analytics_campaign_detail (specific campaign)\n\n#### 14. Track Transactions:\nanalytics_transactions \u2192 transaction_list (details)\n\n### Aggregation Queries (Top Spenders, Purchase Analysis):\n\nIMPORTANT: For queries like \"top 5 spenders in July 2025\", use this approach:\n\n#### 15. Find Top Spenders by Date Range:\n1. transaction_list(purchasedAtFrom, purchasedAtTo, perPage=50, cursor='') - returns customerId with each transaction\n2. Use cursor pagination to fetch ALL pages - even if there are 1000+ transactions\n3. Aggregate grossValue by customerId in your code\n4. Sort by total spent, take top N\n5. member_get for each top spender to get names/details\n\nCRITICAL - DO NOT TRY TO BE SMART OR OPTIMIZE:\n- ALWAYS iterate through ALL pages using cursor pagination - this is the ONLY correct approach\n- DO NOT skip pages or try to sample data - you will get inaccurate results\n- DO NOT use transaction_get individually - transaction_list already includes customerId\n- DO NOT try to find \"smarter\" analytics endpoints - they don't exist for per-customer aggregation\n- Large datasets (1000+ transactions) are normal - just keep paginating until cursor is empty\n- Start with cursor='' (empty string), use returned cursor for next request, repeat until done\n\nExample: Top 5 spenders July 2025\n- First request: transaction_list(purchasedAtFrom: \"2025-07-01\", purchasedAtTo: \"2025-07-31\", perPage: 50, cursor: \"\")\n- Each result includes: transactionId, grossValue, customerId, purchasedAt\n- Keep fetching with returned cursor until response has no cursor or empty transactions\n- Even if there are 1500 transactions (30 pages), iterate through ALL of them\n- Group by customerId, sum grossValue, sort descending, take 5\n\n### Admin & Security Workflows:\n\n#### 15. Create Admin with Limited Role:\nacl_get_resources \u2192 role_create \u2192 admin_create (with roleId)\n\n#### 16. Generate API Key for Integration:\nadmin_get \u2192 apikey_create \u2192 SAVE TOKEN IMMEDIATELY (shown once!)\n\n#### 17. Audit User Actions:\naudit_list (filter by username/entity) \u2192 audit_export (compliance report)\n\n### Store Multi-Tenancy:\n\n#### 18. Create New Store:\nstore_create \u2192 configure campaigns/tiers \u2192 member_create (with storeCode)\n\n### Analytics Query Patterns:\n- All analytics tools support dateFrom/dateTo ISO date filters\n- analytics_dashboard: high-level program metrics\n- analytics_units: wallet-specific metrics (requires walletTypeCode)\n- analytics_campaign_detail: detailed metrics for single campaign\n\n### Admin \u2192 Role \u2192 Permission Model:\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Admin \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 Role \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 Permission \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502 \u2502\n \u2502 resource + access\n \u2502 (VIEW, MODIFY, etc.)\n \u25BC\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 API Key \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\n### Store Multi-Tenancy:\n- Each store is isolated: members, campaigns, rewards, transactions\n- storeCode parameter routes requests to correct tenant\n- Default store used when storeCode omitted\n- IMPORTANT: Do NOT pass storeCode parameter unless the user explicitly asks to work with a different store. The configured default store should always be used unless the user requests otherwise.\n\n## Phase 4: Webhooks, Import & Export\n\n### Domain Model (Extended)\n\nWebhook Subscription (event notification)\n \u2514\u2500\u2500 eventName (event to subscribe to)\n \u2514\u2500\u2500 url (callback endpoint)\n \u2514\u2500\u2500 headers (custom HTTP headers)\n\nImport (bulk data upload)\n \u2514\u2500\u2500 type: member, groupValue, segmentMembers, unitTransferAdding, etc.\n \u2514\u2500\u2500 status: pending, processing, succeed, failed\n \u2514\u2500\u2500 items (individual row results)\n\nExport (bulk data download)\n \u2514\u2500\u2500 type: campaignCode, member, memberTier, memberSegment, rewardFulfillment\n \u2514\u2500\u2500 status: pending, done, failed, error\n \u2514\u2500\u2500 CSV file (when status='done')\n\n### Webhook Workflows:\n\n#### 19. Subscribe to Member Events for CRM Sync:\nwebhook_events \u2192 webhook_create (eventName: 'member.created', url: 'https://crm.example.com/webhook')\n\n#### 20. List and Manage Subscriptions:\nwebhook_list \u2192 webhook_get \u2192 webhook_update or webhook_delete\n\n### Import Workflows:\n\n#### 21. Bulk Import Members from CSV:\nimport_create (type: 'member', fileContent: CSV data) \u2192 import_list \u2192 import_get (check status)\n\n#### 22. Bulk Add Points to Members:\nimport_create (type: 'unitTransferAdding', fileContent: CSV) \u2192 poll import_get until complete\n\n### Export Workflows:\n\n#### 23. Export Campaign Codes:\nexport_create (type: 'campaignCode', filters: { campaignId }) \u2192 poll export_get (until status='done') \u2192 export_download\n\n#### 24. Export Member Data:\nexport_create (type: 'member') \u2192 export_get \u2192 export_download (returns CSV)\n\n### Webhook Patterns:\n- Use webhook_events to discover available event types before subscribing\n- API uses wrapper: { webhookSubscription: { eventName, url, headers? } }\n- Common events: member.created, member.updated, transaction.created, reward.purchased\n\n### Import Patterns:\n- Import is async: create returns importId, poll status with import_get\n- CSV format required - provide plain text, not base64\n- Types: member, groupValue, segmentMembers, unitTransferAdding, unitTransferSpending, transaction, campaignCode, rewardCoupon\n\n### Export Patterns:\n- Export is async: create returns exportId, poll status until 'done'\n- API body wrapper varies by type: { campaignCode: { filters... } }\n- Only call export_download when status='done'\n- Types: campaignCode, member, memberTier, memberSegment, rewardFulfillment\n";
5
+ export declare const SERVER_INSTRUCTIONS = "\nOpen Loyalty MCP Server - Complete Loyalty Program Management\n\n## Domain Model\n\nMember (loyalty program participant)\n \u2514\u2500\u2500 Points (wallet balance, transfers)\n \u2514\u2500\u2500 Tier (current level: Bronze, Silver, Gold)\n \u2514\u2500\u2500 Transactions (purchase history)\n \u2514\u2500\u2500 Rewards (redeemed coupons)\n \u2514\u2500\u2500 Achievements (gamification progress)\n \u2514\u2500\u2500 Badges (visual rewards from achievements)\n\nTierSet (loyalty program structure)\n \u2514\u2500\u2500 Conditions (criteria: activeUnits, totalSpending)\n \u2514\u2500\u2500 Tiers (levels with thresholds)\n\nWalletType (points currency configuration)\n\nReward (redeemable items)\n \u2514\u2500\u2500 Categories (reward groupings)\n\nCampaign (automated points/rewards rules)\n \u2514\u2500\u2500 Type (earning, spending, custom, instant_reward)\n \u2514\u2500\u2500 Trigger (transaction, custom_event, points_transfer)\n \u2514\u2500\u2500 Rules (SKU, category, transaction amount conditions)\n \u2514\u2500\u2500 Effects (give_points, multiply_points, percentage_discount)\n \u2514\u2500\u2500 Targeting (segments, tiers for audience)\n\nSegment (member audience grouping)\n \u2514\u2500\u2500 Parts (groups of criteria - OR logic between parts)\n \u2514\u2500\u2500 Criteria (conditions - AND logic within part)\n Types: transaction_count (working; requires min+max). Other types may be rejected by the API.\n\nAchievement (gamification goals)\n \u2514\u2500\u2500 Trigger (transaction, custom_event, points_transfer, reward_redemption, referral, achievement, tier_change, profile_update)\n \u2514\u2500\u2500 CompleteRule (periodGoal, period type, unique counting)\n \u2514\u2500\u2500 Badge (visual reward when completed)\n\nBadge (visual recognition)\n \u2514\u2500\u2500 Linked to achievements via badgeTypeId\n \u2514\u2500\u2500 Auto-created when referenced by achievement\n\n## Key Workflows\n\n### 1. Create 3-tier Loyalty Program:\nRECOMMENDED WORKFLOW:\n1. wallet_type_list \u2192 Get wallet code (usually \"default\")\n2. tierset_list \u2192 Check if tier set already exists\n3. IF EXISTS: tierset_get \u2192 Get conditionId from existing tier set\n ELSE: tierset_create \u2192 Create new, then tierset_get to get conditionId\n4. tierset_update_tiers \u2192 Define tier thresholds using conditionId\n5. tierset_get_tiers \u2192 Verify tiers created correctly\n\nGOTCHA - Valid tier condition attributes:\n- activeUnits (current spendable balance)\n- totalEarnedUnits (lifetime points - NOT 'earnedUnits'!)\n- totalSpending (lifetime spend amount)\n- monthsSinceJoiningProgram (tenure in months)\n- cumulatedEarnedUnits (similar to totalEarnedUnits)\n\nCOMMON MISTAKE: Using 'earnedUnits' will fail - use 'totalEarnedUnits' for lifetime points.\n\n### 2. Register and Reward Member:\nmember_create \u2192 points_add (welcome bonus) \u2192 member_get (verify)\n\n### 3. Record Purchase and Earn Points:\ntransaction_create (with customerData) \u2192 triggers campaigns \u2192 points auto-added\n\n### 4. Redeem Reward:\nreward_list \u2192 reward_buy (deducts points) \u2192 reward_redeem (mark coupon used)\n\n### 5. Assign Unmatched Transaction:\ntransaction_list (matched=false) \u2192 transaction_assign_member \u2192 points earned\n\n### 6. Check Member Tier Progress:\nmember_get_tier_progress \u2192 shows current tier, next tier, progress %\n\n### 7. Double Points for VIP Members:\nsegment_create (with transaction_count criteria) \u2192 campaign_create (targeting that segment with give_points effect and pointsRule: \"transaction.grossValue * 2\")\n\n### 8. Purchase Achievement with Badge:\nbadge_list (find or note badgeTypeId) \u2192 achievement_create (type+trigger+aggregation+period required, badgeTypeId)\n\n### 9. Create Targeted Promotion:\nsegment_create (define audience) \u2192 campaign_create (type: earning, target: segment, segmentIds: [segmentId])\n\n### 10. Track Member Gamification:\nachievement_list_member_achievements \u2192 badge_get_member_badges \u2192 achievement_get_member_progress\n\n## Discovery Paths:\n- Members: member_list \u2192 member_get \u2192 points_get_balance\n- Tiers: tierset_list \u2192 tierset_get \u2192 tierset_get_tiers\n- Rewards: reward_category_list \u2192 reward_list \u2192 reward_get\n- Transactions: transaction_list \u2192 transaction_get\n- Campaigns: campaign_list \u2192 campaign_get \u2192 campaign_simulate\n- Segments: segment_list \u2192 segment_get \u2192 segment_get_members \u2192 campaign_create (audience targeting)\n- Achievements: achievement_list \u2192 badge_list \u2192 achievement_create (with badge)\n- Member Gamification: achievement_list_member_achievements \u2192 badge_get_member_badges\n\n## Important Patterns:\n- TIER SETUP: conditionId REQUIRED for tier thresholds\n 1. tierset_create returns conditions but you need the id from tierset_get\n 2. The conditionId is in tierset_get response: conditions[].id (this IS the conditionId)\n 3. Use this conditionId in tierset_update_tiers for each tier's threshold\n- TIER ATTRIBUTES: Use 'totalEarnedUnits' (NOT 'earnedUnits') for lifetime points\n- walletType uses CODE (e.g., 'default'), not UUID\n- Points operations: check balance with points_get_balance before spending\n- Reward flow: reward_buy returns couponCode, use reward_redeem to mark used\n- Transactions auto-match to members via customerData (email, phone, loyaltyCardNumber)\n\n### Pagination:\n- Traditional pagination: use page + perPage params\n- Cursor pagination: provide cursor from previous response for efficient deep pagination\n- Cursor-enabled tools: member_list, transaction_list, points_get_history\n- First scroll request: cursor=\"\" (empty string)\n- Subsequent requests: use cursor value from previous response\n- When cursor provided, page param is ignored\n\n### Campaign Patterns:\n- Campaign types: direct (standard), referral (referral programs)\n- Triggers: transaction (purchase), custom_event, time, achievement, etc.\n- Effects: give_points, give_reward, deduct_unit\n- Target campaigns to segments or tiers using audience.target: \"segment\" and audience.segments array\n- campaign_create requires activity.startsAt, rules[].name, and effects[].effect (use key effect, not type). pointsRule is a STRING expression.\n\n### Points Expression (pointsRule):\npointsRule is a STRING expression, not an object. Examples:\n- Fixed: \"100\"\n- Per dollar: \"transaction.grossValue * 10\"\n- Category-based: \"transaction.category('electronics').grossValue * 5\"\n- Capped: \"(transaction.grossValue * 2 >= 100) ? 100 : transaction.grossValue * 2\"\n- Rounded: \"round_up(0.1 * transaction.grossValue)\"\n\n### Segment Patterns:\n- Parts use OR logic (member matches ANY part)\n- Criteria within a part use AND logic (member must match ALL criteria in that part)\n- Common criteria: transaction_count (working; requires min+max). Other criteria may be rejected by the API.\n\n### Achievement Patterns:\n- Triggers: transaction, custom_event, points_transfer, reward_redemption, referral, achievement, tier_change, profile_update\n- periodGoal sets the target (e.g., 5 purchases, 1000 points spent)\n- period.type defines timeframe: day, week, month, year, last_day, calendarDays, calendarWeeks, calendarMonths, calendarYears\n- aggregation.type defines counting method: quantity (count events only)\n- Link to badge via badgeTypeId - badge auto-created if doesn't exist\n- uniqueAttribute for counting distinct values (e.g., unique products)\n\n### Achievement Period Types:\n- \"day\": Count all-time when consecutive=1\n- \"week\": Count per week (use consecutive=1 for all-time weekly tracking)\n- \"month\": Count per month\n- \"year\": Count per year\n- \"last_day\": Rolling window of N days (e.g., value: 7 for last 7 days)\n- \"calendarDays\": Reset daily at midnight\n- \"calendarWeeks\": Reset weekly (Monday)\n- \"calendarMonths\": Reset monthly (1st of month)\n- \"calendarYears\": Reset yearly (January 1st)\n\n### Streak Achievement Example (7-day login streak):\n{\n \"rules\": [{\n \"trigger\": \"custom_event\",\n \"event\": \"app_login\",\n \"type\": \"direct\",\n \"aggregation\": {\"type\": \"quantity\"},\n \"completeRule\": {\n \"periodGoal\": 1,\n \"period\": {\"type\": \"last_day\", \"value\": 7, \"consecutive\": 1}\n },\n \"limit\": {\n \"interval\": {\"type\": \"calendarDays\", \"value\": 1},\n \"value\": 1\n }\n }]\n}\n\n### Custom Event Workflows:\n\n#### Create Custom Event Campaign:\n1. custom_event_schema_list \u2192 Check if event type exists\n2. custom_event_schema_create (if needed) \u2192 Define event type and fields\n3. campaign_create with trigger: \"custom_event\", event: \"{event_type}\"\n4. Send events via custom_event_send to trigger campaign\n\n#### Create Achievement with Custom Event:\n1. custom_event_schema_create \u2192 Define event (e.g., \"location_visit\")\n2. achievement_create with:\n - rules[].trigger: \"custom_event\"\n - rules[].event: \"{event_type}\"\n - rules[].type: \"direct\"\n - rules[].aggregation.type: \"quantity\"\n - rules[].completeRule.periodGoal: {count}\n - rules[].completeRule.period: { type: \"day\", consecutive: 1 } (all-time)\n\n#### Create Campaign Triggered by Achievement:\n1. achievement_create \u2192 Get achievementId from response\n2. campaign_create with:\n - trigger: \"achievement\"\n - achievementId: \"{achievement_id}\"\n - rules with effects (give_points, give_reward)\n\n### Condition Operators (for campaigns/achievements):\n- is_equal, is_not_equal\n- gte, gt, lte, lt\n- is_between, is_not_between\n- is_time_between\n- is_day_of_week, is_day_of_month\n- contains, not_contains\n- starts_with, ends_with\n- one_of, not_one_of\n- expression (for custom logic)\n\n## Common Campaign Patterns (Industry-Agnostic)\n\nThese patterns work for any loyalty program - retail, QSR, aviation, fan engagement, hospitality, etc.\n\n### Pattern 1: Count Events Toward Goal (Achievements)\nUse case: Track member actions (visits, purchases, logins, check-ins) toward a milestone.\n1. custom_event_schema_create \u2192 Define your action type (e.g., \"store_visit\", \"app_login\")\n2. achievement_create with:\n - trigger: \"custom_event\"\n - event: \"{your_event_code}\"\n - aggregation: { type: \"quantity\" }\n - completeRule: { periodGoal: {count}, period: { type: \"day\", consecutive: 1 } }\n3. custom_event_send to log each action\n\n### Pattern 2: Points Per Action (Instant Rewards)\nUse case: Award instant points for each qualifying action.\n1. custom_event_schema_create (if not using transaction)\n2. campaign_create with:\n - trigger: \"custom_event\" (or \"transaction\")\n - event: \"{event_code}\" (for custom events)\n - rules: [{ effects: [{ effect: \"give_points\", pointsRule: \"50\" }] }]\n\n### Pattern 3: Conditional Rewards (Bonus Conditions)\nUse case: Award points only when a condition is met (e.g., early arrival, large purchase).\nUse ternary expressions in pointsRule instead of conditions array:\n- pointsRule: \"event.body.minutes_before >= 60 ? 25 : 0\"\n- pointsRule: \"transaction.grossValue >= 100 ? 50 : 0\"\n\n### Pattern 4: Execution Limits (Anti-Fraud)\nUse case: Limit rewards to prevent abuse (once per day, once per week).\nCampaign limits structure:\n{\n \"limits\": {\n \"executionsPerMember\": {\n \"value\": 1,\n \"interval\": { \"type\": \"calendarDays\", \"value\": 1 }\n }\n }\n}\nNote: Use \"calendarDays\" (not \"days\"), \"calendarWeeks\", \"calendarMonths\", \"calendarYears\".\nOmit interval entirely for lifetime/forever limit.\n\n### Pattern 5: Achievement-Triggered Bonus\nUse case: Award bonus points/rewards when member completes an achievement.\n1. achievement_create \u2192 Get achievementId from response\n2. campaign_create with:\n - trigger: \"achievement\"\n - achievementId: \"{achievement_id}\"\n - rules with give_points or give_reward effect\n\n### Pattern 6: Tiered Milestones\nUse case: Multiple achievement levels (bronze/silver/gold, 5/10/25 visits).\nCreate multiple achievements with increasing periodGoal values,\neach linked to a different bonus campaign with increasing rewards.\n\n### Pattern 7: Time-Limited Promotion\nUse case: Seasonal or promotional campaigns.\n{\n \"activity\": {\n \"startsAt\": \"2026-01-01 00:00+00:00\",\n \"endsAt\": \"2026-03-31 23:59+00:00\"\n }\n}\n\n### Pattern 8: Streak Tracking\nUse case: Reward consecutive daily/weekly actions (login streaks, workout streaks).\nAchievement with:\n- completeRule.period: { type: \"last_day\", value: 7 } (rolling 7-day window)\n- limit: { value: 1, interval: { type: \"calendarDays\", value: 1 } } (max 1 per day)\n\n## Phase 3: Analytics, Admin, Roles & Stores\n\n### Domain Model (Extended)\n\nAdmin (system user)\n \u2514\u2500\u2500 Roles (permission sets)\n \u2514\u2500\u2500 Permissions (resource + access level)\n \u2514\u2500\u2500 API Keys (programmatic access)\n\nStore (multi-tenant container)\n \u2514\u2500\u2500 Members, Campaigns, Rewards (isolated per store)\n\nAudit Log (compliance tracking)\n \u2514\u2500\u2500 eventType, entityType, entityId, username, timestamp\n\n### Analytics Workflows:\n\n#### 11. Get Program Overview:\nanalytics_dashboard \u2192 analytics_tiers \u2192 analytics_members\n\n#### 12. Analyze Points Economy:\nanalytics_points \u2192 analytics_units (per wallet) \u2192 points_get_histogram\n\n#### 13. Measure Campaign Performance:\nanalytics_campaigns \u2192 analytics_campaign_detail (specific campaign)\n\n#### 14. Track Transactions:\nanalytics_transactions \u2192 transaction_list (details)\n\n### Aggregation Queries (Top Spenders, Purchase Analysis):\n\nIMPORTANT: For queries like \"top 5 spenders in July 2025\", use this approach:\n\n#### 15. Find Top Spenders by Date Range:\n1. transaction_list(purchasedAtFrom, purchasedAtTo, perPage=50, cursor='') - returns customerId with each transaction\n2. Use cursor pagination to fetch ALL pages - even if there are 1000+ transactions\n3. Aggregate grossValue by customerId in your code\n4. Sort by total spent, take top N\n5. member_get for each top spender to get names/details\n\nCRITICAL - DO NOT TRY TO BE SMART OR OPTIMIZE:\n- ALWAYS iterate through ALL pages using cursor pagination - this is the ONLY correct approach\n- DO NOT skip pages or try to sample data - you will get inaccurate results\n- DO NOT use transaction_get individually - transaction_list already includes customerId\n- DO NOT try to find \"smarter\" analytics endpoints - they don't exist for per-customer aggregation\n- Large datasets (1000+ transactions) are normal - just keep paginating until cursor is empty\n- Start with cursor='' (empty string), use returned cursor for next request, repeat until done\n\nExample: Top 5 spenders July 2025\n- First request: transaction_list(purchasedAtFrom: \"2025-07-01\", purchasedAtTo: \"2025-07-31\", perPage: 50, cursor: \"\")\n- Each result includes: transactionId, grossValue, customerId, purchasedAt\n- Keep fetching with returned cursor until response has no cursor or empty transactions\n- Even if there are 1500 transactions (30 pages), iterate through ALL of them\n- Group by customerId, sum grossValue, sort descending, take 5\n\n### Admin & Security Workflows:\n\n#### 15. Create Admin with Limited Role:\nacl_get_resources \u2192 role_create \u2192 admin_create (with roleId)\n\n#### 16. Generate API Key for Integration:\nadmin_get \u2192 apikey_create \u2192 SAVE TOKEN IMMEDIATELY (shown once!)\n\n#### 17. Audit User Actions:\naudit_list (filter by username/entity) \u2192 audit_export (compliance report)\n\n### Store Multi-Tenancy:\n\n#### 18. Create New Store:\nstore_create \u2192 configure campaigns/tiers \u2192 member_create (with storeCode)\n\n### Analytics Query Patterns:\n- All analytics tools support dateFrom/dateTo ISO date filters\n- analytics_dashboard: high-level program metrics\n- analytics_units: wallet-specific metrics (requires walletTypeCode)\n- analytics_campaign_detail: detailed metrics for single campaign\n\n### Admin \u2192 Role \u2192 Permission Model:\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Admin \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 Role \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 Permission \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502 \u2502\n \u2502 resource + access\n \u2502 (VIEW, MODIFY, etc.)\n \u25BC\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 API Key \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\n### Store Multi-Tenancy:\n- Each store is isolated: members, campaigns, rewards, transactions\n- storeCode parameter routes requests to correct tenant\n- Default store used when storeCode omitted\n- IMPORTANT: Do NOT pass storeCode parameter unless the user explicitly asks to work with a different store. The configured default store should always be used unless the user requests otherwise.\n\n## Phase 4: Webhooks, Import & Export\n\n### Domain Model (Extended)\n\nWebhook Subscription (event notification)\n \u2514\u2500\u2500 eventName (event to subscribe to)\n \u2514\u2500\u2500 url (callback endpoint)\n \u2514\u2500\u2500 headers (custom HTTP headers)\n\nImport (bulk data upload)\n \u2514\u2500\u2500 type: member, groupValue, segmentMembers, unitTransferAdding, etc.\n \u2514\u2500\u2500 status: pending, processing, succeed, failed\n \u2514\u2500\u2500 items (individual row results)\n\nExport (bulk data download)\n \u2514\u2500\u2500 type: campaignCode, member, memberTier, memberSegment, rewardFulfillment\n \u2514\u2500\u2500 status: pending, done, failed, error\n \u2514\u2500\u2500 CSV file (when status='done')\n\n### Webhook Workflows:\n\n#### 19. Subscribe to Member Events for CRM Sync:\nwebhook_events \u2192 webhook_create (eventName: 'member.created', url: 'https://crm.example.com/webhook')\n\n#### 20. List and Manage Subscriptions:\nwebhook_list \u2192 webhook_get \u2192 webhook_update or webhook_delete\n\n### Import Workflows:\n\n#### 21. Bulk Import Members from CSV:\nimport_create (type: 'member', fileContent: CSV data) \u2192 import_list \u2192 import_get (check status)\n\n#### 22. Bulk Add Points to Members:\nimport_create (type: 'unitTransferAdding', fileContent: CSV) \u2192 poll import_get until complete\n\n### Export Workflows:\n\n#### 23. Export Campaign Codes:\nexport_create (type: 'campaignCode', filters: { campaignId }) \u2192 poll export_get (until status='done') \u2192 export_download\n\n#### 24. Export Member Data:\nexport_create (type: 'member') \u2192 export_get \u2192 export_download (returns CSV)\n\n### Webhook Patterns:\n- Use webhook_events to discover available event types before subscribing\n- API uses wrapper: { webhookSubscription: { eventName, url, headers? } }\n- Common events: member.created, member.updated, transaction.created, reward.purchased\n\n### Import Patterns:\n- Import is async: create returns importId, poll status with import_get\n- CSV format required - provide plain text, not base64\n- Types: member, groupValue, segmentMembers, unitTransferAdding, unitTransferSpending, transaction, campaignCode, rewardCoupon\n\n### Export Patterns:\n- Export is async: create returns exportId, poll status until 'done'\n- API body wrapper varies by type: { campaignCode: { filters... } }\n- Only call export_download when status='done'\n- Types: campaignCode, member, memberTier, memberSegment, rewardFulfillment\n";
@@ -48,7 +48,22 @@ Badge (visual recognition)
48
48
  ## Key Workflows
49
49
 
50
50
  ### 1. Create 3-tier Loyalty Program:
51
- wallet_type_list → tierset_create → tierset_get → tierset_update_tiers
51
+ RECOMMENDED WORKFLOW:
52
+ 1. wallet_type_list → Get wallet code (usually "default")
53
+ 2. tierset_list → Check if tier set already exists
54
+ 3. IF EXISTS: tierset_get → Get conditionId from existing tier set
55
+ ELSE: tierset_create → Create new, then tierset_get to get conditionId
56
+ 4. tierset_update_tiers → Define tier thresholds using conditionId
57
+ 5. tierset_get_tiers → Verify tiers created correctly
58
+
59
+ GOTCHA - Valid tier condition attributes:
60
+ - activeUnits (current spendable balance)
61
+ - totalEarnedUnits (lifetime points - NOT 'earnedUnits'!)
62
+ - totalSpending (lifetime spend amount)
63
+ - monthsSinceJoiningProgram (tenure in months)
64
+ - cumulatedEarnedUnits (similar to totalEarnedUnits)
65
+
66
+ COMMON MISTAKE: Using 'earnedUnits' will fail - use 'totalEarnedUnits' for lifetime points.
52
67
 
53
68
  ### 2. Register and Reward Member:
54
69
  member_create → points_add (welcome bonus) → member_get (verify)
@@ -88,7 +103,12 @@ achievement_list_member_achievements → badge_get_member_badges → achievement
88
103
  - Member Gamification: achievement_list_member_achievements → badge_get_member_badges
89
104
 
90
105
  ## Important Patterns:
91
- - conditionId REQUIRED for tier thresholds - call tierset_get after tierset_create
106
+ - TIER SETUP: conditionId REQUIRED for tier thresholds
107
+ 1. tierset_create returns conditions but you need the id from tierset_get
108
+ 2. The conditionId is in tierset_get response: conditions[].id (this IS the conditionId)
109
+ 3. Use this conditionId in tierset_update_tiers for each tier's threshold
110
+ - TIER ATTRIBUTES: Use 'totalEarnedUnits' (NOT 'earnedUnits') for lifetime points
111
+ - walletType uses CODE (e.g., 'default'), not UUID
92
112
  - Points operations: check balance with points_get_balance before spending
93
113
  - Reward flow: reward_buy returns couponCode, use reward_redeem to mark used
94
114
  - Transactions auto-match to members via customerData (email, phone, loyaltyCardNumber)
@@ -93,11 +93,11 @@ export declare const achievementToolDefinitions: readonly [{
93
93
  value: import("zod").ZodOptional<import("zod").ZodNumber>;
94
94
  consecutive: import("zod").ZodNumber;
95
95
  }, "strip", import("zod").ZodTypeAny, {
96
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
96
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
97
97
  consecutive: number;
98
98
  value?: number | undefined;
99
99
  }, {
100
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
100
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
101
101
  consecutive: number;
102
102
  value?: number | undefined;
103
103
  }>;
@@ -105,7 +105,7 @@ export declare const achievementToolDefinitions: readonly [{
105
105
  }, "strip", import("zod").ZodTypeAny, {
106
106
  periodGoal: string | number;
107
107
  period: {
108
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
108
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
109
109
  consecutive: number;
110
110
  value?: number | undefined;
111
111
  };
@@ -113,7 +113,7 @@ export declare const achievementToolDefinitions: readonly [{
113
113
  }, {
114
114
  periodGoal: string | number;
115
115
  period: {
116
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
116
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
117
117
  consecutive: number;
118
118
  value?: number | undefined;
119
119
  };
@@ -159,7 +159,7 @@ export declare const achievementToolDefinitions: readonly [{
159
159
  completeRule: {
160
160
  periodGoal: string | number;
161
161
  period: {
162
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
162
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
163
163
  consecutive: number;
164
164
  value?: number | undefined;
165
165
  };
@@ -168,11 +168,11 @@ export declare const achievementToolDefinitions: readonly [{
168
168
  aggregation: {
169
169
  type: "quantity";
170
170
  };
171
- conditions?: Record<string, unknown>[] | undefined;
172
171
  translations?: Record<string, {
173
172
  name: string;
174
173
  description?: string | undefined;
175
174
  }> | undefined;
175
+ conditions?: Record<string, unknown>[] | undefined;
176
176
  event?: string | undefined;
177
177
  achievementRuleId?: string | undefined;
178
178
  limit?: {
@@ -189,7 +189,7 @@ export declare const achievementToolDefinitions: readonly [{
189
189
  completeRule: {
190
190
  periodGoal: string | number;
191
191
  period: {
192
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
192
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
193
193
  consecutive: number;
194
194
  value?: number | undefined;
195
195
  };
@@ -198,11 +198,11 @@ export declare const achievementToolDefinitions: readonly [{
198
198
  aggregation: {
199
199
  type: "quantity";
200
200
  };
201
- conditions?: Record<string, unknown>[] | undefined;
202
201
  translations?: Record<string, {
203
202
  name: string;
204
203
  description?: string | undefined;
205
204
  }> | undefined;
205
+ conditions?: Record<string, unknown>[] | undefined;
206
206
  event?: string | undefined;
207
207
  achievementRuleId?: string | undefined;
208
208
  limit?: {
@@ -306,11 +306,11 @@ export declare const achievementToolDefinitions: readonly [{
306
306
  value: import("zod").ZodOptional<import("zod").ZodNumber>;
307
307
  consecutive: import("zod").ZodNumber;
308
308
  }, "strip", import("zod").ZodTypeAny, {
309
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
309
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
310
310
  consecutive: number;
311
311
  value?: number | undefined;
312
312
  }, {
313
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
313
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
314
314
  consecutive: number;
315
315
  value?: number | undefined;
316
316
  }>;
@@ -318,7 +318,7 @@ export declare const achievementToolDefinitions: readonly [{
318
318
  }, "strip", import("zod").ZodTypeAny, {
319
319
  periodGoal: string | number;
320
320
  period: {
321
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
321
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
322
322
  consecutive: number;
323
323
  value?: number | undefined;
324
324
  };
@@ -326,7 +326,7 @@ export declare const achievementToolDefinitions: readonly [{
326
326
  }, {
327
327
  periodGoal: string | number;
328
328
  period: {
329
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
329
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
330
330
  consecutive: number;
331
331
  value?: number | undefined;
332
332
  };
@@ -372,7 +372,7 @@ export declare const achievementToolDefinitions: readonly [{
372
372
  completeRule: {
373
373
  periodGoal: string | number;
374
374
  period: {
375
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
375
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
376
376
  consecutive: number;
377
377
  value?: number | undefined;
378
378
  };
@@ -381,11 +381,11 @@ export declare const achievementToolDefinitions: readonly [{
381
381
  aggregation: {
382
382
  type: "quantity";
383
383
  };
384
- conditions?: Record<string, unknown>[] | undefined;
385
384
  translations?: Record<string, {
386
385
  name: string;
387
386
  description?: string | undefined;
388
387
  }> | undefined;
388
+ conditions?: Record<string, unknown>[] | undefined;
389
389
  event?: string | undefined;
390
390
  achievementRuleId?: string | undefined;
391
391
  limit?: {
@@ -402,7 +402,7 @@ export declare const achievementToolDefinitions: readonly [{
402
402
  completeRule: {
403
403
  periodGoal: string | number;
404
404
  period: {
405
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
405
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
406
406
  consecutive: number;
407
407
  value?: number | undefined;
408
408
  };
@@ -411,11 +411,11 @@ export declare const achievementToolDefinitions: readonly [{
411
411
  aggregation: {
412
412
  type: "quantity";
413
413
  };
414
- conditions?: Record<string, unknown>[] | undefined;
415
414
  translations?: Record<string, {
416
415
  name: string;
417
416
  description?: string | undefined;
418
417
  }> | undefined;
418
+ conditions?: Record<string, unknown>[] | undefined;
419
419
  event?: string | undefined;
420
420
  achievementRuleId?: string | undefined;
421
421
  limit?: {
@@ -79,11 +79,11 @@ export declare const AchievementCreateInputSchema: {
79
79
  value: z.ZodOptional<z.ZodNumber>;
80
80
  consecutive: z.ZodNumber;
81
81
  }, "strip", z.ZodTypeAny, {
82
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
82
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
83
83
  consecutive: number;
84
84
  value?: number | undefined;
85
85
  }, {
86
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
86
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
87
87
  consecutive: number;
88
88
  value?: number | undefined;
89
89
  }>;
@@ -91,7 +91,7 @@ export declare const AchievementCreateInputSchema: {
91
91
  }, "strip", z.ZodTypeAny, {
92
92
  periodGoal: string | number;
93
93
  period: {
94
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
94
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
95
95
  consecutive: number;
96
96
  value?: number | undefined;
97
97
  };
@@ -99,7 +99,7 @@ export declare const AchievementCreateInputSchema: {
99
99
  }, {
100
100
  periodGoal: string | number;
101
101
  period: {
102
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
102
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
103
103
  consecutive: number;
104
104
  value?: number | undefined;
105
105
  };
@@ -145,7 +145,7 @@ export declare const AchievementCreateInputSchema: {
145
145
  completeRule: {
146
146
  periodGoal: string | number;
147
147
  period: {
148
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
148
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
149
149
  consecutive: number;
150
150
  value?: number | undefined;
151
151
  };
@@ -154,11 +154,11 @@ export declare const AchievementCreateInputSchema: {
154
154
  aggregation: {
155
155
  type: "quantity";
156
156
  };
157
- conditions?: Record<string, unknown>[] | undefined;
158
157
  translations?: Record<string, {
159
158
  name: string;
160
159
  description?: string | undefined;
161
160
  }> | undefined;
161
+ conditions?: Record<string, unknown>[] | undefined;
162
162
  event?: string | undefined;
163
163
  achievementRuleId?: string | undefined;
164
164
  limit?: {
@@ -175,7 +175,7 @@ export declare const AchievementCreateInputSchema: {
175
175
  completeRule: {
176
176
  periodGoal: string | number;
177
177
  period: {
178
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
178
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
179
179
  consecutive: number;
180
180
  value?: number | undefined;
181
181
  };
@@ -184,11 +184,11 @@ export declare const AchievementCreateInputSchema: {
184
184
  aggregation: {
185
185
  type: "quantity";
186
186
  };
187
- conditions?: Record<string, unknown>[] | undefined;
188
187
  translations?: Record<string, {
189
188
  name: string;
190
189
  description?: string | undefined;
191
190
  }> | undefined;
191
+ conditions?: Record<string, unknown>[] | undefined;
192
192
  event?: string | undefined;
193
193
  achievementRuleId?: string | undefined;
194
194
  limit?: {
@@ -280,11 +280,11 @@ export declare const AchievementUpdateInputSchema: {
280
280
  value: z.ZodOptional<z.ZodNumber>;
281
281
  consecutive: z.ZodNumber;
282
282
  }, "strip", z.ZodTypeAny, {
283
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
283
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
284
284
  consecutive: number;
285
285
  value?: number | undefined;
286
286
  }, {
287
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
287
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
288
288
  consecutive: number;
289
289
  value?: number | undefined;
290
290
  }>;
@@ -292,7 +292,7 @@ export declare const AchievementUpdateInputSchema: {
292
292
  }, "strip", z.ZodTypeAny, {
293
293
  periodGoal: string | number;
294
294
  period: {
295
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
295
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
296
296
  consecutive: number;
297
297
  value?: number | undefined;
298
298
  };
@@ -300,7 +300,7 @@ export declare const AchievementUpdateInputSchema: {
300
300
  }, {
301
301
  periodGoal: string | number;
302
302
  period: {
303
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
303
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
304
304
  consecutive: number;
305
305
  value?: number | undefined;
306
306
  };
@@ -346,7 +346,7 @@ export declare const AchievementUpdateInputSchema: {
346
346
  completeRule: {
347
347
  periodGoal: string | number;
348
348
  period: {
349
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
349
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
350
350
  consecutive: number;
351
351
  value?: number | undefined;
352
352
  };
@@ -355,11 +355,11 @@ export declare const AchievementUpdateInputSchema: {
355
355
  aggregation: {
356
356
  type: "quantity";
357
357
  };
358
- conditions?: Record<string, unknown>[] | undefined;
359
358
  translations?: Record<string, {
360
359
  name: string;
361
360
  description?: string | undefined;
362
361
  }> | undefined;
362
+ conditions?: Record<string, unknown>[] | undefined;
363
363
  event?: string | undefined;
364
364
  achievementRuleId?: string | undefined;
365
365
  limit?: {
@@ -376,7 +376,7 @@ export declare const AchievementUpdateInputSchema: {
376
376
  completeRule: {
377
377
  periodGoal: string | number;
378
378
  period: {
379
- type: "day" | "week" | "month" | "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "year" | "last_day";
379
+ type: "calendarDays" | "calendarWeeks" | "calendarMonths" | "calendarYears" | "day" | "week" | "month" | "year" | "last_day";
380
380
  consecutive: number;
381
381
  value?: number | undefined;
382
382
  };
@@ -385,11 +385,11 @@ export declare const AchievementUpdateInputSchema: {
385
385
  aggregation: {
386
386
  type: "quantity";
387
387
  };
388
- conditions?: Record<string, unknown>[] | undefined;
389
388
  translations?: Record<string, {
390
389
  name: string;
391
390
  description?: string | undefined;
392
391
  }> | undefined;
392
+ conditions?: Record<string, unknown>[] | undefined;
393
393
  event?: string | undefined;
394
394
  achievementRuleId?: string | undefined;
395
395
  limit?: {
@@ -20,10 +20,15 @@ export const campaignToolDefinitions = [
20
20
  {
21
21
  name: "ol_campaign_create",
22
22
  title: "Create Campaign",
23
- description: "Create campaign to automate engagement. Triggers: transaction (purchase-based), custom_event (for custom actions), time (scheduled). " +
24
- "Effects: give_points, give_reward, deduct_unit. Rules define when/what happens. " +
25
- "REQUIRED: activity.startsAt, rules[].name, effects[].effect. " +
26
- "pointsRule is a STRING expression (e.g., 'transaction.grossValue * 2'), not an object.",
23
+ description: "Create campaign to automate engagement (earning rules). " +
24
+ "⚠️ REQUIRED FIELDS: " +
25
+ "1. type: 'direct', " +
26
+ "2. trigger: 'transaction', " +
27
+ "3. translations: { en: { name: 'Campaign Name' } }, " +
28
+ "4. activity: { startsAt: '2026-01-01 00:00+00:00' }, " +
29
+ "5. rules: [{ name: 'Rule Name', effects: [{ effect: 'give_points', pointsRule: 'transaction.grossValue * 10' }] }]. " +
30
+ "pointsRule is a STRING expression, not an object. Examples: '100' (fixed), 'transaction.grossValue * 10' (dynamic). " +
31
+ "To target ALL members, OMIT the audience parameter entirely - do not set audience.target='all'.",
27
32
  readOnly: false,
28
33
  inputSchema: CampaignCreateInputSchema,
29
34
  handler: campaignCreate,
@@ -70,13 +70,13 @@ export declare const rewardToolDefinitions: readonly [{
70
70
  }>;
71
71
  usageLimit: import("zod").ZodObject<{
72
72
  perUser: import("zod").ZodNumber;
73
- general: import("zod").ZodOptional<import("zod").ZodNumber>;
73
+ general: import("zod").ZodNumber;
74
74
  }, "strip", import("zod").ZodTypeAny, {
75
75
  perUser: number;
76
- general?: number | undefined;
76
+ general: number;
77
77
  }, {
78
78
  perUser: number;
79
- general?: number | undefined;
79
+ general: number;
80
80
  }>;
81
81
  costInPoints: import("zod").ZodOptional<import("zod").ZodNumber>;
82
82
  usageInstruction: import("zod").ZodOptional<import("zod").ZodString>;
@@ -20,11 +20,14 @@ export const rewardToolDefinitions = [
20
20
  name: "ol_reward_create",
21
21
  title: "Create New Reward",
22
22
  description: "Create a new reward that members can redeem with points. " +
23
- "REQUIRED: translations.en.name, reward (type), activity {from,to}, visibility {from,to}. " +
24
- "Coupon types should include usageLimit.perUser. " +
25
- "Types: static_coupon (fixed discount), dynamic_coupon (variable value set at purchase), " +
26
- "material (physical goods), conversion_coupon (converts points), fortune_wheel (gamified). " +
27
- "Returns rewardId.",
23
+ "⚠️ REQUIRED FIELDS (will fail without these): " +
24
+ "1. translations: { en: { name: 'Reward Name' } }, " +
25
+ "2. reward: 'material' or 'static_coupon' or 'dynamic_coupon', " +
26
+ "3. activity: { from: '2026-01-01 00:00', to: '2027-12-31 23:59' }, " +
27
+ "4. visibility: { from: '2026-01-01 00:00', to: '2027-12-31 23:59' }, " +
28
+ "5. usageLimit: { perUser: 5, general: 1000 } - BOTH perUser AND general are REQUIRED. " +
29
+ "Types: material (physical goods), static_coupon (fixed discount), dynamic_coupon (variable value). " +
30
+ "For tier targeting: set target='level' and levels=['tier-uuid-1', 'tier-uuid-2'].",
28
31
  readOnly: false,
29
32
  inputSchema: RewardCreateInputSchema,
30
33
  handler: rewardCreate,
@@ -57,13 +57,13 @@ export declare const RewardCreateInputSchema: {
57
57
  }>;
58
58
  usageLimit: z.ZodObject<{
59
59
  perUser: z.ZodNumber;
60
- general: z.ZodOptional<z.ZodNumber>;
60
+ general: z.ZodNumber;
61
61
  }, "strip", z.ZodTypeAny, {
62
62
  perUser: number;
63
- general?: number | undefined;
63
+ general: number;
64
64
  }, {
65
65
  perUser: number;
66
- general?: number | undefined;
66
+ general: number;
67
67
  }>;
68
68
  costInPoints: z.ZodOptional<z.ZodNumber>;
69
69
  usageInstruction: z.ZodOptional<z.ZodString>;
@@ -26,11 +26,12 @@ const RewardVisibilityInputSchema = z.object({
26
26
  from: z.string().describe("Visibility start datetime (format: 'YYYY-MM-DD HH:mm'). REQUIRED."),
27
27
  to: z.string().describe("Visibility end datetime (format: 'YYYY-MM-DD HH:mm'). REQUIRED."),
28
28
  });
29
- // Usage limit schema (REQUIRED by API for coupon types)
29
+ // Usage limit schema (REQUIRED by API)
30
30
  // NOTE: API uses 'general' (not 'total') for total redemptions limit
31
+ // BOTH perUser and general are REQUIRED by the API
31
32
  const RewardUsageLimitInputSchema = z.object({
32
- perUser: z.number().describe("Maximum redemptions per member. REQUIRED for coupon types."),
33
- general: z.number().optional().describe("Total redemptions across all members (API calls this 'general')."),
33
+ perUser: z.number().describe("Maximum redemptions per member. REQUIRED."),
34
+ general: z.number().describe("Total redemptions across all members. REQUIRED. Use a large number (e.g., 10000) if unlimited."),
34
35
  });
35
36
  export const RewardCreateInputSchema = {
36
37
  storeCode: z.string().optional().describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
@@ -39,7 +40,7 @@ export const RewardCreateInputSchema = {
39
40
  "conversion_coupon (converts points to coupon), material (physical goods), fortune_wheel (gamified)."),
40
41
  activity: RewardActivityInputSchema.describe("Activity period when reward can be purchased. Use datetime format 'YYYY-MM-DD HH:mm'. REQUIRED."),
41
42
  visibility: RewardVisibilityInputSchema.describe("Visibility period when reward is shown. Use datetime format 'YYYY-MM-DD HH:mm'. REQUIRED."),
42
- usageLimit: RewardUsageLimitInputSchema.describe("Usage limits. perUser is REQUIRED for coupon types."),
43
+ usageLimit: RewardUsageLimitInputSchema.describe("Usage limits. ⚠️ BOTH perUser AND general are REQUIRED by the API."),
43
44
  costInPoints: z.number().optional().describe("Points required to redeem this reward."),
44
45
  usageInstruction: z.string().optional().describe("Instructions for using the reward."),
45
46
  active: z.boolean().optional().describe("Whether reward is active (default: false)."),
@@ -18,10 +18,11 @@ export const segmentToolDefinitions = [
18
18
  {
19
19
  name: "ol_segment_create",
20
20
  title: "Create Segment",
21
- description: "Create segment to group members. Parts use OR logic (member matches if ANY part matches). Criteria within parts use AND logic (must match ALL criteria in that part). " +
22
- "WORKING criterion types: 'transaction_count' (max auto-filled if omitted). " +
23
- "NOT WORKING: 'tier', 'points_balance' are rejected by the API. " +
24
- "Example - High activity segment: parts: [{ criteria: [{ type: 'transaction_count', min: 5, max: 999999 }] }]",
21
+ description: "Create segment to group members. " +
22
+ "⚠️ ONLY 'transaction_count' criterion type works reliably. 'tier' and 'points_balance' are REJECTED by the API. " +
23
+ "REQUIRED: name, parts array with criteria. " +
24
+ "Example for 5+ purchases: { name: 'Frequent Buyers', parts: [{ criteria: [{ type: 'transaction_count', min: 5 }] }], active: true }. " +
25
+ "Parts use OR logic (ANY part matches), criteria within parts use AND logic (ALL criteria must match).",
25
26
  readOnly: false,
26
27
  inputSchema: SegmentCreateInputSchema,
27
28
  handler: segmentCreate,
@@ -169,7 +169,7 @@ export declare function tiersetGetTiers(input: TierSetGetInput): Promise<{
169
169
  export declare const tiersetToolDefinitions: readonly [{
170
170
  readonly name: "ol_tierset_list";
171
171
  readonly title: "List Loyalty Programs";
172
- readonly description: "List all tier sets. Use tierset_get to fetch conditions needed for defining tiers. Returns tierSetId, name, active status, and tier count for each tier set.";
172
+ readonly description: string;
173
173
  readonly readOnly: true;
174
174
  readonly inputSchema: {
175
175
  storeCode: z.ZodOptional<z.ZodString>;
@@ -212,7 +212,7 @@ export declare const tiersetToolDefinitions: readonly [{
212
212
  }, {
213
213
  readonly name: "ol_tierset_get";
214
214
  readonly title: "Get Loyalty Program Details";
215
- readonly description: "Get tier set details including conditionId values needed for tierset_update_tiers. Returns the full tier set with conditions array containing conditionId for each condition.";
215
+ readonly description: string;
216
216
  readonly readOnly: true;
217
217
  readonly inputSchema: {
218
218
  storeCode: z.ZodOptional<z.ZodString>;
@@ -222,7 +222,7 @@ export declare const tiersetToolDefinitions: readonly [{
222
222
  }, {
223
223
  readonly name: "ol_tierset_update";
224
224
  readonly title: "Update Loyalty Program";
225
- readonly description: "Update tier set metadata (name, description, active status, downgrade settings). Does not modify tiers - use tierset_update_tiers for that.";
225
+ readonly description: string;
226
226
  readonly readOnly: false;
227
227
  readonly inputSchema: {
228
228
  storeCode: z.ZodOptional<z.ZodString>;