Overview

The Notification API enables merchant admins to respond contextually to customer support tickets and questions. It implements a bidirectional notification system where:

  1. Customers trigger notifications (support requests, questions)
  2. Merchant admins receive campaign messages with instructions
  3. Admins respond via AnswerNotificationTool with structured answers
  4. System sends localized responses back to customers

Architecture

The notification system consists of three main components:

1. Request Flow (Customer → Admin)

  • Customer initiates a notification (via Voyager tools or direct triggers)
  • System creates Notification record with answer schema
  • Campaign message sent to appropriate merchant admin(s)
  • Assistant instruction message provides context and answer format

2. Answer Flow (Admin → Customer)

  • Admin responds using AnswerNotificationTool in their conversation
  • Answer validated against notification's JSON schema
  • Response localized to customer's language using AI
  • 24-hour policy determines delivery method

3. Delivery Methods

>24 Hours Since Last Customer Message (Campaign Template): - Uses WhatsApp-approved campaign templates - Populates template variables with localized response - Required due to WhatsApp 24-hour messaging window policy

≤24 Hours Since Last Customer Message (Voyager): - Uses Voyager to generate contextual response - Incorporates admin's answer while maintaining conversation tone - Sends as normal WhatsApp/Instagram message

Notification Types

user_question_request

Purpose: Handle customer questions that Cosmo cannot answer from existing knowledge base.

Triggered by: RequestNotificationTool when customer asks unanswerable question

Request Context:

{
    "question": str,  # The customer's question
    "lead_phone": str,  # Auto-populated
    "document_id": int,  # Auto-created Document ID
}

Answer Schema:

{
    "answer": str  # Admin's answer to the question
}

Campaigns Used: - Request: merchant_user_question_request - Answer: merchant_user_question_answer (>24h only)

Special Behavior: - Creates a Document (category: UserQuestion) to store Q&A - Document title = question, content = answer - Document becomes part of merchant's knowledge base


user_support_request

Purpose: Route support tickets to appropriate merchant admins and enable contextual responses.

Triggered by: Customer requesting live agent or escalating an issue

Request Context:

{
    "support_request_reason": str,  # Why customer needs support
    "support_request_type": str,  # AI-classified type (Sales, Returns, etc.)
    "lead_phone": str,  # Auto-populated
}

Answer Schema:

{
    "agent_response_to_customer": str,  # Required response text
    "resolution_notes": str,  # Optional internal notes
}

Campaigns Used: - Request: merchant_user_override_request - Answer: customer_support_response (>24h only)

Special Behavior: - AI classification determines target merchant user type - Falls back to 'admin' type if no users found for classified type - Supports optional internal resolution notes (not sent to customer)

Code Flow Details

Request Notification Flow

  1. Validate Input
  2. Check notification type exists in NOTIFICATION_CONFIG
  3. Verify all requested_fields present in context

  4. Type-Specific Processing

  5. Question: Create Document with question as title
  6. Support: AI-classify to determine target merchant user type

  7. Create Notification Record

  8. Store in database with status=requested
  9. Include answer_model_json_schema for validation
  10. Add allow_multiple_answers flag

  11. Build Assistant Instruction

  12. Extract notification content from requested_fields
  13. Generate prefixed notification ID (e.g., NOTIF_123)
  14. Include JSON schema and usage instructions
  15. Store notification IDs in other_data

  16. Send Campaign to Admins

  17. Route to merchant_user or conversation_user per config
  18. Create ConversationUser records for merchant phone numbers if needed
  19. Send via send_service_campaign_messages
  20. Insert assistant instruction message per recipient

  21. Persist Recipients

  22. Store merchant_user_conversation_user_ids in notification context
  23. Used later to notify admins when notification is closed

Answer Notification Flow

  1. Load Notification
  2. Fetch by notification_id or create new answered notification
  3. Merge answer context into notification context

  4. Validate Answer

  5. Convert notification_type string to Enum
  6. Check all answered_fields present in context
  7. Enforce single-answer policy (if configured)

  8. Type-Specific Processing

  9. Question: Update Document content with answer
  10. Support: Extract admin response text

  11. Localize Response

  12. AI rewrites admin answer for customer's language
  13. Generates continuation_fragment (for templates) and full_sentence (for Voyager)
  14. Uses GPT-4.1 Mini model

  15. Determine Delivery Method

  16. Check last inbound user message timestamp
  17. use_campaign = (now - last_user_message_time) > 24 hours

  18. Send Response to Customer

If use_campaign=True (>24h): - Populate campaign variables with localized text - Send via send_notification_messages - Uses customer_support_response or merchant_user_question_answer campaign

If use_campaign=False (≤24h): - Create assistant message with notification context + admin answer - Build Voyager with conversation, merchant, user, billing_plan - Generate response via voyager.navigate() - Send directly via Twilio or Instagram (no template)

  1. Mark as Answered
  2. Update notification status to answered
  3. Update updated_at timestamp

  4. Notify Other Admins (Optional)

  5. If allow_multiple_answers=False
  6. Send closure message to other recipient admins
  7. Message: "Notification NOTIF_XXX has been answered and is now closed."

Integration with Other Modules

Dependencies

  • Campaign: Sends notification campaigns to admins and customers
  • Document: Stores questions and answers as knowledge base entries
  • Merchant: Fetches merchant users by type for routing
  • Conversation: Message storage and conversation management
  • ML/Tools: AnswerNotificationTool for admin responses
  • AI Client: Support classification and response localization

Used By

  • Voyager: Customer agent can trigger notifications via RequestNotificationTool
  • Merchant Admins: Answer notifications via AnswerNotificationTool in their conversations
  • SAQ Jobs: Async processing of notification requests and answers

Key Features

1. AI-Powered Support Classification

For user_support_request notifications: - Reads merchant's support classification documents - Determines appropriate merchant user type (sales, technical, returns, etc.) - Falls back to 'admin' type if no match found - Extracts readable support request type for display

2. Localization

All customer-facing responses are localized: - Detects customer's language from conversation.language - Rewrites admin answers professionally and concisely - Generates two variants: - Continuation fragment: Fits within campaign template variables - Full sentence: Standalone response for direct messaging

3. 24-Hour Messaging Window

WhatsApp enforces a 24-hour window for non-template messages: - >24h: Must use approved campaign templates - ≤24h: Can send free-form messages via Voyager

System automatically determines which path to use based on last customer message timestamp.

4. Single-Answer Enforcement

Prevents duplicate responses: - Each notification can only be answered once (by default) - Other admins notified when someone answers - Configurable via allow_multiple_answers flag

5. Notification ID Prefixing

Uses NOTIFICATION_PREFIX (defined in app/ml/prefix_utils.py): - Prevents confusion with other prefixed entities (orders, products, etc.) - Validated for correct format and int32 range - Example: NOTIF_123

6. Template Response in Voyager Context

  • Notification campaign messages (with whatsapp_payload.type == "template") are now included in Voyager's message history
  • Provides context when merchant admin replies
  • Helps Voyager determine when to use AnswerNotificationTool

Configuration

All notification types are configured in NOTIFICATION_CONFIG dictionary:

NOTIFICATION_CONFIG = {
    NotificationType.user_question_request: {
        "requested_fields": ["question"],
        "requested_campaign": CommerceDefaultCampaigns.merchant_user_question_request,
        "requested_to": "merchant_user",
        "answered_fields": ["answer"],
        "answered_campaign": CommerceDefaultCampaigns.merchant_user_question_answer,
        "answered_to": "conversation_user",
        "answer_schema": UserQuestionAnswerSchema,
        "allow_multiple_answers": False,
    },
    NotificationType.user_support_request: {
        "requested_fields": ["support_request_reason"],
        "requested_campaign": CommerceDefaultCampaigns.merchant_user_override_request,
        "requested_to": "merchant_user",
        "answered_fields": ["agent_response_to_customer"],
        "answered_campaign": CommerceDefaultCampaigns.customer_support_response,
        "answered_to": "conversation_user",
        "answer_schema": UserSupportRequestAnswerSchema,
        "allow_multiple_answers": False,
    },
}

Error Handling

Validation Errors

At Request Time: - Missing required fields in context - Invalid notification type - Conversation not found

At Answer Time: - Notification not found - Missing answered fields - Notification already answered (if single-answer) - Document not found (for questions) - Invalid answer JSON format - Answer doesn't match JSON schema

Edge Cases

  1. No merchant users found for classified type: Falls back to 'admin' type
  2. No ConversationUser for merchant phone: Automatically created
  3. Empty message list in Voyager: DBClient.db_update_rows no-ops safely
  4. Notification ID overflow: Validated to int32 range before querying
  5. String/Enum mismatch: notification_type converted to Enum before use

Performance Considerations

Async Processing

  • Notification requests/answers run in SAQ background jobs
  • Prevents blocking customer-facing API calls
  • Tool returns "processing" status (actual send happens async)

Database Queries

  • Uses DBClient to avoid greenlet/session issues
  • Explicit queries for relationships to prevent DetachedInstanceError
  • Minimal queries per notification (3-4 total)

AI Usage

  • Support classification: GPT-4.1 with 100 token limit
  • Response localization: GPT-4.1 Mini for cost efficiency
  • Cached results where possible via logging params

Usage Examples

Triggering a Question Notification

from app.api.notification.service import request_notification_job
from app.api.notification.models import NotificationType

await request_notification_job(
    notification_type=NotificationType.user_question_request,
    conversation_id=123,
    context={"question": "What are your business hours?"}
)

Triggering a Support Request

await request_notification_job(
    notification_type=NotificationType.user_support_request,
    conversation_id=456,
    context={"support_request_reason": "Product arrived damaged, need refund"}
)

Answering via Tool (Merchant Admin)

# In merchant admin conversation, Voyager calls:
AnswerNotificationTool(
    notification_id="NOTIF_123",
    answer_json='{"answer": "We are open Mon-Fri 9am-5pm EST"}'
)

Future Enhancements

  1. Streaming Responses: Stream Voyager responses as they're generated (≤24h path)
  2. Answer Templates: Pre-defined templates for common questions
  3. Auto-Close: Close notifications after configurable timeout
  4. Answer History: Track all answer attempts for analytics
  5. Priority Routing: Route urgent tickets to on-call admins first
  6. SLA Tracking: Monitor response times and SLA compliance
  7. Customer Satisfaction: Collect feedback on admin responses